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.

1515 lines
43 KiB

  1. /***************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. INTREAD.C
  5. Abstract:
  6. Generic USB routines - must be called at PASSIVE_LEVEL
  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) 2001 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 01/08/2001 : created
  17. Authors:
  18. Tom Green
  19. ****************************************************************************/
  20. #include "pch.h"
  21. #include <usb.h>
  22. #include <usbdrivr.h>
  23. #include <usbdlib.h>
  24. #include <ntstatus.h>
  25. #include "usbutil.h"
  26. #include "usbdbg.h"
  27. #include "intread.h"
  28. #include "usbpriv.h"
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(PAGE, USBCallSyncEx)
  31. #pragma alloc_text(PAGE, USBVendorRequestEx)
  32. #pragma alloc_text(PAGE, USBClassRequestEx)
  33. #pragma alloc_text(PAGE, USBStartInterruptTransfers)
  34. #pragma alloc_text(PAGE, USBStopInterruptTransfers)
  35. #pragma alloc_text(PAGE, USBStartSelectiveSuspend)
  36. #pragma alloc_text(PAGE, USBStopSelectiveSuspend)
  37. #endif // ALLOC_PRAGMA
  38. /*
  39. ********************************************************************************
  40. * UsbWrapInitializeInterruptReadData
  41. ********************************************************************************
  42. *
  43. *
  44. */
  45. NTSTATUS UsbWrapInitializeInterruptReadData(
  46. IN PUSB_WRAPPER_EXTENSION WrapExtension,
  47. IN PUSBD_PIPE_INFORMATION InterruptPipe,
  48. IN INTERRUPT_CALLBACK DriverCallback,
  49. IN PVOID DriverContext,
  50. IN ULONG MaxTransferSize,
  51. IN ULONG NotificationTypes,
  52. IN ULONG PingPongCount)
  53. {
  54. WrapExtension->IntReadWrap.InterruptPipe = InterruptPipe;
  55. WrapExtension->IntReadWrap.MaxTransferSize = MaxTransferSize;
  56. WrapExtension->IntReadWrap.ClientCallback = DriverCallback;
  57. WrapExtension->IntReadWrap.ClientContext = DriverContext;
  58. WrapExtension->IntReadWrap.NotificationTypes = NotificationTypes;
  59. WrapExtension->IntReadWrap.NumPingPongs = PingPongCount;
  60. WrapExtension->IntReadWrap.OutstandingRequests = 0;
  61. WrapExtension->IntReadWrap.WorkItemRunning = 0;
  62. WrapExtension->IntReadWrap.TransferCount = 0;
  63. return STATUS_SUCCESS;
  64. }
  65. /*
  66. ********************************************************************************
  67. * UsbWrapInitializePingPongIrps
  68. ********************************************************************************
  69. *
  70. *
  71. */
  72. NTSTATUS UsbWrapInitializePingPongIrps(PUSB_WRAPPER_EXTENSION WrapExtension)
  73. {
  74. NTSTATUS result = STATUS_SUCCESS;
  75. ULONG i;
  76. CCHAR numIrpStackLocations;
  77. PAGED_CODE();
  78. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapInitializePingPongIrps\n"));
  79. numIrpStackLocations = WrapExtension->LowerDeviceObject->StackSize;
  80. //
  81. // Initialize the queues for interrupt read data
  82. //
  83. InitializeListHead(&WrapExtension->IntReadWrap.SavedQueue);
  84. InitializeListHead(&WrapExtension->IntReadWrap.IncomingQueue);
  85. KeInitializeSpinLock(&WrapExtension->IntReadWrap.QueueLock);
  86. ASSERT(WrapExtension->IntReadWrap.NumPingPongs > 0);
  87. WrapExtension->IntReadWrap.PingPongs = ALLOC_MEM(NonPagedPool,
  88. WrapExtension->IntReadWrap.NumPingPongs*sizeof(USB_WRAPPER_PINGPONG),
  89. USBWRAP_TAG);
  90. if (WrapExtension->IntReadWrap.PingPongs){
  91. ULONG transferBufferSize = WrapExtension->IntReadWrap.MaxTransferSize;
  92. RtlZeroMemory(WrapExtension->IntReadWrap.PingPongs,
  93. WrapExtension->IntReadWrap.NumPingPongs*sizeof(USB_WRAPPER_PINGPONG));
  94. for (i = 0; i < WrapExtension->IntReadWrap.NumPingPongs; i++) {
  95. WrapExtension->IntReadWrap.PingPongs[i].myWrapExt = WrapExtension;
  96. WrapExtension->IntReadWrap.PingPongs[i].weAreCancelling = 0;
  97. WrapExtension->IntReadWrap.PingPongs[i].sig = PINGPONG_SIG;
  98. WrapExtension->IntReadWrap.PingPongs[i].irp = IoAllocateIrp(numIrpStackLocations+1, FALSE);
  99. if (WrapExtension->IntReadWrap.PingPongs[i].irp){
  100. PURB pUrb;
  101. KeInitializeEvent(&WrapExtension->IntReadWrap.PingPongs[i].sentEvent,
  102. NotificationEvent,
  103. TRUE); // Set to signaled
  104. KeInitializeEvent(&WrapExtension->IntReadWrap.PingPongs[i].pumpDoneEvent,
  105. NotificationEvent,
  106. TRUE); // Set to signaled
  107. pUrb = ALLOC_MEM( NonPagedPool, sizeof(URB), USBWRAP_TAG);
  108. if(pUrb) {
  109. USHORT size;
  110. PIO_STACK_LOCATION NextStack = NULL;
  111. RtlZeroMemory(pUrb, sizeof(URB));
  112. WrapExtension->IntReadWrap.PingPongs[i].urb = pUrb;
  113. } else {
  114. result = STATUS_INSUFFICIENT_RESOURCES;
  115. FREE_MEM(WrapExtension->IntReadWrap.PingPongs[i].irp);
  116. break;
  117. }
  118. } else {
  119. result = STATUS_INSUFFICIENT_RESOURCES;
  120. break;
  121. }
  122. }
  123. } else {
  124. result = STATUS_INSUFFICIENT_RESOURCES;
  125. }
  126. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapInitializePingPongIrps (0x%x)\n", result));
  127. return result;
  128. }
  129. /*
  130. ********************************************************************************
  131. * UsbWrapSubmitInterruptRead
  132. ********************************************************************************
  133. *
  134. *
  135. */
  136. NTSTATUS UsbWrapSubmitInterruptRead(
  137. IN PUSB_WRAPPER_EXTENSION WrapExtension,
  138. PUSB_WRAPPER_PINGPONG PingPong,
  139. BOOLEAN *IrpSent)
  140. {
  141. NTSTATUS status = STATUS_SUCCESS;
  142. PIO_STACK_LOCATION irpSp;
  143. KIRQL oldIrql;
  144. BOOLEAN proceed;
  145. LONG oldInterlock;
  146. ULONG transferBufferSize;
  147. PIRP irp = PingPong->irp;
  148. PURB urb = PingPong->urb;
  149. ASSERT(irp);
  150. *IrpSent = FALSE;
  151. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapSubmitInterruptRead\n"));
  152. while (1) {
  153. if (NT_SUCCESS(status)) {
  154. oldInterlock = InterlockedExchange(&PingPong->ReadInterlock,
  155. PINGPONG_START_READ);
  156. ASSERT(oldInterlock == PINGPONG_END_READ);
  157. irp->Cancel = FALSE;
  158. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  159. /*
  160. * Send down the read IRP.
  161. */
  162. KeResetEvent(&PingPong->sentEvent);
  163. if (PingPong->weAreCancelling) {
  164. InterlockedDecrement(&PingPong->weAreCancelling);
  165. //
  166. // Ordering of the next two instructions is crucial, since
  167. // CancelPingPongs will exit after pumpDoneEvent is set, and the
  168. // pingPongs could be deleted after that.
  169. //
  170. DBGPRINT(DBG_USBUTIL_TRACE, ("Pingpong %x cancelled in submit before sending\n", PingPong))
  171. KeSetEvent (&PingPong->sentEvent, 0, FALSE);
  172. KeSetEvent(&PingPong->pumpDoneEvent, 0, FALSE);
  173. status = STATUS_CANCELLED;
  174. break;
  175. } else {
  176. PIO_STACK_LOCATION NextStack = NULL;
  177. UsbBuildInterruptOrBulkTransferRequest(PingPong->urb,
  178. (USHORT) sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
  179. WrapExtension->IntReadWrap.InterruptPipe->PipeHandle,
  180. NULL,
  181. NULL,
  182. WrapExtension->IntReadWrap.MaxTransferSize,
  183. USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
  184. NULL);
  185. urb->UrbBulkOrInterruptTransfer.TransferBuffer = UsbWrapGetTransferBuffer(WrapExtension);
  186. urb->UrbBulkOrInterruptTransfer.TransferBufferLength = WrapExtension->IntReadWrap.MaxTransferSize;
  187. if (urb->UrbBulkOrInterruptTransfer.TransferBuffer == NULL) {
  188. KeSetEvent (&PingPong->sentEvent, 0, FALSE);
  189. KeSetEvent(&PingPong->pumpDoneEvent, 0, FALSE);
  190. status = STATUS_INSUFFICIENT_RESOURCES;
  191. break;
  192. }
  193. InterlockedIncrement(&WrapExtension->IntReadWrap.OutstandingRequests);
  194. DBGPRINT(DBG_USBUTIL_TRACE, ("Sending pingpong %x from Submit\n", PingPong))
  195. IoSetCompletionRoutine( irp,
  196. UsbWrapInterruptReadComplete,
  197. WrapExtension, // context
  198. TRUE,
  199. TRUE,
  200. TRUE );
  201. NextStack = IoGetNextIrpStackLocation(PingPong->irp);
  202. ASSERT(NextStack);
  203. NextStack->Parameters.Others.Argument1 = PingPong->urb;
  204. NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  205. NextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  206. NextStack->DeviceObject = WrapExtension->LowerDeviceObject;
  207. status = IoCallDriver(WrapExtension->LowerDeviceObject, irp);
  208. KeSetEvent (&PingPong->sentEvent, 0, FALSE);
  209. *IrpSent = TRUE;
  210. }
  211. if (PINGPONG_IMMEDIATE_READ != InterlockedExchange(&PingPong->ReadInterlock,
  212. PINGPONG_END_READ)) {
  213. //
  214. // The read is asynch, will call SubmitInterruptRead from the
  215. // completion routine
  216. //
  217. DBGPRINT(DBG_USBUTIL_TRACE, ("read is pending\n"))
  218. break;
  219. } else {
  220. //
  221. // The read was synchronous (probably bytes in the buffer). The
  222. // completion routine will not call SubmitInterruptRead, so we
  223. // just loop here. This is to prevent us from running out of stack
  224. // space if always call StartRead from the completion routine
  225. //
  226. status = irp->IoStatus.Status;
  227. DBGPRINT(DBG_USBUTIL_TRACE, ("read is looping with status %x\n", status))
  228. }
  229. } else {
  230. // if (PingPong->weAreCancelling ) {
  231. // We are stopping the read pump.
  232. // set this event and stop resending the pingpong IRP.
  233. DBGPRINT(DBG_USBUTIL_TRACE, ("We are cancelling bit set for pingpong %x\n", PingPong))
  234. // InterlockedDecrement(&PingPong->weAreCancelling);
  235. KeSetEvent(&PingPong->pumpDoneEvent, 0, FALSE);
  236. break;
  237. // }
  238. }
  239. }
  240. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapSubmitInterruptRead (0x%x)\n", status));
  241. return status;
  242. }
  243. /*
  244. ********************************************************************************
  245. * UsbWrapIsDeviceConnected
  246. ********************************************************************************
  247. *
  248. *
  249. */
  250. NTSTATUS
  251. UsbWrapIsDeviceConnected (
  252. IN PUSB_WRAPPER_EXTENSION WrapExt
  253. )
  254. {
  255. PIRP irp;
  256. KEVENT event;
  257. PIO_STACK_LOCATION nextStack;
  258. ULONG portStatus;
  259. NTSTATUS status;
  260. IO_STATUS_BLOCK iostatus;
  261. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapIsDeviceConnected\n"));
  262. // Initialize the event we'll wait on.
  263. //
  264. KeInitializeEvent(&event,
  265. SynchronizationEvent,
  266. FALSE);
  267. // Allocate the Irp
  268. //
  269. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS,
  270. WrapExt->LowerDeviceObject,
  271. NULL,
  272. 0,
  273. NULL,
  274. 0,
  275. TRUE,
  276. &event,
  277. &iostatus);
  278. if (irp == NULL)
  279. {
  280. return STATUS_INSUFFICIENT_RESOURCES;
  281. }
  282. // Set the Irp parameters
  283. //
  284. nextStack = IoGetNextIrpStackLocation(irp);
  285. nextStack->Parameters.Others.Argument1 = &portStatus;
  286. // Pass the Irp down the stack
  287. //
  288. status = IoCallDriver(WrapExt->LowerDeviceObject,
  289. irp);
  290. // If the request is pending, block until it completes
  291. //
  292. if (status == STATUS_PENDING)
  293. {
  294. KeWaitForSingleObject(&event,
  295. Executive,
  296. KernelMode,
  297. FALSE,
  298. NULL);
  299. status = iostatus.Status;
  300. }
  301. if (NT_SUCCESS(status) && !(portStatus & USBD_PORT_CONNECTED))
  302. {
  303. status = STATUS_DEVICE_DOES_NOT_EXIST;
  304. }
  305. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapIsDeviceConnected (0x%x)\n", status));
  306. return status;
  307. }
  308. /*
  309. ********************************************************************************
  310. * UsbWrapResetDevice
  311. ********************************************************************************
  312. *
  313. *
  314. */
  315. NTSTATUS
  316. UsbWrapResetDevice (
  317. IN PUSB_WRAPPER_EXTENSION WrapExt
  318. )
  319. {
  320. NTSTATUS status;
  321. KEVENT event;
  322. PIRP irp;
  323. IO_STATUS_BLOCK iostatus;
  324. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapResetDevice\n"));
  325. KeInitializeEvent(&event, NotificationEvent, FALSE);
  326. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_RESET_PORT,
  327. WrapExt->LowerDeviceObject,
  328. NULL,
  329. 0,
  330. NULL,
  331. 0,
  332. TRUE,
  333. &event,
  334. &iostatus);
  335. if (irp == NULL) {
  336. return STATUS_INSUFFICIENT_RESOURCES;
  337. }
  338. status = IoCallDriver(WrapExt->LowerDeviceObject, irp);
  339. if (status == STATUS_PENDING) {
  340. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  341. status = iostatus.Status;
  342. }
  343. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapResetDevice (0x%x)\n", status));
  344. return status;
  345. }
  346. /*
  347. ********************************************************************************
  348. * UsbWrapErrorHandlerWorkRoutine
  349. ********************************************************************************
  350. *
  351. *
  352. */
  353. VOID
  354. UsbWrapErrorHandlerWorkRoutine (
  355. IN PDEVICE_OBJECT DeviceObject,
  356. IN PVOID Context)
  357. {
  358. PUSB_WRAPPER_EXTENSION wrapExt = ((PUSB_WRAPPER_WORKITEM_CONTEXT) Context)->WrapExtension;
  359. PIO_WORKITEM workItem = ((PUSB_WRAPPER_WORKITEM_CONTEXT) Context)->WorkItem;
  360. PUSB_WRAPPER_PINGPONG pingPong = ((PUSB_WRAPPER_WORKITEM_CONTEXT) Context)->PingPong;
  361. NTSTATUS status;
  362. BOOLEAN errorHandled = FALSE;
  363. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapErrorHandlerWorkRoutine\n"));
  364. status = IoAcquireRemoveLockEx(wrapExt->RemoveLock,
  365. DeviceObject,
  366. __FILE__,
  367. __LINE__,
  368. wrapExt->RemLockSize);
  369. if (!NT_SUCCESS(status)) {
  370. DBGPRINT(DBG_USBUTIL_ERROR, ("UsbWrapErrorHandlerWorkRoutine: exiting due to removal\n"));
  371. goto ErrorWorkItemComplete;
  372. }
  373. // Lets first stop all ping pongs.
  374. UsbWrapCancelAllPingPongIrps(wrapExt);
  375. //
  376. // Notify Client of the error and give them a chance to handle it
  377. //
  378. if (wrapExt->IntReadWrap.NotificationTypes & USBWRAP_NOTIFICATION_READ_ERROR) {
  379. status = (wrapExt->IntReadWrap.ClientCallback)(wrapExt->IntReadWrap.ClientContext,
  380. &pingPong->irp->IoStatus.Status,
  381. sizeof(NTSTATUS),
  382. USBWRAP_NOTIFICATION_READ_ERROR,
  383. &errorHandled);
  384. }
  385. if(!errorHandled) {
  386. // The client didn't handle it, lets try to fix it ourselves by resetting the pipe
  387. ULONG retryCount;
  388. // Try the reset up to 3 times
  389. //
  390. for (retryCount = 0; retryCount < 3; retryCount++)
  391. {
  392. //
  393. // First figure out if the device is still connected.
  394. //
  395. status = UsbWrapIsDeviceConnected(wrapExt);
  396. if (!NT_SUCCESS(status))
  397. {
  398. // Give up if the device is no longer connected.
  399. break;
  400. }
  401. //
  402. // The device is still connected, now reset the device.
  403. //
  404. status = UsbWrapResetDevice(wrapExt);
  405. if (NT_SUCCESS(status)) {
  406. // reset was successful
  407. break;
  408. }
  409. }
  410. InterlockedExchange(&wrapExt->IntReadWrap.HandlingError, 0);
  411. if (NT_SUCCESS(status) && pingPong->irp->IoStatus.Status != STATUS_DEVICE_NOT_CONNECTED) {
  412. UsbWrapStartAllPingPongs(wrapExt);
  413. }
  414. }
  415. IoReleaseRemoveLockEx(wrapExt->RemoveLock,
  416. DeviceObject,
  417. wrapExt->RemLockSize);
  418. ErrorWorkItemComplete:
  419. FREE_MEM(Context);
  420. IoFreeWorkItem(workItem);
  421. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapErrorHandlerWorkRoutine\n"));
  422. }
  423. /*
  424. ********************************************************************************
  425. * UsbWrapWorkRoutine
  426. ********************************************************************************
  427. *
  428. *
  429. */
  430. VOID
  431. UsbWrapWorkRoutine (
  432. IN PDEVICE_OBJECT DeviceObject,
  433. IN PVOID Context)
  434. {
  435. BOOLEAN QueueData = FALSE;
  436. PVOID buffer;
  437. ULONG dataLength;
  438. NTSTATUS status;
  439. PUSB_WRAPPER_EXTENSION wrapExtension = ((PUSB_WRAPPER_WORKITEM_CONTEXT) Context)->WrapExtension;
  440. PIO_WORKITEM workItem = ((PUSB_WRAPPER_WORKITEM_CONTEXT) Context)->WorkItem;
  441. KIRQL irql;
  442. __try
  443. {
  444. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapWorkRoutine\n"));
  445. KeAcquireSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  446. &irql);
  447. if(wrapExtension->IntReadWrap.PumpState == PUMP_STOPPED) {
  448. wrapExtension->IntReadWrap.WorkItemRunning--;
  449. ASSERT(wrapExtension->IntReadWrap.WorkItemRunning == 0);
  450. KeReleaseSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  451. irql);
  452. __leave;
  453. }
  454. while(!IsListEmpty(&wrapExtension->IntReadWrap.IncomingQueue)) {
  455. UsbWrapDequeueData(wrapExtension,
  456. &buffer,
  457. &dataLength,
  458. &wrapExtension->IntReadWrap.IncomingQueue);
  459. if (!buffer) {
  460. wrapExtension->IntReadWrap.WorkItemRunning--;
  461. ASSERT(wrapExtension->IntReadWrap.WorkItemRunning == 0);
  462. }
  463. KeReleaseSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  464. irql);
  465. DBGPRINT(DBG_USBUTIL_OTHER_ERROR, (" Dequeued Data buffer: 0x%x\n", buffer));
  466. if(!buffer) {
  467. //
  468. // This data had better be there!!!
  469. //
  470. __leave;
  471. }
  472. status = (wrapExtension->IntReadWrap.ClientCallback)(wrapExtension->IntReadWrap.ClientContext,
  473. buffer,
  474. dataLength,
  475. USBWRAP_NOTIFICATION_READ_COMPLETE,
  476. &QueueData);
  477. if(QueueData) {
  478. UsbWrapEnqueueData(wrapExtension,
  479. buffer,
  480. dataLength,
  481. &wrapExtension->IntReadWrap.SavedQueue);
  482. } else {
  483. if (!(wrapExtension->IntReadWrap.NotificationTypes & USBWRAP_NOTIFICATION_BUFFER_CLIENT_FREE)) {
  484. UsbWrapFreeTransferBuffer(wrapExtension,
  485. buffer);
  486. }
  487. }
  488. KeAcquireSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  489. &irql);
  490. }
  491. wrapExtension->IntReadWrap.WorkItemRunning--;
  492. KeReleaseSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  493. irql);
  494. }
  495. __finally
  496. {
  497. if (workItem) {
  498. IoFreeWorkItem(workItem);
  499. // only want to free the context if this was actually executed in a
  500. // Worker thread. If it was called directly, then this was allocated
  501. // on the stack.
  502. FREE_MEM(Context);
  503. }
  504. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapWorkRoutine\n"));
  505. }
  506. }
  507. /*
  508. ********************************************************************************
  509. * GetPingPongFromIrp
  510. ********************************************************************************
  511. *
  512. *
  513. */
  514. USB_WRAPPER_PINGPONG *GetPingPongFromIrp(
  515. PUSB_WRAPPER_EXTENSION WrapExt,
  516. PIRP irp)
  517. {
  518. USB_WRAPPER_PINGPONG *pingPong = NULL;
  519. ULONG i;
  520. for (i = 0; i < WrapExt->IntReadWrap.NumPingPongs; i++){
  521. if (WrapExt->IntReadWrap.PingPongs[i].irp == irp){
  522. pingPong = &WrapExt->IntReadWrap.PingPongs[i];
  523. break;
  524. }
  525. }
  526. ASSERT(pingPong);
  527. return pingPong;
  528. }
  529. /*
  530. ********************************************************************************
  531. * UsbWrapInterruptReadComplete
  532. ********************************************************************************
  533. *
  534. *
  535. */
  536. NTSTATUS UsbWrapInterruptReadComplete(
  537. IN PDEVICE_OBJECT DeviceObject,
  538. IN PIRP Irp,
  539. IN PVOID Context
  540. )
  541. {
  542. PUSB_WRAPPER_EXTENSION wrapExtension = (PUSB_WRAPPER_EXTENSION)Context;
  543. PUSB_WRAPPER_PINGPONG pingPong;
  544. KIRQL oldIrql;
  545. BOOLEAN startRead;
  546. BOOLEAN errorHandled = FALSE;
  547. BOOLEAN startWorkItem = FALSE;
  548. NTSTATUS status;
  549. BOOLEAN resend = TRUE;
  550. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapInterruptReadComplete %p\n", Irp));
  551. //
  552. // Track the number of outstanding requests to this device.
  553. //
  554. ASSERT(wrapExtension->IntReadWrap.OutstandingRequests > 0 );
  555. InterlockedDecrement(&wrapExtension->IntReadWrap.OutstandingRequests);
  556. DeviceObject = wrapExtension->DeviceObject;
  557. pingPong = GetPingPongFromIrp(wrapExtension, Irp);
  558. ASSERT(DeviceObject);
  559. if (!pingPong) {
  560. //
  561. // Something is terribly wrong, but do nothing. Hopefully
  562. // just exiting will clear up this pimple.
  563. //
  564. DBGPRINT(DBG_USBUTIL_ERROR,("A pingPong structure could not be found!!! Have this looked at!"))
  565. goto InterruptReadCompleteExit;
  566. }
  567. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  568. if (wrapExtension->IntReadWrap.NotificationTypes & (USBWRAP_NOTIFICATION_READ_COMPLETE | USBWRAP_NOTIFICATION_READ_COMPLETE_DIRECT)) {
  569. PIO_WORKITEM workItem;
  570. PUSB_WRAPPER_WORKITEM_CONTEXT workItemContext;
  571. ULONG count;
  572. UsbWrapEnqueueData(wrapExtension,
  573. pingPong->urb->UrbBulkOrInterruptTransfer.TransferBuffer,
  574. pingPong->urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
  575. &wrapExtension->IntReadWrap.IncomingQueue);
  576. count = pingPong->urb->UrbBulkOrInterruptTransfer.TransferFlags;
  577. DBGPRINT(DBG_USBUTIL_OTHER_ERROR,
  578. ("UsbWrapEnqueueData, %p buffer: 0x%x\n", pingPong,
  579. pingPong->urb->UrbBulkOrInterruptTransfer.TransferBuffer));
  580. wrapExtension->IntReadWrap.TransferCount = count;
  581. pingPong->urb->UrbBulkOrInterruptTransfer.TransferBuffer = NULL;
  582. KeAcquireSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  583. &oldIrql);
  584. if (wrapExtension->IntReadWrap.WorkItemRunning) {
  585. startWorkItem = FALSE;
  586. } else {
  587. startWorkItem = TRUE;
  588. wrapExtension->IntReadWrap.WorkItemRunning++;
  589. }
  590. KeReleaseSpinLock(&wrapExtension->IntReadWrap.QueueLock,
  591. oldIrql);
  592. if (startWorkItem) {
  593. if (wrapExtension->IntReadWrap.NotificationTypes & USBWRAP_NOTIFICATION_READ_COMPLETE_DIRECT) {
  594. USB_WRAPPER_WORKITEM_CONTEXT context;
  595. context.WorkItem = NULL;
  596. context.WrapExtension = wrapExtension;
  597. UsbWrapWorkRoutine(DeviceObject,
  598. &context);
  599. } else {
  600. workItem = IoAllocateWorkItem(DeviceObject);
  601. if (!workItem) {
  602. //
  603. // Insufficient Resources
  604. //
  605. goto InterruptReadCompleteExit;
  606. }
  607. workItemContext = ALLOC_MEM(NonPagedPool, sizeof(USB_WRAPPER_WORKITEM_CONTEXT), USBWRAP_TAG);
  608. if (!workItemContext) {
  609. //
  610. // Insufficient Resources;
  611. //
  612. goto InterruptReadCompleteExit;
  613. }
  614. workItemContext->WorkItem = workItem;
  615. workItemContext->WrapExtension = wrapExtension;
  616. //
  617. // Queue work item to notify the client
  618. //
  619. IoQueueWorkItem(workItem,
  620. UsbWrapWorkRoutine,
  621. CriticalWorkQueue,
  622. workItemContext);
  623. }
  624. }
  625. } else {
  626. //
  627. // Client doesn't want notification, so queue data in saved queue
  628. // so it can be read when the client is ready
  629. //
  630. UsbWrapEnqueueData(wrapExtension,
  631. pingPong->urb->UrbBulkOrInterruptTransfer.TransferBuffer,
  632. pingPong->urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
  633. &wrapExtension->IntReadWrap.SavedQueue);
  634. }
  635. } else {
  636. DBGPRINT(DBG_USBUTIL_ERROR,("irp failed buffer: 0x%x\n",pingPong->urb->UrbBulkOrInterruptTransfer.TransferBuffer ))
  637. UsbWrapFreeTransferBuffer(wrapExtension, pingPong->urb->UrbBulkOrInterruptTransfer.TransferBuffer);
  638. if ((!pingPong->weAreCancelling)) {
  639. //
  640. // The Irp failed.
  641. //
  642. ULONG i;
  643. PIO_WORKITEM workItem;
  644. PUSB_WRAPPER_WORKITEM_CONTEXT workItemContext;
  645. DBGPRINT(DBG_USBUTIL_ERROR,("A pingpong irp (0x%x) failed : 0x%x\n",pingPong,Irp->IoStatus.Status ))
  646. //
  647. // First we must stop all Ping Pongs
  648. //
  649. KeSetEvent (&pingPong->sentEvent, 0, FALSE);
  650. KeSetEvent(&pingPong->pumpDoneEvent, 0, FALSE);
  651. // resend = FALSE;
  652. if ((Irp->IoStatus.Status != STATUS_DEVICE_NOT_CONNECTED)
  653. && (!InterlockedCompareExchange(&wrapExtension->IntReadWrap.HandlingError, 1, 0))) {
  654. // Queue a workitem to actually handle the error
  655. workItem = IoAllocateWorkItem(DeviceObject);
  656. if (!workItem) {
  657. //
  658. // Insufficient Resources
  659. //
  660. goto InterruptReadCompleteExit;
  661. }
  662. workItemContext = ALLOC_MEM(NonPagedPool, sizeof(USB_WRAPPER_WORKITEM_CONTEXT), USBWRAP_TAG);
  663. if (!workItemContext) {
  664. //
  665. // Insufficient Resources;
  666. //
  667. goto InterruptReadCompleteExit;
  668. }
  669. workItemContext->WorkItem = workItem;
  670. workItemContext->WrapExtension = wrapExtension;
  671. workItemContext->PingPong = pingPong;
  672. IoQueueWorkItem(workItem,
  673. UsbWrapErrorHandlerWorkRoutine,
  674. CriticalWorkQueue,
  675. workItemContext);
  676. }
  677. }
  678. }
  679. //
  680. // If ReadInterlock is == START_READ, this func has been completed
  681. // synchronously. Place IMMEDIATE_READ into the interlock to signify this
  682. // situation; this will notify StartRead to loop when IoCallDriver returns.
  683. // Otherwise, we have been completed async and it is safe to call StartRead()
  684. //
  685. startRead =
  686. (PINGPONG_START_READ !=
  687. InterlockedCompareExchange(&pingPong->ReadInterlock,
  688. PINGPONG_IMMEDIATE_READ,
  689. PINGPONG_START_READ));
  690. //
  691. // Business as usual.
  692. //
  693. if (startRead) {
  694. if (pingPong->weAreCancelling){
  695. // We are stopping the read pump.
  696. // Set this event and stop resending the pingpong IRP.
  697. DBGPRINT(DBG_USBUTIL_TRACE, ("We are cancelling bit set for pingpong %x\n", pingPong))
  698. // InterlockedDecrement(&pingPong->weAreCancelling);
  699. KeSetEvent(&pingPong->pumpDoneEvent, 0, FALSE);
  700. } else {
  701. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  702. BOOLEAN irpSent;
  703. DBGPRINT(DBG_USBUTIL_TRACE, ("Submitting pingpong %x from completion routine\n", pingPong))
  704. UsbWrapSubmitInterruptRead(wrapExtension, pingPong, &irpSent);
  705. }
  706. }
  707. }
  708. InterruptReadCompleteExit:
  709. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapInterruptReadComplete\n"));
  710. /*
  711. * ALWAYS return STATUS_MORE_PROCESSING_REQUIRED;
  712. * otherwise, the irp is required to have a thread.
  713. */
  714. return STATUS_MORE_PROCESSING_REQUIRED;
  715. }
  716. /*
  717. ********************************************************************************
  718. * UsbWrapStartAllPingPongs
  719. ********************************************************************************
  720. *
  721. *
  722. */
  723. NTSTATUS UsbWrapStartAllPingPongs(PUSB_WRAPPER_EXTENSION WrapExt)
  724. {
  725. NTSTATUS status = STATUS_SUCCESS;
  726. ULONG i;
  727. PAGED_CODE();
  728. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapStartAllPingPongs\n"));
  729. ASSERT(WrapExt->IntReadWrap.NumPingPongs > 0);
  730. InterlockedExchange(&WrapExt->IntReadWrap.PumpState,
  731. PUMP_STARTED);
  732. for (i = 0; i < WrapExt->IntReadWrap.NumPingPongs; i++){
  733. BOOLEAN irpSent;
  734. // Different threads may be trying to start this pump at the
  735. // same time due to idle notification. Must only start once.
  736. if (WrapExt->IntReadWrap.PingPongs[i].pumpDoneEvent.Header.SignalState) {
  737. WrapExt->IntReadWrap.PingPongs[i].ReadInterlock = PINGPONG_END_READ;
  738. KeResetEvent(&WrapExt->IntReadWrap.PingPongs[i].pumpDoneEvent);
  739. DBGPRINT(DBG_USBUTIL_TRACE, ("Starting pingpong %x from UsbWrapStartAllPingPongs\n", &WrapExt->IntReadWrap.PingPongs[i]))
  740. status = UsbWrapSubmitInterruptRead(WrapExt, &WrapExt->IntReadWrap.PingPongs[i], &irpSent);
  741. if (!NT_SUCCESS(status)){
  742. if (irpSent){
  743. DBGPRINT(DBG_USBUTIL_USB_ERROR,("Initial read failed with status %xh.", status))
  744. status = STATUS_SUCCESS;
  745. } else {
  746. DBGPRINT(DBG_USBUTIL_USB_ERROR,("Initial read failed, irp not sent, status = %xh.", status))
  747. break;
  748. }
  749. }
  750. }
  751. }
  752. if (status == STATUS_PENDING){
  753. status = STATUS_SUCCESS;
  754. }
  755. if(!NT_SUCCESS(status)) {
  756. InterlockedExchange(&WrapExt->IntReadWrap.PumpState,
  757. PUMP_STOPPED);
  758. }
  759. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapStartAllPingPongs (0x%x)\n", status));
  760. return status;
  761. }
  762. /*
  763. ********************************************************************************
  764. * UsbWrapCancelAllPingPongIrps
  765. ********************************************************************************
  766. *
  767. *
  768. */
  769. VOID UsbWrapCancelAllPingPongIrps(PUSB_WRAPPER_EXTENSION WrapExt)
  770. {
  771. ULONG i;
  772. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapCancelAllPingPongIrpss\n"));
  773. for (i = 0; i < WrapExt->IntReadWrap.NumPingPongs; i++){
  774. USB_WRAPPER_PINGPONG *pingPong = &WrapExt->IntReadWrap.PingPongs[i];
  775. UsbWrapCancelPingPongIrp(pingPong);
  776. }
  777. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapCancelAllPingPongIrps\n"));
  778. }
  779. /*
  780. ********************************************************************************
  781. * UsbWrapCancelPingPongIrp
  782. ********************************************************************************
  783. *
  784. *
  785. */
  786. VOID UsbWrapCancelPingPongIrp(USB_WRAPPER_PINGPONG *PingPong)
  787. {
  788. DBGPRINT(DBG_USBUTIL_TRACE, ("Cancelling pingpong %x\n", PingPong))
  789. ASSERT(PingPong->sig == PINGPONG_SIG);
  790. //
  791. // The order of the following instructions is crucial. We must set
  792. // the weAreCancelling bit before waiting on the sentEvent, and the
  793. // last thing that we should wait on is the pumpDoneEvent, which
  794. // indicates that the read loop has finished all reads and will never
  795. // run again.
  796. //
  797. InterlockedIncrement(&PingPong->weAreCancelling);
  798. /*
  799. * Synchronize with the irp's completion routine.
  800. */
  801. KeWaitForSingleObject(&PingPong->sentEvent,
  802. Executive, // wait reason
  803. KernelMode,
  804. FALSE, // not alertable
  805. NULL ); // no timeout
  806. DBGPRINT(DBG_USBUTIL_TRACE, ("Pingpong sent event set for pingpong %x\n", PingPong))
  807. IoCancelIrp(PingPong->irp);
  808. /*
  809. * Cancelling the IRP causes a lower driver to
  810. * complete it (either in a cancel routine or when
  811. * the driver checks Irp->Cancel just before queueing it).
  812. * Wait for the IRP to actually get cancelled.
  813. */
  814. KeWaitForSingleObject( &PingPong->pumpDoneEvent,
  815. Executive, // wait reason
  816. KernelMode,
  817. FALSE, // not alertable
  818. NULL ); // no timeout
  819. // // Now clear the cancelling flag so the pingpong could be resent.
  820. InterlockedDecrement(&PingPong->weAreCancelling);
  821. DBGPRINT(DBG_USBUTIL_TRACE, ("Pingpong pump done event set for %x\n", PingPong))
  822. }
  823. /*
  824. ********************************************************************************
  825. * UsbWrapDestroyPingPongs
  826. ********************************************************************************
  827. *
  828. *
  829. */
  830. VOID UsbWrapDestroyPingPongs(PUSB_WRAPPER_EXTENSION WrapExt)
  831. {
  832. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapDestroyPingPongs\n"));
  833. if (WrapExt && WrapExt->IntReadWrap.PingPongs){
  834. ULONG i;
  835. UsbWrapCancelAllPingPongIrps(WrapExt);
  836. for (i = 0; i < WrapExt->IntReadWrap.NumPingPongs; i++){
  837. if (WrapExt->IntReadWrap.PingPongs[i].urb) {
  838. ExFreePool(WrapExt->IntReadWrap.PingPongs[i].urb);
  839. WrapExt->IntReadWrap.PingPongs[i].urb = NULL;
  840. }
  841. if (WrapExt->IntReadWrap.PingPongs[i].irp) {
  842. IoFreeIrp(WrapExt->IntReadWrap.PingPongs[i].irp);
  843. }
  844. }
  845. ExFreePool(WrapExt->IntReadWrap.PingPongs);
  846. WrapExt->IntReadWrap.PingPongs = NULL;
  847. }
  848. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapDestroyPingPongs\n"));
  849. }
  850. /*
  851. ********************************************************************************
  852. * UsbWrapEnqueueData
  853. ********************************************************************************
  854. *
  855. *
  856. */
  857. VOID UsbWrapEnqueueData(
  858. IN PUSB_WRAPPER_EXTENSION WrapExt,
  859. IN PVOID Data,
  860. IN ULONG DataLength,
  861. IN PLIST_ENTRY Queue
  862. )
  863. {
  864. PUSB_WRAPPER_DATA_BLOCK dataBlock;
  865. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapEnqueueData\n"));
  866. dataBlock = ALLOC_MEM(NonPagedPool, sizeof(USB_WRAPPER_DATA_BLOCK), USBWRAP_TAG);
  867. if (!dataBlock) {
  868. //
  869. // D'oh, out of resources
  870. //
  871. DBGPRINT(DBG_USBUTIL_ERROR, ("UsbWrapEnqueueData: Failed to allocate dataBlock\n"));
  872. // Make sure that we don't leak this memory
  873. if (Data) {
  874. FREE_MEM(Data);
  875. }
  876. return;
  877. }
  878. dataBlock->Buffer = Data;
  879. dataBlock->DataLen = DataLength;
  880. ExInterlockedInsertTailList(
  881. Queue,
  882. (PLIST_ENTRY) dataBlock,
  883. &WrapExt->IntReadWrap.QueueLock);
  884. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapEnqueueData\n"));
  885. }
  886. /*
  887. ********************************************************************************
  888. * UsbWrapDequeueData
  889. ********************************************************************************
  890. *
  891. *
  892. */
  893. VOID UsbWrapDequeueData(
  894. IN PUSB_WRAPPER_EXTENSION WrapExt,
  895. OUT PVOID *Data,
  896. OUT ULONG *DataLength,
  897. IN PLIST_ENTRY Queue
  898. )
  899. {
  900. PUSB_WRAPPER_DATA_BLOCK dataBlock;
  901. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapDequeueData\n"));
  902. dataBlock = (PUSB_WRAPPER_DATA_BLOCK) RemoveHeadList(Queue);
  903. if(!dataBlock) {
  904. *Data = NULL;
  905. *DataLength = 0;
  906. } else {
  907. *Data = dataBlock->Buffer;
  908. *DataLength = dataBlock->DataLen;
  909. }
  910. FREE_MEM(dataBlock);
  911. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapDequeueData\n"));
  912. }
  913. /*
  914. ********************************************************************************
  915. * UsbWrapGetTransferBuffer
  916. ********************************************************************************
  917. *
  918. *
  919. */
  920. PVOID UsbWrapGetTransferBuffer(
  921. IN PUSB_WRAPPER_EXTENSION WrapExt
  922. )
  923. {
  924. PVOID buffer;
  925. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapGetTransferBuffer\n"));
  926. buffer = ALLOC_MEM(NonPagedPool, WrapExt->IntReadWrap.MaxTransferSize, USBWRAP_TAG);
  927. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapGetTransferBuffer\n"));
  928. return buffer;
  929. }
  930. /*
  931. ********************************************************************************
  932. * UsbWrapFreeTransferBuffer
  933. ********************************************************************************
  934. *
  935. *
  936. */
  937. VOID UsbWrapFreeTransferBuffer(
  938. IN PUSB_WRAPPER_EXTENSION WrapExt,
  939. PVOID Buffer
  940. )
  941. {
  942. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Enter: UsbWrapFreeTransferBuffer\n"));
  943. if (Buffer != NULL) {
  944. FREE_MEM(Buffer);
  945. }
  946. DBGPRINT(DBG_USBUTIL_ENTRY_EXIT, ("Exit: UsbWrapFreeTransferBuffer\n"));
  947. }
  948. /*
  949. ********************************************************************************
  950. * UsbWrapReadData
  951. ********************************************************************************
  952. *
  953. *
  954. */
  955. NTSTATUS UsbWrapReadData(
  956. IN PUSB_WRAPPER_EXTENSION WrapExt,
  957. IN PVOID Buffer,
  958. IN ULONG *BufferLength
  959. )
  960. {
  961. NTSTATUS status = STATUS_SUCCESS;
  962. PUSB_WRAPPER_DATA_BLOCK dataBlock;
  963. KIRQL oldIrql;
  964. ULONG bytesCoppied;
  965. __try{
  966. KeAcquireSpinLock(&WrapExt->IntReadWrap.QueueLock,
  967. &oldIrql);
  968. if(IsListEmpty(&WrapExt->IntReadWrap.SavedQueue)) {
  969. bytesCoppied = 0;
  970. status = STATUS_SUCCESS;
  971. __leave;
  972. }
  973. dataBlock = (PUSB_WRAPPER_DATA_BLOCK) WrapExt->IntReadWrap.SavedQueue.Flink;
  974. if(dataBlock->DataLen > *BufferLength) {
  975. status = STATUS_INVALID_PARAMETER;
  976. bytesCoppied = dataBlock->DataLen;
  977. __leave;
  978. }
  979. RemoveHeadList(&WrapExt->IntReadWrap.SavedQueue);
  980. bytesCoppied = 0;
  981. while(TRUE) {
  982. RtlCopyMemory(Buffer,
  983. dataBlock->Buffer,
  984. dataBlock->DataLen);
  985. bytesCoppied += dataBlock->DataLen;
  986. *BufferLength -= dataBlock->DataLen;
  987. (UCHAR*) Buffer += dataBlock->DataLen;
  988. FREE_MEM(dataBlock->Buffer);
  989. if(dataBlock->DataLen < WrapExt->IntReadWrap.MaxTransferSize) {
  990. // Found the end of the data
  991. FREE_MEM(dataBlock);
  992. __leave;
  993. }
  994. FREE_MEM(dataBlock);
  995. if(IsListEmpty(&WrapExt->IntReadWrap.SavedQueue)) {
  996. __leave;
  997. }
  998. dataBlock = (PUSB_WRAPPER_DATA_BLOCK) WrapExt->IntReadWrap.SavedQueue.Flink;
  999. if(dataBlock->DataLen > *BufferLength) {
  1000. // Not enough buffer left for this transfer
  1001. __leave;
  1002. }
  1003. RemoveHeadList(&WrapExt->IntReadWrap.SavedQueue);
  1004. }
  1005. } __finally {
  1006. *BufferLength = bytesCoppied;
  1007. KeReleaseSpinLock(&WrapExt->IntReadWrap.QueueLock,
  1008. oldIrql);
  1009. }
  1010. return status;
  1011. }
  1012. VOID
  1013. UsbWrapEmptyQueue(PUSB_WRAPPER_EXTENSION WrapExt,
  1014. PLIST_ENTRY Queue)
  1015. {
  1016. __try
  1017. {
  1018. PUSB_WRAPPER_DATA_BLOCK dataBlock;
  1019. if (!WrapExt) {
  1020. __leave;
  1021. }
  1022. while (!IsListEmpty(Queue)) {
  1023. dataBlock =
  1024. (PUSB_WRAPPER_DATA_BLOCK) ExInterlockedRemoveHeadList(Queue,
  1025. &WrapExt->IntReadWrap.QueueLock);
  1026. FREE_MEM(dataBlock->Buffer);
  1027. FREE_MEM(dataBlock);
  1028. }
  1029. }
  1030. __finally
  1031. {
  1032. }
  1033. }