Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

488 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999, 2000 Microsoft Corporation
  3. Module Name:
  4. int.c
  5. Abstract:
  6. interrupt service routine
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13. PURPOSE.
  14. Copyright (c) 1999, 2000 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 7-26-00 : created, jsenior
  17. --*/
  18. #include "pch.h"
  19. //implements the following miniport functions:
  20. //non paged
  21. //UhciInterruptService
  22. //UhciInterruptDpc
  23. //UhciDisableInterrupts
  24. //UhciEnableInterrupts
  25. //UhciRHDisableIrq
  26. //UhciRHEnableIrq
  27. //UhciInterruptNextSOF
  28. BOOLEAN
  29. UhciInterruptService (
  30. IN PDEVICE_DATA DeviceData
  31. )
  32. /*++
  33. Routine Description:
  34. Arguments:
  35. Return Value:
  36. --*/
  37. {
  38. BOOLEAN usbInt;
  39. PHC_REGISTER reg;
  40. // USBINTR enabledIrqs;
  41. USBSTS irqStatus;
  42. reg = DeviceData->Registers;
  43. // assume it is not ours
  44. usbInt = FALSE;
  45. // see if we have lost the controller due to
  46. // a surprise remove
  47. if (UhciHardwarePresent(DeviceData) == FALSE) {
  48. return FALSE;
  49. }
  50. // get a mask of possible interrupts
  51. // enabledIrqs.us = READ_PORT_USHORT(&reg->UsbInterruptEnable.us);
  52. irqStatus.us = READ_PORT_USHORT(&reg->UsbStatus.us);
  53. // just look at the IRQ status bits
  54. irqStatus.us &= HcInterruptStatusMask;
  55. // irqStatus now possibly contains bits set for any currently
  56. // enabled interrupts
  57. if (irqStatus.HostSystemError ||
  58. irqStatus.HostControllerProcessError) {
  59. UhciKdPrint((DeviceData, 0, "IrqStatus Error: %x\n", irqStatus.us));
  60. } else if (irqStatus.us) {
  61. DeviceData->HCErrorCount = 0;
  62. }
  63. #if DBG
  64. // this usually means we have a bad TD in the schedule
  65. // we will need to debug this since the controller and/or
  66. // device will not function after this point
  67. if (irqStatus.HostControllerProcessError) {
  68. USHORT fn;
  69. fn = READ_PORT_USHORT(&reg->FrameNumber.us)&0x7ff;
  70. UhciKdPrint((DeviceData, 0, "HostControllerProcessError: %x\n", irqStatus.us));
  71. UhciKdPrint((DeviceData, 0, "frame[]: %x\n", fn&0x7ff));
  72. {
  73. //UhciDumpRegs(DeviceData);
  74. USHORT tmp;
  75. tmp = READ_PORT_USHORT(&reg->UsbCommand.us);
  76. UhciKdPrint((DeviceData, 0, "UsbCommand %x\n", tmp));
  77. tmp = READ_PORT_USHORT(&reg->UsbStatus.us);
  78. UhciKdPrint((DeviceData, 0, "UsbStatus %x\n", tmp));
  79. tmp = READ_PORT_USHORT(&reg->UsbInterruptEnable.us);
  80. UhciKdPrint((DeviceData, 0, "UsbInterruptEnable %x\n", tmp));
  81. tmp = READ_PORT_USHORT(&reg->UsbCommand.us);
  82. UhciKdPrint((DeviceData, 0, "UsbCommand %x\n", tmp));
  83. }
  84. TEST_TRAP();
  85. }
  86. #endif
  87. // the halted bit alone does not indicate the interrupt
  88. // came from the controller
  89. if (irqStatus.UsbInterrupt ||
  90. irqStatus.ResumeDetect ||
  91. irqStatus.UsbError ||
  92. irqStatus.HostSystemError ||
  93. irqStatus.HostControllerProcessError) {
  94. DeviceData->IrqStatus = irqStatus.us;
  95. // Clear the condition
  96. WRITE_PORT_USHORT(&reg->UsbStatus.us, irqStatus.us);
  97. #if DBG
  98. #ifndef _WIN64
  99. if (irqStatus.HostSystemError) {
  100. // something has gone terribly wrong
  101. UhciKdPrint((DeviceData, 0, "HostSystemError: %x\n", irqStatus.us));
  102. TEST_TRAP();
  103. }
  104. #endif
  105. #endif
  106. // indications are that this came from the
  107. // USB controller
  108. usbInt = TRUE;
  109. // disable all interrupts until the DPC for ISR runs
  110. WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us, 0);
  111. }
  112. //
  113. // If bulk bandwidth reclamation is on and there's
  114. // nothing queued, then turn it off.
  115. //
  116. if (irqStatus.UsbInterrupt) {
  117. UhciUpdateCounter(DeviceData);
  118. if (!DeviceData->LastBulkQueueHead->HwQH.HLink.Terminate) {
  119. PHCD_QUEUEHEAD_DESCRIPTOR qh;
  120. BOOLEAN activeBulkTDs = FALSE;
  121. // This loop skips the td that has been inserted for
  122. // the PIIX4 problem, since it starts with the qh
  123. // the bulk queuehead is pointing at.
  124. // If the bulk queuehead is not pointing at anything,
  125. // then we're fine too, since it will have been
  126. // turned off already.
  127. for (qh = DeviceData->BulkQueueHead->NextQh;
  128. qh;
  129. qh = qh->NextQh) {
  130. if (!qh->HwQH.VLink.Terminate) {
  131. activeBulkTDs = TRUE;
  132. break;
  133. }
  134. }
  135. //
  136. // qh is pointing at either the first queuehead
  137. // with transfers pending or the bulk queuehead.
  138. //
  139. if (!activeBulkTDs) {
  140. UHCI_ASSERT(DeviceData, !qh)
  141. DeviceData->LastBulkQueueHead->HwQH.HLink.Terminate = 1;
  142. }
  143. }
  144. }
  145. if (irqStatus.HostControllerProcessError) {
  146. //
  147. // Force the schedule clean.
  148. //
  149. UhciCleanOutIsoch(DeviceData, TRUE);
  150. } else if (irqStatus.UsbInterrupt && DeviceData->IsoPendingTransfers) {
  151. //
  152. // Something completed.
  153. //
  154. UhciCleanOutIsoch(DeviceData, FALSE);
  155. #if 0
  156. } else if (!DeviceData->IsoPendingTransfers) {
  157. //
  158. // Remove the rollover interrupt.
  159. //
  160. *( ((PULONG) (DeviceData->FrameListVA)) ) = DeviceData->RollOverTd->HwTD.LinkPointer.HwAddress;
  161. #endif
  162. }
  163. if (irqStatus.HostControllerProcessError) {
  164. if (DeviceData->HCErrorCount++ < UHCI_HC_MAX_ERRORS) {
  165. USBCMD command;
  166. // Attempt to recover.
  167. // It could just be that we overran. If so,
  168. // the above code that clears the schedule
  169. // should take care of it.
  170. command.us = READ_PORT_USHORT(&reg->UsbCommand.us);
  171. command.RunStop = 1;
  172. WRITE_PORT_USHORT(&reg->UsbCommand.us, command.us);
  173. UhciKdPrint((DeviceData, 0, "Attempted to recover from error\n"));
  174. }
  175. }
  176. return usbInt;
  177. }
  178. VOID
  179. UhciInterruptDpc (
  180. IN PDEVICE_DATA DeviceData,
  181. IN BOOLEAN EnableInterrupts
  182. )
  183. /*++
  184. Routine Description:
  185. process an interrupt
  186. Arguments:
  187. Return Value:
  188. --*/
  189. {
  190. PHC_REGISTER reg;
  191. USBSTS irqStatus, tmp;
  192. PLIST_ENTRY listEntry;
  193. PENDPOINT_DATA endpointData;
  194. reg = DeviceData->Registers;
  195. // ack all status bits asserted now
  196. //tmp.us = READ_PORT_USHORT(&reg->UsbStatus.us);
  197. tmp.us = DeviceData->IrqStatus;
  198. DeviceData->IrqStatus = 0;
  199. LOGENTRY(DeviceData, G, '_idp', tmp.us, 0, 0);
  200. //WRITE_PORT_USHORT(&reg->UsbStatus.us, tmp.us);
  201. // now process status bits aserted,
  202. // just look at the IRQ status bits
  203. irqStatus.us = tmp.us & HcInterruptStatusMask;
  204. if (irqStatus.UsbInterrupt ||
  205. irqStatus.UsbError) {
  206. LOGENTRY(DeviceData, G, '_iEP', irqStatus.us, 0, 0);
  207. USBPORT_INVALIDATE_ENDPOINT(DeviceData, NULL);
  208. }
  209. if (EnableInterrupts) {
  210. LOGENTRY(DeviceData, G, '_iEE', 0, 0, 0);
  211. WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us,
  212. DeviceData->EnabledInterrupts.us);
  213. }
  214. }
  215. VOID
  216. USBMPFN
  217. UhciDisableInterrupts(
  218. IN PDEVICE_DATA DeviceData
  219. )
  220. /*++
  221. Routine Description:
  222. Arguments:
  223. Return Value:
  224. --*/
  225. {
  226. USHORT legsup;
  227. PHC_REGISTER reg;
  228. UhciKdPrint((DeviceData, 2, "Disable interrupts\n"));
  229. LOGENTRY(DeviceData, G, '_DIn', 0, 0, 0);
  230. reg = DeviceData->Registers;
  231. WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us,
  232. 0);
  233. if (DeviceData->ControllerFlavor != UHCI_Ich2_1 &&
  234. DeviceData->ControllerFlavor != UHCI_Ich2_2) {
  235. //
  236. // change the state of the PIRQD routing bit
  237. //
  238. USBPORT_READ_CONFIG_SPACE(
  239. DeviceData,
  240. &legsup,
  241. LEGACY_BIOS_REGISTER,
  242. sizeof(legsup));
  243. LOGENTRY(DeviceData, G, '_leg', 0, legsup, 0);
  244. // clear the PIRQD routing bit
  245. legsup &= ~LEGSUP_USBPIRQD_EN;
  246. USBPORT_WRITE_CONFIG_SPACE(
  247. DeviceData,
  248. &legsup,
  249. LEGACY_BIOS_REGISTER,
  250. sizeof(legsup));
  251. }
  252. }
  253. VOID
  254. UhciFlushInterrupts(
  255. IN PDEVICE_DATA DeviceData
  256. )
  257. /*++
  258. Routine Description:
  259. used to flush rougue interrupts from the controller
  260. after power events
  261. Arguments:
  262. Return Value:
  263. --*/
  264. {
  265. PHC_REGISTER reg;
  266. LOGENTRY(DeviceData, G, '_FIn', 0, 0, 0);
  267. UhciKdPrint((DeviceData, 2, "Enable interrupts\n"));
  268. reg = DeviceData->Registers;
  269. // before writing the PIRQD register ack any eronious interrupts
  270. // the controller may be asserting -- it should not be asserting
  271. // at all but often is
  272. WRITE_PORT_USHORT(&reg->UsbStatus.us, 0xFFFF);
  273. }
  274. VOID
  275. USBMPFN
  276. UhciEnableInterrupts(
  277. IN PDEVICE_DATA DeviceData
  278. )
  279. /*++
  280. Routine Description:
  281. Arguments:
  282. Return Value:
  283. --*/
  284. {
  285. USHORT legsup;
  286. PHC_REGISTER reg;
  287. LOGENTRY(DeviceData, G, '_EIn', 0, 0, 0);
  288. UhciKdPrint((DeviceData, 2, "Enable interrupts\n"));
  289. reg = DeviceData->Registers;
  290. //
  291. // change the state of the PIrQD routing bit
  292. //
  293. USBPORT_READ_CONFIG_SPACE(
  294. DeviceData,
  295. &legsup,
  296. LEGACY_BIOS_REGISTER,
  297. sizeof(legsup));
  298. LOGENTRY(DeviceData, G, '_leg', 0, legsup, 0);
  299. // clear the PIRQD routing bit
  300. legsup |= LEGSUP_USBPIRQD_EN;
  301. USBPORT_WRITE_CONFIG_SPACE(
  302. DeviceData,
  303. &legsup,
  304. LEGACY_BIOS_REGISTER,
  305. sizeof(legsup));
  306. WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us,
  307. DeviceData->EnabledInterrupts.us);
  308. }
  309. VOID
  310. UhciRHDisableIrq(
  311. IN PDEVICE_DATA DeviceData
  312. )
  313. {
  314. // Uhci doesn't have this IRQ
  315. }
  316. VOID
  317. UhciRHEnableIrq(
  318. IN PDEVICE_DATA DeviceData
  319. )
  320. {
  321. // Uhci doesn't have this IRQ
  322. }
  323. #define UHCI_SOF_LATENCY 2
  324. VOID
  325. UhciInterruptNextSOF(
  326. IN PDEVICE_DATA DeviceData
  327. )
  328. {
  329. ULONG i, frame, offset, cf;
  330. PHCD_TRANSFER_DESCRIPTOR td;
  331. BOOLEAN found = FALSE;
  332. cf = UhciGet32BitFrameNumber(DeviceData);
  333. // find a TD
  334. for (i=0; i<SOF_TD_COUNT; i++) {
  335. td = &DeviceData->SofTdList->Td[i];
  336. UHCI_ASSERT(DeviceData, td->Sig == SIG_HCD_SOFTD);
  337. // use transferconext to hold req frame
  338. frame = td->RequestFrame;
  339. if (frame == cf+UHCI_SOF_LATENCY) {
  340. // There's already one queued
  341. found = TRUE;
  342. break;
  343. }
  344. if (frame < cf) {
  345. td->RequestFrame = (cf+UHCI_SOF_LATENCY);
  346. LOGENTRY(DeviceData, G, '_SOF', td, td->RequestFrame, cf);
  347. // insert TD
  348. td->HwTD.LinkPointer.HwAddress = 0;
  349. INSERT_ISOCH_TD(DeviceData, td, td->RequestFrame);
  350. found = TRUE;
  351. break;
  352. }
  353. }
  354. if (!found) {
  355. TEST_TRAP();
  356. }
  357. // recycle any old SOF interrupt TDs
  358. for (i=0; i<SOF_TD_COUNT; i++) {
  359. td = &DeviceData->SofTdList->Td[i];
  360. UHCI_ASSERT(DeviceData, td->Sig == SIG_HCD_SOFTD);
  361. // use transferconext to hold req frame
  362. frame = td->RequestFrame;
  363. if (frame &&
  364. (frame < cf ||
  365. frame - cf > UHCI_MAX_FRAME)) {
  366. td->RequestFrame = 0;
  367. }
  368. }
  369. }