Source code of Windows XP (NT5)
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.

309 lines
8.5 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. adapter.c
  5. Author:
  6. ervinp
  7. Environment:
  8. Kernel mode
  9. Revision History:
  10. --*/
  11. #include <WDM.H>
  12. #include <usbdi.h>
  13. #include <usbdlib.h>
  14. #include <usbioctl.h>
  15. #include "usb8023.h"
  16. #include "debug.h"
  17. LIST_ENTRY allAdaptersList;
  18. KSPIN_LOCK globalSpinLock;
  19. #ifdef RAW_TEST
  20. BOOLEAN rawTest = TRUE;
  21. #endif
  22. ADAPTEREXT *NewAdapter(PDEVICE_OBJECT pdo)
  23. {
  24. ADAPTEREXT *adapter;
  25. adapter = AllocPool(sizeof(ADAPTEREXT));
  26. if (adapter){
  27. adapter->sig = DRIVER_SIG;
  28. adapter->nextDevObj = pdo;
  29. adapter->physDevObj = pdo;
  30. InitializeListHead(&adapter->adaptersListEntry);
  31. KeInitializeSpinLock(&adapter->adapterSpinLock);
  32. InitializeListHead(&adapter->usbFreePacketPool);
  33. InitializeListHead(&adapter->usbPendingReadPackets);
  34. InitializeListHead(&adapter->usbPendingWritePackets);
  35. InitializeListHead(&adapter->usbCompletedReadPackets);
  36. adapter->initialized = FALSE;
  37. adapter->halting = FALSE;
  38. adapter->gotPacketFilterIndication = FALSE;
  39. adapter->readReentrancyCount = 0;
  40. #ifdef RAW_TEST
  41. adapter->rawTest = rawTest;
  42. #endif
  43. /*
  44. * Do all internal allocations.
  45. * If any of them fail, FreeAdapter will free the others.
  46. */
  47. adapter->deviceDesc = AllocPool(sizeof(USB_DEVICE_DESCRIPTOR));
  48. #if SPECIAL_WIN98SE_BUILD
  49. adapter->ioWorkItem = MyIoAllocateWorkItem(adapter->physDevObj);
  50. #else
  51. adapter->ioWorkItem = IoAllocateWorkItem(adapter->physDevObj);
  52. #endif
  53. if (adapter->deviceDesc && adapter->ioWorkItem){
  54. }
  55. else {
  56. FreeAdapter(adapter);
  57. adapter = NULL;
  58. }
  59. }
  60. return adapter;
  61. }
  62. VOID FreeAdapter(ADAPTEREXT *adapter)
  63. {
  64. USBPACKET *packet;
  65. ASSERT(adapter->sig == DRIVER_SIG);
  66. adapter->sig = 0xDEADDEAD;
  67. /*
  68. * All the read and write packets should have been returned to the free list.
  69. */
  70. ASSERT(IsListEmpty(&adapter->usbPendingReadPackets));
  71. ASSERT(IsListEmpty(&adapter->usbPendingWritePackets));
  72. ASSERT(IsListEmpty(&adapter->usbCompletedReadPackets));
  73. /*
  74. * Free all the packets in the free list.
  75. */
  76. while (packet = DequeueFreePacket(adapter)){
  77. FreePacket(packet);
  78. }
  79. /*
  80. * FreeAdapter can be called after a failed start,
  81. * so check that each pointer was actually allocated before freeing it.
  82. */
  83. if (adapter->deviceDesc) FreePool(adapter->deviceDesc);
  84. if (adapter->configDesc) FreePool(adapter->configDesc);
  85. if (adapter->notifyBuffer) FreePool(adapter->notifyBuffer);
  86. if (adapter->notifyIrpPtr) IoFreeIrp(adapter->notifyIrpPtr);
  87. if (adapter->notifyUrbPtr) FreePool(adapter->notifyUrbPtr);
  88. if (adapter->interfaceInfo) FreePool(adapter->interfaceInfo);
  89. if (adapter->interfaceInfoMaster) FreePool(adapter->interfaceInfoMaster);
  90. if (adapter->ioWorkItem){
  91. #if SPECIAL_WIN98SE_BUILD
  92. MyIoFreeWorkItem(adapter->ioWorkItem);
  93. #else
  94. IoFreeWorkItem(adapter->ioWorkItem);
  95. #endif
  96. }
  97. FreePool(adapter);
  98. }
  99. VOID EnqueueAdapter(ADAPTEREXT *adapter)
  100. {
  101. KIRQL oldIrql;
  102. ASSERT(adapter->sig == DRIVER_SIG);
  103. KeAcquireSpinLock(&globalSpinLock, &oldIrql);
  104. InsertTailList(&allAdaptersList, &adapter->adaptersListEntry);
  105. KeReleaseSpinLock(&globalSpinLock, oldIrql);
  106. }
  107. VOID DequeueAdapter(ADAPTEREXT *adapter)
  108. {
  109. KIRQL oldIrql;
  110. ASSERT(adapter->sig == DRIVER_SIG);
  111. KeAcquireSpinLock(&globalSpinLock, &oldIrql);
  112. ASSERT(!IsListEmpty(&allAdaptersList));
  113. RemoveEntryList(&adapter->adaptersListEntry);
  114. InitializeListHead(&adapter->adaptersListEntry);
  115. KeReleaseSpinLock(&globalSpinLock, oldIrql);
  116. }
  117. VOID HaltAdapter(ADAPTEREXT *adapter)
  118. {
  119. ASSERT(!adapter->halting);
  120. adapter->halting = TRUE;
  121. ASSERT(IsListEmpty(&adapter->usbCompletedReadPackets));
  122. CancelAllPendingPackets(adapter);
  123. adapter->initialized = FALSE;
  124. }
  125. VOID QueueAdapterWorkItem(ADAPTEREXT *adapter)
  126. {
  127. BOOLEAN queueNow;
  128. KIRQL oldIrql;
  129. BOOLEAN useTimer;
  130. KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
  131. if (adapter->workItemOrTimerPending || adapter->halting || adapter->resetting){
  132. queueNow = FALSE;
  133. }
  134. else {
  135. adapter->workItemOrTimerPending = queueNow = TRUE;
  136. useTimer = (adapter->numConsecutiveReadFailures >= 8);
  137. }
  138. KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
  139. if (queueNow){
  140. KeInitializeEvent(&adapter->workItemOrTimerEvent, NotificationEvent, FALSE);
  141. if (useTimer){
  142. /*
  143. * If we're experiencing a large number of read failures,
  144. * then possibly the hardware needs more time to recover
  145. * than allowed by the workItem delay.
  146. * This happens specifically on a surprise remove: the reads
  147. * start failing, and the flurry of workItems hold off the
  148. * actual remove forever.
  149. * So in this case, we use a long timer instead of a workItem
  150. * in order to allow a large gap before the next attempted read.
  151. */
  152. LARGE_INTEGER timerPeriod;
  153. const ULONG numSeconds = 10;
  154. DBGWARN(("Large number of READ FAILURES (%d), scheduling %d-second backoff timer ...", adapter->numConsecutiveReadFailures, numSeconds));
  155. /*
  156. * Set the timer for 10 seconds (in negative 100 nsec units).
  157. */
  158. timerPeriod.HighPart = -1;
  159. timerPeriod.LowPart = numSeconds * -10000000;
  160. KeInitializeTimer(&adapter->backoffTimer);
  161. KeInitializeDpc(&adapter->backoffTimerDPC, BackoffTimerDpc, adapter);
  162. KeSetTimer(&adapter->backoffTimer, timerPeriod, &adapter->backoffTimerDPC);
  163. }
  164. else {
  165. #if SPECIAL_WIN98SE_BUILD
  166. MyIoQueueWorkItem( adapter->ioWorkItem,
  167. AdapterWorkItemCallback,
  168. DelayedWorkQueue,
  169. adapter);
  170. #else
  171. IoQueueWorkItem( adapter->ioWorkItem,
  172. AdapterWorkItemCallback,
  173. DelayedWorkQueue,
  174. adapter);
  175. #endif
  176. }
  177. }
  178. }
  179. VOID AdapterWorkItemCallback(IN PDEVICE_OBJECT devObj, IN PVOID context)
  180. {
  181. ADAPTEREXT *adapter = (ADAPTEREXT *)context;
  182. ASSERT(adapter->sig == DRIVER_SIG);
  183. ASSERT(adapter->physDevObj == devObj);
  184. ProcessWorkItemOrTimerCallback(adapter);
  185. }
  186. VOID BackoffTimerDpc(
  187. IN PKDPC Dpc,
  188. IN PVOID DeferredContext,
  189. IN PVOID SystemArgument1,
  190. IN PVOID SystemArgument2
  191. )
  192. {
  193. ADAPTEREXT *adapter = (ADAPTEREXT *)DeferredContext;
  194. ASSERT(adapter->sig == DRIVER_SIG);
  195. DBGWARN((" ... Backoff timer CALLBACK: (halting=%d, readDeficit=%d)", adapter->halting, adapter->readDeficit));
  196. ProcessWorkItemOrTimerCallback(adapter);
  197. }
  198. VOID ProcessWorkItemOrTimerCallback(ADAPTEREXT *adapter)
  199. {
  200. BOOLEAN stillHaveReadDeficit;
  201. KIRQL oldIrql;
  202. if (adapter->initialized && !adapter->halting){
  203. /*
  204. * Attempt to service any read deficit.
  205. * If read packets are still not available, then this
  206. * will NOT queue another workItem in TryReadUSB
  207. * because adapter->workItemOrTimerPending is STILL SET.
  208. */
  209. ServiceReadDeficit(adapter);
  210. #if DO_FULL_RESET
  211. if (adapter->needFullReset){
  212. /*
  213. * We can only do a full reset if we are not at DPC level,
  214. * so skip it if we are called from the timer DPC.
  215. */
  216. if (KeGetCurrentIrql() <= APC_LEVEL){
  217. AdapterFullResetAndRestore(adapter);
  218. }
  219. }
  220. #endif
  221. }
  222. KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
  223. ASSERT(adapter->workItemOrTimerPending);
  224. adapter->workItemOrTimerPending = FALSE;
  225. KeSetEvent(&adapter->workItemOrTimerEvent, 0, FALSE);
  226. stillHaveReadDeficit = (adapter->readDeficit > 0);
  227. KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
  228. /*
  229. * If we were not able to service the entire read deficit,
  230. * (e.g. because no free packets have become available)
  231. * then schedule another workItem so that we try again later.
  232. */
  233. if (stillHaveReadDeficit && !adapter->halting){
  234. QueueAdapterWorkItem(adapter);
  235. }
  236. }