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.

338 lines
8.5 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. int.c
  5. Abstract:
  6. code to handle adapter interrupts
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 6-20-99 : created
  12. --*/
  13. #include "common.h"
  14. // paged functions
  15. #ifdef ALLOC_PRAGMA
  16. #endif
  17. // non paged functions
  18. // USBPORT_InterruptService
  19. // USBPORT_IsrDpc
  20. // USBPORT_DisableInterrupts
  21. // USBPORT_IsrDpcWorker
  22. BOOLEAN
  23. USBPORT_InterruptService(
  24. PKINTERRUPT Interrupt,
  25. PVOID Context
  26. )
  27. /*++
  28. Routine Description:
  29. This is the interrupt service routine for the PORT driver.
  30. Arguments:
  31. Interrupt - A pointer to the interrupt object for this interrupt.
  32. Context - A pointer to the device object.
  33. Return Value:
  34. Returns TRUE if the interrupt was expected (and therefore processed);
  35. otherwise, FALSE is returned.
  36. --*/
  37. {
  38. PDEVICE_OBJECT fdoDeviceObject = Context;
  39. PDEVICE_EXTENSION devExt;
  40. BOOLEAN usbInt = FALSE;
  41. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  42. ASSERT_FDOEXT(devExt);
  43. // by definition, if we are in any other power state than D0 then
  44. // the interrupt could not be from the controller. To handle this
  45. // case we use our internal flag that indicates interrupts are
  46. // disabled
  47. if (!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_EN)) {
  48. return FALSE;
  49. }
  50. // if the controller is gone then the interrupt cannot
  51. // be from USB
  52. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_CONTROLLER_GONE)) {
  53. return FALSE;
  54. }
  55. // check flag and calldown to miniport
  56. if (devExt->Fdo.MpStateFlags & MP_STATE_STARTED) {
  57. MP_InterruptService(devExt, usbInt);
  58. }
  59. //#if DBG
  60. // else {
  61. // // interrupt before we have started,
  62. // // it had better not be ours
  63. // DEBUG_BREAK();
  64. // }
  65. //#endif
  66. if (usbInt) {
  67. devExt->Fdo.StatPciInterruptCount++;
  68. KeInsertQueueDpc(&devExt->Fdo.IsrDpc,
  69. NULL,
  70. NULL);
  71. }
  72. return usbInt;
  73. }
  74. VOID
  75. USBPORT_IsrDpcWorker(
  76. PDEVICE_OBJECT FdoDeviceObject,
  77. BOOLEAN HcInterrupt
  78. )
  79. /*++
  80. Routine Description:
  81. This routine runs at DISPATCH_LEVEL IRQL.
  82. This routine dous our 'ISR Work' it can be called as a result
  83. of an interrupt or from the Deadman DPC timer.
  84. This function is not reentrant
  85. This function does not directly signal the worker thread
  86. instead we leave this to invalidate endpoint.
  87. Arguments:
  88. Return Value:
  89. None.
  90. --*/
  91. {
  92. PDEVICE_EXTENSION devExt;
  93. KIRQL irql;
  94. PLIST_ENTRY listEntry;
  95. LONG busy;
  96. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  97. ASSERT_FDOEXT(devExt);
  98. busy = InterlockedIncrement(&devExt->Fdo.WorkerDpc);
  99. if (busy) {
  100. InterlockedDecrement(&devExt->Fdo.WorkerDpc);
  101. return;
  102. }
  103. // noisy becuse it is called via timer
  104. #if DBG
  105. {
  106. ULONG cf;
  107. MP_Get32BitFrameNumber(devExt, cf);
  108. if (HcInterrupt) {
  109. LOGENTRY(NULL,
  110. FdoDeviceObject, LOG_NOISY, 'iDW+', FdoDeviceObject, cf, HcInterrupt);
  111. } else {
  112. LOGENTRY(NULL,
  113. FdoDeviceObject, LOG_NOISY, 'idw+', FdoDeviceObject, cf, HcInterrupt);
  114. }
  115. }
  116. #endif
  117. // check the state list for any endpoints
  118. // that have changed state
  119. //
  120. // We add elements to the tail so the ones at
  121. // the head should be the oldest and ready
  122. // for processing.
  123. // if we hit one that is not ready then we know
  124. // the others are not ready either so we bail.
  125. listEntry =
  126. ExInterlockedRemoveHeadList(&devExt->Fdo.EpStateChangeList,
  127. &devExt->Fdo.EpStateChangeListSpin.sl);
  128. while (listEntry != NULL) {
  129. PHCD_ENDPOINT endpoint;
  130. ULONG frameNumber;
  131. endpoint = (PHCD_ENDPOINT) CONTAINING_RECORD(
  132. listEntry,
  133. struct _HCD_ENDPOINT,
  134. StateLink);
  135. ASSERT_ENDPOINT(endpoint);
  136. // lock the endpoint before changing its state
  137. ACQUIRE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'LeG0');
  138. // see if it is time
  139. MP_Get32BitFrameNumber(devExt, frameNumber);
  140. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'chgS', endpoint, frameNumber,
  141. endpoint->StateChangeFrame);
  142. if (frameNumber <= endpoint->StateChangeFrame &&
  143. !TEST_FLAG(endpoint->Flags, EPFLAG_NUKED)) {
  144. // not time yet, put it back (on the head) and bail
  145. RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'UeG1');
  146. ExInterlockedInsertHeadList(&devExt->Fdo.EpStateChangeList,
  147. &endpoint->StateLink,
  148. &devExt->Fdo.EpStateChangeListSpin.sl);
  149. // request an SOF just in case
  150. MP_InterruptNextSOF(devExt);
  151. break;
  152. }
  153. // this endpoint is ripe, change its state
  154. //
  155. // note: we should never move into the unknown state
  156. //
  157. // IT IS CRITICAL that this is the only place an endpoint state
  158. // may be changed.
  159. // there is one exception and that is cahnging the state to
  160. // CLOSED
  161. RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'UeG0');
  162. ACQUIRE_STATECHG_LOCK(FdoDeviceObject, endpoint);
  163. USBPORT_ASSERT(endpoint->NewState != ENDPOINT_TRANSITION);
  164. endpoint->CurrentState = endpoint->NewState;
  165. RELEASE_STATECHG_LOCK(FdoDeviceObject, endpoint);
  166. // endpoint needs to be checked,
  167. // since we are in DPC context we will be processing
  168. // all endpoints
  169. USBPORT_InvalidateEndpoint(FdoDeviceObject,
  170. endpoint,
  171. 0);
  172. listEntry =
  173. ExInterlockedRemoveHeadList(&devExt->Fdo.EpStateChangeList,
  174. &devExt->Fdo.EpStateChangeListSpin.sl);
  175. }
  176. //#ifdef USBPERF
  177. // // always run the DPC worker from the timer to compensate for
  178. // // reduced thread activity
  179. // USBPORT_DpcWorker(FdoDeviceObject);
  180. //#else
  181. if (HcInterrupt) {
  182. USBPORT_DpcWorker(FdoDeviceObject);
  183. }
  184. //#endif
  185. #if DBG
  186. if (HcInterrupt) {
  187. LOGENTRY(NULL, FdoDeviceObject, LOG_NOISY, 'iDW-', 0,
  188. 0, 0);
  189. } else {
  190. LOGENTRY(NULL, FdoDeviceObject, LOG_NOISY, 'idw-', 0,
  191. 0, 0);
  192. }
  193. #endif
  194. InterlockedDecrement(&devExt->Fdo.WorkerDpc);
  195. }
  196. VOID
  197. USBPORT_IsrDpc(
  198. PKDPC Dpc,
  199. PVOID DeferredContext,
  200. PVOID SystemArgument1,
  201. PVOID SystemArgument2
  202. )
  203. /*++
  204. Routine Description:
  205. This routine runs at DISPATCH_LEVEL IRQL.
  206. If the controller was the source of the interrupt this
  207. routine will be called.
  208. Arguments:
  209. Dpc - Pointer to the DPC object.
  210. DeferredContext - supplies the DeviceObject.
  211. SystemArgument1 - not used.
  212. SystemArgument2 - not used.
  213. Return Value:
  214. None.
  215. --*/
  216. {
  217. PDEVICE_EXTENSION devExt;
  218. PDEVICE_OBJECT fdoDeviceObject;
  219. BOOLEAN enableIrq;
  220. fdoDeviceObject = (PDEVICE_OBJECT) DeferredContext;
  221. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  222. ASSERT_FDOEXT(devExt);
  223. LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'iDP+', fdoDeviceObject, 0, 0);
  224. KeAcquireSpinLockAtDpcLevel(&devExt->Fdo.IsrDpcSpin.sl);
  225. LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'DPlk', fdoDeviceObject, 0, 0);
  226. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_EN)) {
  227. enableIrq = TRUE;
  228. } else {
  229. enableIrq = FALSE;
  230. }
  231. MP_InterruptDpc(devExt, enableIrq);
  232. KeReleaseSpinLockFromDpcLevel(&devExt->Fdo.IsrDpcSpin.sl);
  233. LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'DPuk', fdoDeviceObject, 0, 0);
  234. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED)) {
  235. // if we take an interrupt while 'suspended' we treat
  236. // this as a wakeup event.
  237. USBPORT_KdPrint((1, " HC Wake Event\n"));
  238. USBPORT_CompletePdoWaitWake(fdoDeviceObject);
  239. } else {
  240. USBPORT_IsrDpcWorker(fdoDeviceObject, TRUE);
  241. }
  242. LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'iDP-', 0,
  243. 0, 0);
  244. }