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.

692 lines
21 KiB

  1. /* ++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name :
  4. int.c
  5. Abstract:
  6. Interrupt Pipe handler
  7. Based on read.c
  8. Author:
  9. Jeff Midkiff (jeffmi) 08-20-99
  10. --*/
  11. #include "wceusbsh.h"
  12. VOID
  13. RestartInterruptWorkItem(
  14. IN PWCE_WORK_ITEM PWorkItem
  15. );
  16. NTSTATUS
  17. UsbInterruptComplete(
  18. IN PDEVICE_OBJECT DeviceObject,
  19. IN PIRP Irp,
  20. IN PVOID Context
  21. );
  22. //
  23. // called with control lock held
  24. //
  25. #define START_ANOTHER_INTERRUPT( _PDevExt, _AcquireLock ) \
  26. ( (IRP_STATE_COMPLETE == _PDevExt->IntState) && \
  27. CanAcceptIoRequests(_PDevExt->DeviceObject, _AcquireLock, TRUE) \
  28. )
  29. //
  30. // This function allocates a single Irp & Urb to be continously
  31. // submitted to USBD for INT pipe notifications.
  32. // It is called from StartDevice.
  33. // The Irp & Urb are finally freed in StopDevice.
  34. //
  35. NTSTATUS
  36. AllocUsbInterrupt(
  37. IN PDEVICE_EXTENSION PDevExt
  38. )
  39. {
  40. NTSTATUS status = STATUS_SUCCESS;
  41. PIRP pIrp;
  42. PURB pUrb;
  43. PAGED_CODE();
  44. DbgDump(DBG_INT, (">AllocUsbInterrupt(%p)\n", PDevExt->DeviceObject));
  45. ASSERT( PDevExt );
  46. if ( !PDevExt->IntPipe.hPipe ) {
  47. status = STATUS_UNSUCCESSFUL;
  48. DbgDump(DBG_ERR, ("AllocUsbInterrupt: 0x%x\n", status ));
  49. } else {
  50. ASSERT( NULL == PDevExt->IntIrp );
  51. pIrp = IoAllocateIrp( (CCHAR)(PDevExt->NextDevice->StackSize + 1), FALSE);
  52. if (pIrp) {
  53. //
  54. // fixup irp so we can pass to ourself,
  55. // and to USBD
  56. //
  57. FIXUP_RAW_IRP( pIrp, PDevExt->DeviceObject );
  58. //
  59. // alloc the int pipe's Urb
  60. //
  61. pUrb = ExAllocateFromNPagedLookasideList( &PDevExt->BulkTransferUrbPool );
  62. if (pUrb) {
  63. // save these to be freed when not needed
  64. SetPVoidLocked( &PDevExt->IntIrp,
  65. pIrp,
  66. &PDevExt->ControlLock);
  67. SetPVoidLocked( &PDevExt->IntUrb,
  68. pUrb,
  69. &PDevExt->ControlLock);
  70. DbgDump(DBG_INT, ("IntIrp: %p\t IntUrb: %p\n", PDevExt->IntIrp, PDevExt->IntUrb));
  71. InterlockedExchange(&PDevExt->IntState, IRP_STATE_COMPLETE);
  72. KeInitializeEvent( &PDevExt->IntCancelEvent,
  73. SynchronizationEvent,
  74. FALSE);
  75. } else {
  76. //
  77. // this is a fatal err since we can't post int requests to USBD
  78. //
  79. status = STATUS_INSUFFICIENT_RESOURCES;
  80. DbgDump(DBG_ERR, ("AllocUsbInterrupt: 0x%x\n", status ));
  81. TEST_TRAP();
  82. }
  83. } else {
  84. //
  85. // this is a fatal err since we can't post int requests to USBD
  86. //
  87. status = STATUS_INSUFFICIENT_RESOURCES;
  88. DbgDump(DBG_ERR, ("AllocUsbInterrupt: 0x%x\n", status ));
  89. TEST_TRAP();
  90. }
  91. }
  92. DbgDump(DBG_INT, ("<AllocUsbInterrupt 0x%x\n", status ));
  93. return status;
  94. }
  95. //
  96. // This routine takes the device's current IntIrp and submits it to USBD.
  97. // When the Irp is completed by USBD our completion routine fires.
  98. //
  99. // Return: successful return value is STATUS_SUCCESS, or
  100. // STATUS_PENDING - which means the I/O is pending in the USB stack.
  101. //
  102. NTSTATUS
  103. UsbInterruptRead(
  104. IN PDEVICE_EXTENSION PDevExt
  105. )
  106. {
  107. PIO_STACK_LOCATION pNextStack;
  108. NTSTATUS status = STATUS_SUCCESS;
  109. KIRQL irql;
  110. DbgDump(DBG_INT, (">UsbInterruptRead(%p)\n", PDevExt->DeviceObject));
  111. do {
  112. //
  113. // check our USB INT state
  114. //
  115. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  116. if ( !PDevExt->IntPipe.hPipe || !PDevExt->IntIrp ||
  117. !PDevExt->IntUrb || !PDevExt->IntBuff ) {
  118. status = STATUS_UNSUCCESSFUL;
  119. DbgDump(DBG_ERR, ("UsbInterruptRead: 0x%x\n", status ));
  120. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  121. break;
  122. }
  123. if ( !CanAcceptIoRequests(PDevExt->DeviceObject, FALSE, TRUE) ) {
  124. status = STATUS_DELETE_PENDING;
  125. DbgDump(DBG_ERR, ("UsbInterruptRead: 0x%x\n", status ));
  126. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  127. break;
  128. }
  129. #if DBG
  130. if (IRP_STATE_CANCELLED == PDevExt->IntState)
  131. TEST_TRAP();
  132. #endif
  133. //
  134. // we post our INT irp to USB if it has been completed (not cancelled),
  135. // and the device is accepting requests
  136. //
  137. if ( START_ANOTHER_INTERRUPT( PDevExt, FALSE ) ) {
  138. status = AcquireRemoveLock(&PDevExt->RemoveLock, PDevExt->IntIrp);
  139. if ( !NT_SUCCESS(status) ) {
  140. DbgDump(DBG_ERR, ("UsbInterruptRead: 0x%x\n", status ));
  141. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  142. break;
  143. }
  144. ASSERT( IRP_STATE_COMPLETE == PDevExt->IntState);
  145. InterlockedExchange(&PDevExt->IntState, IRP_STATE_PENDING);
  146. KeClearEvent( &PDevExt->PendingIntEvent );
  147. KeClearEvent( &PDevExt->IntCancelEvent );
  148. RecycleIrp( PDevExt->DeviceObject, PDevExt->IntIrp );
  149. UsbBuildTransferUrb( PDevExt->IntUrb,
  150. PDevExt->IntBuff,
  151. PDevExt->IntPipe.MaxPacketSize,
  152. PDevExt->IntPipe.hPipe,
  153. TRUE );
  154. //
  155. // set Irp up for a submit Urb IOCTL
  156. //
  157. IoCopyCurrentIrpStackLocationToNext(PDevExt->IntIrp);
  158. pNextStack = IoGetNextIrpStackLocation(PDevExt->IntIrp);
  159. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  160. pNextStack->Parameters.Others.Argument1 = PDevExt->IntUrb;
  161. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  162. //
  163. // completion routine will take care of updating buffer
  164. //
  165. IoSetCompletionRoutine( PDevExt->IntIrp,
  166. UsbInterruptComplete,
  167. NULL, //PDevExt, // Context
  168. TRUE, TRUE, TRUE);
  169. InterlockedIncrement(&PDevExt->PendingIntCount);
  170. KeReleaseSpinLock( &PDevExt->ControlLock, irql );
  171. status = IoCallDriver(PDevExt->NextDevice, PDevExt->IntIrp );
  172. if ( (STATUS_SUCCESS != status) && (STATUS_PENDING != status)) {
  173. //
  174. // We can end up here after our completion routine runs
  175. // for an error condition i.e., when we have an
  176. // invalid parameter, or when user pulls the plug, etc.
  177. //
  178. DbgDump(DBG_ERR, ("UsbInterruptRead: 0x%x\n", status));
  179. }
  180. } else {
  181. //
  182. // we did not post an INT, but this is not an error condition
  183. //
  184. status = STATUS_SUCCESS;
  185. DbgDump(DBG_INT, ("!UsbInterruptRead RE: 0x%x\n", PDevExt->IntState ));
  186. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  187. }
  188. } while (0);
  189. DbgDump(DBG_INT, ("<UsbInterruptRead 0x%x\n", status ));
  190. return status;
  191. }
  192. /*
  193. This completion routine fires when USBD completes our IntIrp
  194. Note: we allocated the Irp, and recycle it.
  195. Always return STATUS_MORE_PROCESSING_REQUIRED to retain the Irp.
  196. This routine runs at DPC_LEVEL.
  197. Interrupt Endpoint:
  198. This endpoint will be used to indicate the availability of IN data,
  199. as well as to reflect the state of the device serial control lines :
  200. D15..D3 Reserved
  201. D2 DSR state (1=Active, 0=Inactive)
  202. D1 CTS state (1=Active, 0=Inactive)
  203. D0 Data Available - (1=Host should read IN endpoint, 0=No data currently available)
  204. */
  205. NTSTATUS
  206. UsbInterruptComplete(
  207. IN PDEVICE_OBJECT PDevObj,
  208. IN PIRP Irp,
  209. IN PVOID Context)
  210. {
  211. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  212. ULONG count;
  213. KIRQL irql;
  214. PIRP pCurrentMaskIrp = NULL;
  215. NTSTATUS irpStatus;
  216. USBD_STATUS urbStatus;
  217. USHORT usNewMSR;
  218. USHORT usOldMSR;
  219. USHORT usDeltaMSR;
  220. NTSTATUS workStatus;
  221. BOOLEAN bStartRead = FALSE;
  222. UNREFERENCED_PARAMETER( Irp );
  223. UNREFERENCED_PARAMETER( Context );
  224. ASSERT( pDevExt->IntIrp == Irp );
  225. ASSERT( pDevExt->IntBuff );
  226. DbgDump(DBG_INT, (">UsbInterruptComplete(%p)\n", PDevObj));
  227. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  228. //
  229. // Our INT state should be either pending or cancelled at this point.
  230. // If it pending then USB is completing the Irp normally.
  231. // If it is cancelled then our Cancel routine set it,
  232. // in which case USB can complete the irp normally or as cancelled
  233. // depending on where it was in processing. If the state is cancelled
  234. // then do NOT set to complete, else the Irp will
  235. // go back down to USB and you are hosed.
  236. //
  237. ASSERT( (IRP_STATE_PENDING == pDevExt->IntState)
  238. || (IRP_STATE_CANCELLED== pDevExt->IntState) );
  239. if (IRP_STATE_PENDING == pDevExt->IntState) {
  240. InterlockedExchange(&pDevExt->IntState, IRP_STATE_COMPLETE);
  241. }
  242. //
  243. // signal everyone if this is the last IRP
  244. //
  245. if ( 0 == InterlockedDecrement(&pDevExt->PendingIntCount) ) {
  246. // DbgDump(DBG_INT, ("PendingIntCount: 0\n"));
  247. // when we drop back to passive level they will get signalled
  248. KeSetEvent(&pDevExt->PendingIntEvent, IO_SERIAL_INCREMENT, FALSE);
  249. }
  250. //
  251. // get the completion info
  252. //
  253. count = pDevExt->IntUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  254. irpStatus = pDevExt->IntIrp->IoStatus.Status;
  255. DbgDump(DBG_INT, ("Irp->IoStatus.Status 0x%x\n", irpStatus));
  256. urbStatus = pDevExt->IntUrb->UrbHeader.Status;
  257. DbgDump(DBG_INT, ("Urb->UrbHeader.Status 0x%x\n", urbStatus ));
  258. switch (irpStatus) {
  259. case STATUS_SUCCESS: {
  260. ASSERT( USBD_STATUS_SUCCESS == urbStatus );
  261. //
  262. // clear pipe error count
  263. //
  264. InterlockedExchange( &pDevExt->IntDeviceErrors, 0);
  265. #if DBG
  266. if (DebugLevel & DBG_DUMP_INT) {
  267. ULONG i;
  268. DbgDump(DBG_INT, ("IntBuff[%d]: ", count ));
  269. for (i=0; i < count; i++) {
  270. KdPrint( ("%02x ", pDevExt->IntBuff[i] ) );
  271. }
  272. KdPrint(("\n"));
  273. }
  274. #endif
  275. //
  276. // Get Data Ready
  277. //
  278. // D0 - Data Available (1=Host should read IN endpoint, 0=No data currently available)
  279. //
  280. if ( pDevExt->IntBuff[0] & USB_COMM_DATA_READY_MASK ) {
  281. DbgDump(DBG_INT, ("Data Ready\n"));
  282. bStartRead = TRUE;
  283. // Note: we may be prematurely setting this bit since we have not
  284. // confirmed data reception, but need to get the user's read started.
  285. // Perhaps only set if not using the ring-buffer, since buffered reads are not bound to app's reads.
  286. pDevExt->SerialPort.HistoryMask |= SERIAL_EV_RXCHAR;
  287. }
  288. //
  289. // Get Modem Status Register
  290. //
  291. // D1 CTS state (1=Active, 0=Inactive)
  292. // D2 DSR state (1=Active, 0=Inactive)
  293. //
  294. usOldMSR = pDevExt->SerialPort.ModemStatus;
  295. usNewMSR = pDevExt->IntBuff[0] & USB_COMM_MODEM_STATUS_MASK;
  296. DbgDump(DBG_INT, ("USB_COMM State: 0x%x\n", usNewMSR));
  297. if (usNewMSR & USB_COMM_CTS) {
  298. pDevExt->SerialPort.ModemStatus |= SERIAL_MSR_CTS;
  299. } else {
  300. pDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_CTS;
  301. }
  302. if (usNewMSR & USB_COMM_DSR) {
  303. pDevExt->SerialPort.ModemStatus |= SERIAL_MSR_DSR | SERIAL_MSR_DCD;
  304. } else {
  305. pDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DSR & ~SERIAL_MSR_DCD;
  306. }
  307. // see what has changed in the status register
  308. usDeltaMSR = usOldMSR ^ pDevExt->SerialPort.ModemStatus;
  309. if (/*(pDevExt->SerialPort.RS232Lines & SERIAL_RTS_STATE) && */
  310. (usDeltaMSR & SERIAL_MSR_CTS)) {
  311. pDevExt->SerialPort.HistoryMask |= SERIAL_EV_CTS;
  312. pDevExt->SerialPort.ModemStatus |= SERIAL_MSR_DCTS;
  313. }
  314. if (/*(pDevExt->SerialPort.RS232Lines & SERIAL_DTR_STATE) && */
  315. (usDeltaMSR & SERIAL_MSR_DSR)) {
  316. pDevExt->SerialPort.HistoryMask |= SERIAL_EV_DSR | SERIAL_EV_RLSD;
  317. pDevExt->SerialPort.ModemStatus |= SERIAL_MSR_DDSR | SERIAL_MSR_DDCD;
  318. }
  319. DbgDump(DBG_INT, ("SerialPort.MSR: 0x%x\n", pDevExt->SerialPort.ModemStatus));
  320. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  321. //
  322. // signal serial events @ DISPATCH_LEVEL before starting our UsbRead,
  323. // since we run at higher IRQL than apps.
  324. //
  325. ProcessSerialWaits( pDevExt );
  326. if ( bStartRead ) {
  327. //
  328. // Get the data.
  329. // We do set a timeout on 1st read, in case the INT was illegit.
  330. // Note: we start this read @ DISPATCH_LEVEL.
  331. //
  332. UsbRead( pDevExt,
  333. TRUE );
  334. }
  335. //
  336. // Queue a passive work item to sync execution of the INT pipe and the IN pipe
  337. // and then start the next INT packet.
  338. //
  339. workStatus = QueueWorkItem( PDevObj,
  340. RestartInterruptWorkItem,
  341. NULL,
  342. 0 );
  343. }
  344. break;
  345. case STATUS_CANCELLED: {
  346. DbgDump(DBG_INT|DBG_IRP, ("Int: STATUS_CANCELLED\n"));
  347. // signal anyone who cancelled this or is waiting for it to stop
  348. //
  349. KeSetEvent(&pDevExt->IntCancelEvent, IO_SERIAL_INCREMENT, FALSE);
  350. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  351. }
  352. break;
  353. case STATUS_DEVICE_DATA_ERROR: {
  354. //
  355. // generic device error set by USBD.
  356. //
  357. DbgDump(DBG_ERR, ("IntPipe STATUS_DEVICE_DATA_ERROR: 0x%x\n", urbStatus ));
  358. //
  359. // bump pipe error count
  360. //
  361. InterlockedIncrement( &pDevExt->IntDeviceErrors);
  362. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  363. //
  364. // is the endpoint is stalled?
  365. //
  366. if ( USBD_HALTED(pDevExt->IntUrb->UrbHeader.Status) ) {
  367. //
  368. // queue a reset request,
  369. // which also starts another INT
  370. //
  371. workStatus = QueueWorkItem( PDevObj,
  372. UsbResetOrAbortPipeWorkItem,
  373. (PVOID)((LONG_PTR)urbStatus),
  374. WORK_ITEM_RESET_INT_PIPE );
  375. } else {
  376. //
  377. // queue a passive work item to start the next INT packet.
  378. //
  379. workStatus = QueueWorkItem( PDevObj,
  380. RestartInterruptWorkItem,
  381. NULL,
  382. 0 );
  383. }
  384. }
  385. break;
  386. default:
  387. DbgDump(DBG_WRN|DBG_INT, ("Unhandled INT Pipe status: 0x%x 0x%x\n", irpStatus, urbStatus ));
  388. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  389. break;
  390. }
  391. ReleaseRemoveLock(&pDevExt->RemoveLock, pDevExt->IntIrp);
  392. DbgDump(DBG_INT, ("<UsbInterruptComplete\n"));
  393. return STATUS_MORE_PROCESSING_REQUIRED;
  394. }
  395. //
  396. // This routine requests USB to cancel our INT Irp.
  397. // It must be called at passive level.
  398. // Note: it is the responsibility of the caller to
  399. // reset the IntState to IRP_STATE_COMPLETE and restart USB Ints
  400. // when this routine completes. Else, no more Interrupts will get posted.
  401. //
  402. NTSTATUS
  403. CancelUsbInterruptIrp(
  404. IN PDEVICE_OBJECT PDevObj
  405. )
  406. {
  407. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  408. NTSTATUS status = STATUS_SUCCESS;
  409. NTSTATUS wait_status;
  410. KIRQL irql;
  411. DbgDump(DBG_INT|DBG_IRP, (">CancelUsbInterruptIrp\n"));
  412. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  413. if ( pDevExt->IntPipe.hPipe && pDevExt->IntIrp ) {
  414. switch (pDevExt->IntState) {
  415. //case IRP_STATE_START:
  416. case IRP_STATE_PENDING:
  417. {
  418. //
  419. // the Irp is pending somewhere down the USB stack...
  420. //
  421. PVOID Objects[2] = { &pDevExt->PendingIntEvent,
  422. &pDevExt->IntCancelEvent };
  423. //
  424. // signal we need to cancel the Irp
  425. //
  426. pDevExt->IntState = IRP_STATE_CANCELLED;
  427. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  428. if ( !IoCancelIrp( pDevExt->IntIrp ) ) {
  429. //
  430. // This means USB has the IntIrp in a non-canceable state.
  431. // We still need to wait for either the pending INT event, or the cancel event.
  432. //
  433. DbgDump(DBG_INT|DBG_IRP, ("Irp (%p) was not cancelled\n", pDevExt->IntIrp ));
  434. // TEST_TRAP();
  435. }
  436. DbgDump(DBG_INT|DBG_IRP, ("Waiting for pending IntIrp (%p) to cancel...\n", pDevExt->IntIrp ));
  437. PAGED_CODE();
  438. wait_status = KeWaitForMultipleObjects(
  439. 2,
  440. Objects,
  441. WaitAny,
  442. Executive,
  443. KernelMode,
  444. FALSE,
  445. NULL,
  446. NULL );
  447. DbgDump(DBG_INT|DBG_IRP, ("...IntIrp (%p) signalled by: %d\n", pDevExt->IntIrp, wait_status ));
  448. //
  449. // At this point we have the Irp back from USB
  450. //
  451. }
  452. break;
  453. case IRP_STATE_COMPLETE:
  454. case IRP_STATE_CANCELLED:
  455. pDevExt->IntState = IRP_STATE_CANCELLED;
  456. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  457. break;
  458. default:
  459. DbgDump(DBG_ERR, ("CancelUsbInterruptIrp - Invalid IntState: 0x%x\n", pDevExt->IntState ));
  460. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  461. break;
  462. }
  463. if ( (IRP_STATE_CANCELLED != pDevExt->IntState) ||
  464. (0 != pDevExt->PendingIntCount) ) {
  465. DbgDump(DBG_ERR, ("CancelUsbInterruptIrp error: IntState: 0x%x \tPendingIntCount: 0x%x\n", pDevExt->IntState, pDevExt->PendingIntCount ));
  466. TEST_TRAP();
  467. }
  468. } else {
  469. status = STATUS_UNSUCCESSFUL;
  470. DbgDump(DBG_ERR, ("No INT Irp\n" ));
  471. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  472. // TEST_TRAP();
  473. }
  474. DbgDump(DBG_INT|DBG_IRP, ("<CancelUsbInterruptIrp\n"));
  475. return status;
  476. }
  477. //
  478. // Work item queued from interrupt completion
  479. // to sync execution of the INT pipe and the IN pipe
  480. // and then start another USB INT read if there is not one already in progress
  481. //
  482. VOID
  483. RestartInterruptWorkItem(
  484. IN PWCE_WORK_ITEM PWorkItem
  485. )
  486. {
  487. PDEVICE_OBJECT pDevObj = PWorkItem->DeviceObject;
  488. PDEVICE_EXTENSION pDevExt = pDevObj->DeviceExtension;
  489. NTSTATUS status = STATUS_DELETE_PENDING;
  490. NTSTATUS wait_status;
  491. KIRQL irql;
  492. DbgDump(DBG_INT|DBG_WORK_ITEMS, (">RestartInterruptWorkItem(%p)\n", pDevObj ));
  493. KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
  494. //
  495. // Is the READ Irp is pending somewhere in the USB stack?
  496. //
  497. if ( IRP_STATE_PENDING == pDevExt->UsbReadState ) {
  498. //
  499. // Then we need to sync with the Usb Read Completion routine.
  500. //
  501. #define WAIT_REASONS 2
  502. PVOID Objects[WAIT_REASONS] = { &pDevExt->UsbReadCancelEvent,
  503. &pDevExt->PendingDataInEvent };
  504. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  505. DbgDump(DBG_INT, ("INT pipe waiting for pending UsbReadIrp (%p) to finish...\n", pDevExt->UsbReadIrp ));
  506. PAGED_CODE();
  507. wait_status = KeWaitForMultipleObjects( WAIT_REASONS,
  508. Objects,
  509. WaitAny,
  510. Executive,
  511. KernelMode,
  512. FALSE,
  513. NULL,
  514. NULL );
  515. DbgDump(DBG_INT, ("...UsbReadIrp (%p) signalled by: %d\n", pDevExt->UsbReadIrp, wait_status ));
  516. //
  517. // At this point the read packet is back on our list
  518. // and we have the UsbReadIrp back from USB
  519. //
  520. } else {
  521. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  522. }
  523. // start another INT read
  524. if ( START_ANOTHER_INTERRUPT(pDevExt, TRUE) ) {
  525. status = UsbInterruptRead( pDevExt );
  526. }
  527. DequeueWorkItem( pDevObj, PWorkItem );
  528. DbgDump(DBG_INT|DBG_WORK_ITEMS, ("<RestartInterruptWorkItem 0x%x\n", status ));
  529. PAGED_CODE(); // we must exit at passive level
  530. return;
  531. }