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.

1051 lines
32 KiB

  1. /* ++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. USBIO.C
  5. Abstract:
  6. USB I/O functions
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. 07-14-99 : created
  11. Authors:
  12. Jeff Midkiff (jeffmi)
  13. -- */
  14. #include <wdm.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <usbdi.h>
  18. #include <usbdlib.h>
  19. #include <ntddser.h>
  20. #include "wceusbsh.h"
  21. NTSTATUS
  22. UsbSubmitSyncUrbCompletion(
  23. IN PDEVICE_OBJECT PDevObj,
  24. IN PIRP PIrp,
  25. IN PKEVENT PSyncEvent
  26. )
  27. /*++
  28. Routine Description:
  29. Arguments:
  30. PDevObj - Pointer to Device Object
  31. PIrp - Pointer to IRP that is being completed
  32. PSyncEvent - Pointer to event that we should set
  33. Return Value:
  34. STATUS_MORE_PROCESSING_REQUIRED
  35. --*/
  36. {
  37. UNREFERENCED_PARAMETER( PDevObj );
  38. UNREFERENCED_PARAMETER( PIrp );
  39. DbgDump(DBG_USB, (">UsbSubmitSyncUrbCompletion (%p)\n", PIrp) );
  40. ASSERT( PSyncEvent );
  41. KeSetEvent( PSyncEvent, IO_NO_INCREMENT, FALSE );
  42. DbgDump(DBG_USB, ("<UsbSubmitSyncUrbCompletion 0x%x\n", PIrp->IoStatus.Status ) );
  43. // our driver owns and releases the irp
  44. return STATUS_MORE_PROCESSING_REQUIRED;
  45. }
  46. NTSTATUS
  47. UsbSubmitSyncUrb(
  48. IN PDEVICE_OBJECT PDevObj,
  49. IN PURB PUrb,
  50. IN BOOLEAN Configuration,
  51. IN LONG TimeOut
  52. )
  53. /*++
  54. Routine Description:
  55. This routine issues a synchronous URB request to the USBD.
  56. Arguments:
  57. PDevObj - Ptr to our FDO
  58. PUrb - URB to pass
  59. Configuration - special case to allow USB config transactions onto the bus.
  60. We need to do this because a) if the device was removed then we can stall the controller
  61. which results in a reset kicking anything off the bus and re-enumerating the bus.
  62. b) to trap any cases of suprise removal from numerous paths
  63. TimeOut - timeout in milliseconds
  64. Note: runs at PASSIVE_LEVEL.
  65. Return Value:
  66. NTSTATUS - propogates status from USBD
  67. --*/
  68. {
  69. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  70. IO_STATUS_BLOCK ioStatus = {0, 0};
  71. PIO_STACK_LOCATION pNextIrpSp;
  72. KEVENT event;
  73. NTSTATUS status, wait_status;
  74. PIRP pIrp;
  75. PAGED_CODE();
  76. DbgDump(DBG_USB|DBG_TRACE, (">UsbSubmitSyncUrb\n") );
  77. if ( !PUrb || !pDevExt->NextDevice ) {
  78. status = STATUS_INVALID_PARAMETER;
  79. DbgDump(DBG_ERR, ("UsbSubmitSyncUrb.1: 0x%x\n", status));
  80. TEST_TRAP();
  81. return status;
  82. }
  83. if ( !Configuration && !CanAcceptIoRequests(PDevObj, TRUE, TRUE) ) {
  84. status = STATUS_DELETE_PENDING;
  85. DbgDump(DBG_ERR, ("UsbSubmitSyncUrb.2: 0x%x\n", status));
  86. return status;
  87. }
  88. // we need to grab the lock here to keep it's IoCount correct
  89. status = AcquireRemoveLock(&pDevExt->RemoveLock, PUrb);
  90. if ( !NT_SUCCESS(status) ) {
  91. DbgDump(DBG_ERR, ("UsbSubmitSyncUrb.3: 0x%x\n", status));
  92. return status;
  93. }
  94. DbgDump(DBG_USB, (">UsbSubmitSyncUrb (%p, %p)\n", PDevObj, PUrb) );
  95. pIrp = IoAllocateIrp( (CCHAR)(pDevExt->NextDevice->StackSize + 1), FALSE);
  96. if ( pIrp ) {
  97. KeInitializeEvent(&event, NotificationEvent, FALSE);
  98. RecycleIrp( PDevObj, pIrp);
  99. IoSetCompletionRoutine(pIrp,
  100. UsbSubmitSyncUrbCompletion,
  101. &event, // Context
  102. TRUE, TRUE, TRUE );
  103. pNextIrpSp = IoGetNextIrpStackLocation(pIrp);
  104. ASSERT(pNextIrpSp);
  105. pNextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  106. pNextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  107. pNextIrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  108. pNextIrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  109. pNextIrpSp->Parameters.Others.Argument1 = PUrb;
  110. status = IoCallDriver( pDevExt->NextDevice, pIrp );
  111. if (STATUS_PENDING == status ) {
  112. //
  113. // Set a default timeout in case the hardware is flakey, so USB will not hang us.
  114. // We may want these timeouts user configurable via registry.
  115. //
  116. LARGE_INTEGER timeOut;
  117. ASSERT(TimeOut >= 0);
  118. timeOut.QuadPart = MILLISEC_TO_100NANOSEC( (TimeOut == 0 ? DEFAULT_PENDING_TIMEOUT : TimeOut) );
  119. wait_status = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, &timeOut );
  120. if (STATUS_TIMEOUT == wait_status) {
  121. //
  122. // The wait timed out, try to cancel the Irp.
  123. // N.B: if you freed the Irp in the completion routine
  124. // then you have a race condition between the completion routine freeing the Irp
  125. // and the timer firing where we need to set the cancel bit.
  126. //
  127. DbgDump(DBG_USB|DBG_WRN, ("UsbSubmitSyncUrb: STATUS_TIMEOUT\n"));
  128. if ( !IoCancelIrp(pIrp) ) {
  129. //
  130. // This means USB has the Irp in a non-canceable state.
  131. //
  132. DbgDump(DBG_ERR, ("!IoCancelIrp(%p)\n", pIrp));
  133. TEST_TRAP();
  134. }
  135. //
  136. // Wait for our completion routine, to see if the Irp completed normally or actually cancelled.
  137. // An alternative could be alloc an event & status block, stored in the Irp
  138. // strung along a list, which would also get freed in the completion routine...
  139. // which creates other problems not worth the effort for an exit condition.
  140. //
  141. wait_status = KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL );
  142. }
  143. }
  144. //
  145. // The completion routine signalled the event and completed,
  146. // and our the timer has expired. Now we can safely free the Irp.
  147. //
  148. status = pIrp->IoStatus.Status;
  149. #if DBG
  150. if (STATUS_SUCCESS != status) {
  151. DbgDump(DBG_ERR, ("UsbSubmitSyncUrb IrpStatus: 0x%x UrbStatus: 0x%x\n", status, PUrb->UrbHeader.Status) );
  152. }
  153. #endif
  154. IoFreeIrp( pIrp );
  155. } else {
  156. DbgDump(DBG_ERR, ("IoAllocateIrp failed!\n") );
  157. status = STATUS_INSUFFICIENT_RESOURCES;
  158. TEST_TRAP();
  159. }
  160. ReleaseRemoveLock(&pDevExt->RemoveLock, PUrb);
  161. DbgDump(DBG_USB|DBG_TRACE, ("<UsbSubmitSyncUrb (0x%x)\n", status) );
  162. return status;
  163. }
  164. NTSTATUS
  165. UsbClassVendorCommand(
  166. IN PDEVICE_OBJECT PDevObj,
  167. IN UCHAR Request,
  168. IN USHORT Value,
  169. IN USHORT Index,
  170. IN PVOID Buffer,
  171. IN OUT PULONG BufferLen,
  172. IN BOOLEAN Read,
  173. IN ULONG Class
  174. )
  175. /*++
  176. Routine Description:
  177. Issue class or vendor specific command
  178. Arguments:
  179. PDevObj - pointer to a your object
  180. Request - request field of class/vendor specific command
  181. Value - value field of class/vendor specific command
  182. Index - index field of class/vendor specific command
  183. Buffer - pointer to data buffer
  184. BufferLen - data buffer length
  185. Read - data direction flag
  186. Class - True if Class Command, else vendor command
  187. Return Value:
  188. NTSTATUS
  189. --*/
  190. {
  191. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  192. NTSTATUS status;
  193. PURB pUrb;
  194. ULONG ulSize;
  195. ULONG ulLength;
  196. PAGED_CODE();
  197. DbgDump(DBG_USB, (">UsbClassVendorCommand\n" ));
  198. ulLength = BufferLen ? *BufferLen : 0;
  199. ulSize = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
  200. pUrb = ExAllocateFromNPagedLookasideList( &pDevExt->VendorRequestUrbPool );
  201. if (pUrb) {
  202. UsbBuildVendorRequest( pUrb,
  203. Class == WCEUSB_CLASS_COMMAND ? URB_FUNCTION_CLASS_INTERFACE : URB_FUNCTION_VENDOR_DEVICE,
  204. (USHORT)ulSize,
  205. Read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT,
  206. 0,
  207. Request,
  208. Value,
  209. Index,
  210. Buffer,
  211. NULL,
  212. ulLength,
  213. NULL);
  214. status = UsbSubmitSyncUrb(PDevObj, pUrb, FALSE, DEFAULT_CTRL_TIMEOUT);
  215. if (BufferLen)
  216. *BufferLen = pUrb->UrbControlVendorClassRequest.TransferBufferLength;
  217. ExFreeToNPagedLookasideList( &pDevExt->VendorRequestUrbPool, pUrb );
  218. } else {
  219. status = STATUS_INSUFFICIENT_RESOURCES;
  220. DbgDump(DBG_ERR, ("ExAllocatePool error: 0x%x\n", status));
  221. TEST_TRAP();
  222. }
  223. DbgDump(DBG_USB, ("<UsbClassVendorCommand (0x%x)\n", status));
  224. return status;
  225. }
  226. /////////////////////////////////////////////////////////////////////////
  227. //
  228. // Usb Read / Write Utils
  229. //
  230. NTSTATUS
  231. UsbReadWritePacket(
  232. IN PDEVICE_EXTENSION PDevExt,
  233. IN PIRP PIrp,
  234. IN PIO_COMPLETION_ROUTINE CompletionRoutine,
  235. IN LARGE_INTEGER TimeOut,
  236. IN PKDEFERRED_ROUTINE TimeoutRoutine,
  237. IN BOOLEAN Read
  238. )
  239. /*++
  240. Routine Description:
  241. This function allocates and passes a Bulk Transfer URB Request
  242. down to USBD to perform a Read/Write. Note that the Packet
  243. MUST freed (put back on the packet list) in the
  244. CompletionRoutine.
  245. Arguments:
  246. PDevExt - Pointer to device extension
  247. PIrp - Read/Write IRP
  248. CompletionRoutine - completion routine to set in the Irp
  249. TimeOut - Timeout value for packet. If no timeout is
  250. specified the we use a default timeout.
  251. Read - TRUE for Read, else Write
  252. Return Value:
  253. NTSTATUS
  254. Notes:
  255. This is not currently documented in the DDK, so here 's what
  256. happens:
  257. We pass the Irp to USBD. USBD parameter checks the Irp.
  258. If any parameters are invalid then USBD returns an NT status code
  259. and Urb status code, then the Irp goes to our completion routine.
  260. If there are no errors then USBD passes Irp to HCD. HCD queues the
  261. Irp to it's StartIo & and returns STATUS_PENDING. When HCD finishes
  262. the (DMA) transfer it completes the Irp, setting the Irp & Urb status
  263. fields. USBD's completion routine gets the Irp, translates any HCD
  264. error codes, completes it, which percolates it back up to our
  265. completion routine.
  266. Note: HCD uses DMA & therefore MDLs. Since this client driver
  267. currently uses METHOD_BUFFERED, then USBD allocates an MDL for
  268. HCD. So you have the I/O manager double bufffering the data
  269. and USBD mapping MDLs. What the hell, we have to buffer user reads
  270. too... uggh. Note that if you change to method direct then
  271. the read path gets nastier.
  272. Note: when the user submits a write buffer > MaxTransferSize
  273. then we reject the buffer.
  274. --*/
  275. {
  276. PIO_STACK_LOCATION pIrpSp;
  277. PUSB_PACKET pPacket;
  278. NTSTATUS status;
  279. KIRQL irql; //, cancelIrql;
  280. PURB pUrb;
  281. PVOID pvBuffer;
  282. ULONG ulLength;
  283. USBD_PIPE_HANDLE hPipe;
  284. PERF_ENTRY( PERF_UsbReadWritePacket );
  285. DbgDump(DBG_USB, (">UsbReadWritePacket (%p, %p, %d, %d)\n", PDevExt->DeviceObject, PIrp, TimeOut.QuadPart/10000, Read));
  286. if ( !PDevExt || !PIrp || !CompletionRoutine ) {
  287. status = PIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  288. DbgDump(DBG_ERR, ("<UsbReadWritePacket 0x%x\n", status));
  289. KeAcquireSpinLock( &PDevExt->ControlLock, &irql );
  290. TryToCompleteCurrentIrp(
  291. PDevExt,
  292. status,
  293. &PIrp,
  294. NULL, // Queue
  295. NULL, // IntervalTimer
  296. NULL, // PTotalTimer
  297. NULL, // Starter
  298. NULL, // PGetNextIrp
  299. IRP_REF_RX_BUFFER, // RefType
  300. (BOOLEAN)(!Read),
  301. irql ); // Complete
  302. PERF_EXIT( PERF_UsbReadWritePacket );
  303. TEST_TRAP();
  304. return status;
  305. }
  306. IRP_SET_REFERENCE(PIrp, IRP_REF_RX_BUFFER);
  307. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  308. ASSERT( pIrpSp );
  309. //
  310. // Allocate & Build a USB Bulk Transfer Request (Packet)
  311. //
  312. pPacket = ExAllocateFromNPagedLookasideList( &PDevExt->PacketPool );
  313. if ( !pPacket ) {
  314. status = PIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  315. DbgDump(DBG_ERR, ("<UsbReadWritePacket 0x%x\n", status));
  316. KeAcquireSpinLock( &PDevExt->ControlLock, &irql );
  317. TryToCompleteCurrentIrp(
  318. PDevExt,
  319. status,
  320. &PIrp,
  321. NULL, // Queue
  322. NULL, // IntervalTimer
  323. NULL, // PTotalTimer
  324. NULL, // Starter
  325. NULL, // PGetNextIrp
  326. IRP_REF_RX_BUFFER, // RefType
  327. (BOOLEAN)(!Read),
  328. irql );
  329. PERF_EXIT( PERF_UsbReadWritePacket );
  330. TEST_TRAP();
  331. return status;
  332. }
  333. //
  334. // init the Packet
  335. //
  336. RtlZeroMemory( pPacket, sizeof(USB_PACKET) );
  337. pPacket->DeviceExtension = PDevExt;
  338. pPacket->Irp = PIrp;
  339. pUrb = &pPacket->Urb;
  340. ASSERT( pUrb );
  341. KeAcquireSpinLock( &PDevExt->ControlLock, &irql );
  342. if (Read) {
  343. //
  344. // store the Urb for buffered reads
  345. //
  346. PDevExt->UsbReadUrb = pUrb;
  347. }
  348. //
  349. // Build the URB.
  350. // Note: HCD breaks up our buffer into Transport Descriptors (TD)
  351. // of PipeInfo->MaxPacketSize.
  352. // Q: does USBD/HCD look at the PipeInfo->MaxTransferSize to see
  353. // if he can Rx/Tx?
  354. // A: Yes. HCD will return urbStatus = USBD_STATUS_INVALID_PARAMETER
  355. // and status = STATUS_INVALID_PARAMETER of too large.
  356. //
  357. ASSERT( Read ? (PDevExt->UsbReadBuffSize <= PDevExt->MaximumTransferSize ) :
  358. (pIrpSp->Parameters.Write.Length <= PDevExt->MaximumTransferSize ) );
  359. //
  360. // Note: Reads are done into our local USB read buffer,
  361. // and then copied into the user's buffer on completion.
  362. // Writes are done directly from user's buffer.
  363. // We allow NULL writes to indicate end of a USB transaction.
  364. //
  365. pvBuffer = Read ? PDevExt->UsbReadBuff :
  366. PIrp->AssociatedIrp.SystemBuffer;
  367. ulLength = Read ? PDevExt->UsbReadBuffSize :
  368. pIrpSp->Parameters.Write.Length;
  369. hPipe = Read ? PDevExt->ReadPipe.hPipe :
  370. PDevExt->WritePipe.hPipe;
  371. ASSERT( hPipe );
  372. UsbBuildTransferUrb(
  373. pUrb, // Urb
  374. pvBuffer, // Buffer
  375. ulLength, // Length
  376. hPipe, // PipeHandle
  377. Read // ReadRequest
  378. );
  379. //
  380. // put the packet on a pending list
  381. //
  382. InsertTailList( Read ? &PDevExt->PendingReadPackets : // ListHead,
  383. &PDevExt->PendingWritePackets,
  384. &pPacket->ListEntry ); // ListEntry
  385. //
  386. // Increment the pending packet counter
  387. //
  388. InterlockedIncrement( Read ? &PDevExt->PendingReadCount:
  389. &PDevExt->PendingWriteCount );
  390. //
  391. // Setup Irp for submit Urb IOCTL
  392. //
  393. IoCopyCurrentIrpStackLocationToNext(PIrp);
  394. pIrpSp = IoGetNextIrpStackLocation(PIrp);
  395. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  396. pIrpSp->Parameters.Others.Argument1 = pUrb;
  397. pIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  398. IoSetCompletionRoutine( PIrp,
  399. CompletionRoutine,
  400. pPacket, // Context
  401. TRUE, TRUE, TRUE);
  402. //
  403. // Initialize and Arm the Packet's Timer.
  404. // If the Timer fires then the packet's Timeout routine runs.
  405. //
  406. KeInitializeTimer( &pPacket->TimerObj );
  407. if ( 0 != TimeOut.QuadPart ) {
  408. pPacket->Timeout = TimeOut;
  409. ASSERT( TimeoutRoutine );
  410. pPacket->TimerDPCRoutine = TimeoutRoutine;
  411. KeInitializeDpc( &pPacket->TimerDPCObj, // DPC Object
  412. pPacket->TimerDPCRoutine, // DPC Routine
  413. pPacket ); // Context
  414. DbgDump(DBG_USB, ("Timer for Irp %p due in %d msec\n", pPacket->Irp, pPacket->Timeout.QuadPart/10000 ));
  415. KeSetTimer( &pPacket->TimerObj, // TimerObj
  416. pPacket->Timeout, // DueTime
  417. &pPacket->TimerDPCObj // DPC Obj
  418. );
  419. }
  420. //
  421. // pass the Irp to USBD
  422. //
  423. DbgDump(DBG_IRP, ("UsbReadWritePacket IoCallDriver with %p\n", PIrp));
  424. KeReleaseSpinLock( &PDevExt->ControlLock, irql );
  425. status = IoCallDriver( PDevExt->NextDevice, PIrp );
  426. if ( (STATUS_SUCCESS != status) && (STATUS_PENDING != status) ) {
  427. //
  428. // We end up here after our completion routine runs
  429. // for an error condition i.e., when we have and
  430. // invalid parameter, or when user pulls the plug, etc.
  431. //
  432. DbgDump(DBG_ERR, ("UsbReadWritePacket error: 0x%x\n", status));
  433. }
  434. DbgDump(DBG_USB , ("<UsbReadWritePacket 0x%x\n", status));
  435. PERF_EXIT( PERF_UsbReadWritePacket );
  436. return status;
  437. }
  438. //
  439. // This routine sets up a PUrb for a _URB_BULK_OR_INTERRUPT_TRANSFER.
  440. // It assumes it's called holding a SpinLock.
  441. //
  442. VOID
  443. UsbBuildTransferUrb(
  444. PURB PUrb,
  445. PUCHAR PBuffer,
  446. ULONG Length,
  447. IN USBD_PIPE_HANDLE PipeHandle,
  448. IN BOOLEAN Read
  449. )
  450. {
  451. ULONG size;
  452. ASSERT( PUrb );
  453. ASSERT( PipeHandle );
  454. size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  455. RtlZeroMemory(PUrb, size);
  456. PUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)size;
  457. PUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  458. PUrb->UrbBulkOrInterruptTransfer.Hdr.Status = USBD_STATUS_SUCCESS;
  459. PUrb->UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
  460. //
  461. // we are using a tranfsfer buffer instead of an MDL
  462. //
  463. PUrb->UrbBulkOrInterruptTransfer.TransferBuffer = PBuffer;
  464. PUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = Length;
  465. PUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  466. //
  467. // Set transfer flags
  468. //
  469. PUrb->UrbBulkOrInterruptTransfer.TransferFlags |= Read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT;
  470. //
  471. // Short transfer is not treated as an error.
  472. // If USBD_TRANSFER_DIRECTION_IN is set,
  473. // directs the HCD not to return an error if a packet is received from the device
  474. // shorter than the maximum packet size for the endpoint.
  475. // Otherwise, a short request is returns an error condition.
  476. //
  477. PUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  478. //
  479. // no linkage for now
  480. //
  481. PUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  482. return;
  483. }
  484. /////////////////////////////////////////////////////////////////////////
  485. //
  486. // Usb Reset Utils
  487. //
  488. VOID
  489. UsbResetOrAbortPipeWorkItem(
  490. IN PWCE_WORK_ITEM PWorkItem
  491. )
  492. {
  493. PDEVICE_OBJECT pDevObj = PWorkItem->DeviceObject;
  494. PDEVICE_EXTENSION pDevExt = pDevObj->DeviceExtension;
  495. UCHAR retries = 0;
  496. ULONG ulUniqueErrorValue = 0;
  497. NTSTATUS status = STATUS_DELETE_PENDING;
  498. DbgDump(DBG_WORK_ITEMS, (">UsbResetOrAbortPipeWorkItem (0x%x)\n", pDevObj));
  499. //
  500. // The work item was queued at IRQL > PASSIVE some time ago from an I/O completion routine.
  501. // If we are unsuccessful after max retries then stop taking I/O requests & assume the device is broken
  502. //
  503. if ( CanAcceptIoRequests(pDevObj, TRUE, TRUE) )
  504. {
  505. switch (PWorkItem->Flags)
  506. {
  507. case WORK_ITEM_RESET_READ_PIPE:
  508. {
  509. DbgDump(DBG_WORK_ITEMS, ("WORK_ITEM_RESET_READ_PIPE\n"));
  510. if ( pDevExt->ReadDeviceErrors < g_ulMaxPipeErrors)
  511. {
  512. //
  513. // reset read Pipe, which could fail.
  514. // E.g. flakey h/w, suprise remove, timeout, ...
  515. //
  516. status = UsbResetOrAbortPipe( pDevObj, &pDevExt->ReadPipe, RESET );
  517. switch (status)
  518. {
  519. case STATUS_SUCCESS:
  520. {
  521. //
  522. // kick start another read
  523. //
  524. status = UsbRead( pDevExt,
  525. (BOOLEAN)(pDevExt->IntPipe.hPipe ? TRUE : FALSE) );
  526. if ( (STATUS_SUCCESS == status) || (STATUS_PENDING == status) ) {
  527. //
  528. // the device recovered OK
  529. //
  530. status = STATUS_SUCCESS;
  531. } else {
  532. DbgDump(DBG_ERR, ("UsbRead error: 0x%x\n", status));
  533. }
  534. } break;
  535. case STATUS_UNSUCCESSFUL:
  536. // a previous reset/abort request failed, so this request was rejected
  537. break;
  538. case STATUS_DELETE_PENDING:
  539. // the device is going away
  540. break;
  541. case STATUS_PENDING:
  542. // there is a reset/abort request already pending
  543. break;
  544. default:
  545. {
  546. //
  547. // if we can not reset the endpoint the device is hosed or removed
  548. //
  549. DbgDump(DBG_ERR, ("UsbResetOrAbortPipeWorkItem.1 error: 0x%x\n", status ));
  550. retries = 1;
  551. ulUniqueErrorValue = ERR_NO_READ_PIPE_RESET;
  552. } break;
  553. } // status
  554. } else {
  555. status = (NTSTATUS)PtrToLong(PWorkItem->Context); // Urb status is stored here
  556. retries = (UCHAR)pDevExt->ReadDeviceErrors;
  557. ulUniqueErrorValue = ERR_MAX_READ_PIPE_DEVICE_ERRORS;
  558. }
  559. if ( USBD_STATUS_BUFFER_OVERRUN == (USBD_STATUS)PtrToLong(PWorkItem->Context)) {
  560. LogError( NULL,
  561. pDevObj,
  562. 0, 0,
  563. (UCHAR)pDevExt->ReadDeviceErrors,
  564. ERR_USB_READ_BUFF_OVERRUN,
  565. (USBD_STATUS)PtrToLong(PWorkItem->Context),
  566. SERIAL_USB_READ_BUFF_OVERRUN,
  567. pDevExt->DeviceName.Length + sizeof(WCHAR),
  568. pDevExt->DeviceName.Buffer,
  569. 0, NULL );
  570. }
  571. } // WORK_ITEM_RESET_READ_PIPE
  572. break;
  573. case WORK_ITEM_RESET_WRITE_PIPE:
  574. {
  575. DbgDump(DBG_WORK_ITEMS, ("WORK_ITEM_RESET_WRITE_PIPE\n"));
  576. if (pDevExt->WriteDeviceErrors < g_ulMaxPipeErrors)
  577. {
  578. //
  579. // reset write Pipe, which could fail.
  580. // E.g. flakey h/w, suprise remove, timeout, ...
  581. //
  582. status = UsbResetOrAbortPipe( pDevObj, &pDevExt->WritePipe, RESET );
  583. switch (status)
  584. {
  585. case STATUS_SUCCESS:
  586. // the device recovered OK
  587. break;
  588. case STATUS_UNSUCCESSFUL:
  589. // a previous reset/abort request failed, so this request was rejected
  590. break;
  591. case STATUS_DELETE_PENDING:
  592. // the device is going away
  593. break;
  594. case STATUS_PENDING:
  595. // there is a reset/abort request already pending
  596. break;
  597. default: {
  598. //
  599. // if we can not reset the endpoint the device is hosed or removed
  600. //
  601. DbgDump(DBG_ERR, ("UsbResetOrAbortPipeWorkItem.2 error: 0x%x\n", status ));
  602. retries = 1;
  603. ulUniqueErrorValue = ERR_NO_WRITE_PIPE_RESET;
  604. } break;
  605. } // status
  606. } else {
  607. status = (NTSTATUS)PtrToLong(PWorkItem->Context);
  608. retries = (UCHAR)pDevExt->WriteDeviceErrors;
  609. ulUniqueErrorValue = ERR_MAX_WRITE_PIPE_DEVICE_ERRORS;
  610. }
  611. } // WORK_ITEM_RESET_WRITE_PIPE
  612. break;
  613. case WORK_ITEM_RESET_INT_PIPE:
  614. {
  615. DbgDump(DBG_WORK_ITEMS, ("WORK_ITEM_RESET_INT_PIPE\n"));
  616. if ( pDevExt->IntDeviceErrors < g_ulMaxPipeErrors)
  617. {
  618. //
  619. // reset INT Pipe, which could fail.
  620. // E.g. flakey h/w, suprise remove, timeout, ...
  621. //
  622. status = UsbResetOrAbortPipe( pDevObj, &pDevExt->IntPipe, RESET );
  623. switch (status)
  624. {
  625. case STATUS_SUCCESS:
  626. {
  627. //
  628. // kick start another INT read
  629. //
  630. status = UsbInterruptRead( pDevExt );
  631. if ((STATUS_SUCCESS == status) || (STATUS_PENDING == status) ) {
  632. //
  633. // the device recovered OK
  634. //
  635. status = STATUS_SUCCESS;
  636. } else {
  637. DbgDump(DBG_ERR, ("UsbInterruptRead error: 0x%x\n", status));
  638. }
  639. } break;
  640. case STATUS_UNSUCCESSFUL:
  641. // a previous reset/abort request failed, so this request was rejected
  642. break;
  643. case STATUS_DELETE_PENDING:
  644. // the device is going away
  645. break;
  646. case STATUS_PENDING:
  647. // there is a reset/abort request already pending
  648. break;
  649. default:
  650. {
  651. //
  652. // if we can not reset the endpoint the device is either hosed or removed
  653. //
  654. DbgDump(DBG_ERR, ("UsbResetOrAbortPipeWorkItem.3 error: 0x%x\n", status ));
  655. retries = 1;
  656. ulUniqueErrorValue = ERR_NO_INT_PIPE_RESET;
  657. } break;
  658. } // switch
  659. } else {
  660. status = (NTSTATUS)PtrToLong(PWorkItem->Context);
  661. retries = (UCHAR)pDevExt->IntDeviceErrors;
  662. ulUniqueErrorValue = ERR_MAX_INT_PIPE_DEVICE_ERRORS;
  663. }
  664. } // WORK_ITEM_RESET_INT_PIPE
  665. break;
  666. case WORK_ITEM_ABORT_READ_PIPE:
  667. case WORK_ITEM_ABORT_WRITE_PIPE:
  668. case WORK_ITEM_ABORT_INT_PIPE:
  669. default:
  670. // status = STATUS_NOT_IMPLEMENTED; - let it fall through and see what happens
  671. DbgDump(DBG_ERR, ("ResetWorkItemFlags: 0x%x 0x%x\n", PWorkItem->Flags, status ));
  672. ASSERT(0);
  673. break;
  674. } // PWorkItem->Flags
  675. } else {
  676. status = STATUS_DELETE_PENDING;
  677. }
  678. //
  679. // is the device is hosed?
  680. //
  681. if ( (STATUS_SUCCESS != status) && (STATUS_DELETE_PENDING != status) && (0 != retries)) {
  682. // only log known errors, not suprise remove.
  683. if (1 == retries ) {
  684. // mark as PNP_DEVICE_REMOVED
  685. InterlockedExchange(&pDevExt->DeviceRemoved, TRUE);
  686. DbgDump(DBG_WRN, ("DEVICE REMOVED\n"));
  687. } else {
  688. // mark as PNP_DEVICE_FAILED
  689. InterlockedExchange(&pDevExt->AcceptingRequests, FALSE);
  690. DbgDump(DBG_ERR, ("*** UNRECOVERABLE DEVICE ERROR: (0x%x, %d) No longer Accepting Requests ***\n", status, retries ));
  691. LogError( NULL,
  692. pDevObj,
  693. 0, 0,
  694. retries,
  695. ulUniqueErrorValue,
  696. status,
  697. SERIAL_HARDWARE_FAILURE,
  698. pDevExt->DeviceName.Length + sizeof(WCHAR),
  699. pDevExt->DeviceName.Buffer,
  700. 0,
  701. NULL );
  702. }
  703. IoInvalidateDeviceState( pDevExt->PDO );
  704. }
  705. DequeueWorkItem( pDevObj, PWorkItem );
  706. DbgDump(DBG_WORK_ITEMS, ("<UsbResetOrAbortPipeWorkItem 0x%x\n", status));
  707. }
  708. //
  709. // NT's USB stack likes only 1 reset pending at any time.
  710. // Also, if any reset fails then do NOT send anymore, else you'll get the controller
  711. // or HUB in a funky state, where it will try to reset the port... which kicks off all
  712. // the other devices on the hub.
  713. //
  714. NTSTATUS
  715. UsbResetOrAbortPipe(
  716. IN PDEVICE_OBJECT PDevObj,
  717. IN PUSB_PIPE PPipe,
  718. IN BOOLEAN Reset
  719. )
  720. {
  721. PDEVICE_EXTENSION pDevExt;
  722. NTSTATUS status;
  723. KIRQL irql;
  724. PURB pUrb;
  725. ASSERT( PDevObj );
  726. DbgDump(DBG_USB, (">UsbResetOrAbortPipe (%p)\n", PDevObj) );
  727. PAGED_CODE();
  728. if (!PDevObj || !PPipe || !PPipe->hPipe ) {
  729. DbgDump(DBG_ERR, ("UsbResetOrAbortPipe: STATUS_INVALID_PARAMETER\n") );
  730. TEST_TRAP();
  731. return STATUS_INVALID_PARAMETER;
  732. }
  733. pDevExt = PDevObj->DeviceExtension;
  734. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  735. if ( PPipe->ResetOrAbortFailed ) {
  736. status = STATUS_UNSUCCESSFUL;
  737. DbgDump(DBG_ERR, ("UsbResetOrAbortPipe.1: 0x%x\n", status) );
  738. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  739. return status;
  740. }
  741. if (!CanAcceptIoRequests(PDevObj, FALSE, TRUE) ||
  742. !NT_SUCCESS(AcquireRemoveLock(&pDevExt->RemoveLock, UlongToPtr(Reset ? URB_FUNCTION_RESET_PIPE : URB_FUNCTION_ABORT_PIPE))))
  743. {
  744. status = STATUS_DELETE_PENDING;
  745. DbgDump(DBG_ERR, ("UsbResetOrAbortPipe.2: 0x%x\n", status) );
  746. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  747. return status;
  748. }
  749. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  750. //
  751. // USBVERIFIER ASSERT: Reset sent on a pipe with a reset already pending
  752. // The USB stack likes only 1 pending Reset or Abort request per pipe a time.
  753. //
  754. if ( 1 == InterlockedIncrement(&PPipe->ResetOrAbortPending) ) {
  755. pUrb = ExAllocateFromNPagedLookasideList( &pDevExt->PipeRequestUrbPool );
  756. if ( pUrb != NULL ) {
  757. //
  758. // pass the Reset -or- Abort request to USBD
  759. //
  760. pUrb->UrbHeader.Length = (USHORT)sizeof(struct _URB_PIPE_REQUEST);
  761. pUrb->UrbHeader.Function = Reset ? URB_FUNCTION_RESET_PIPE : URB_FUNCTION_ABORT_PIPE;
  762. pUrb->UrbPipeRequest.PipeHandle = PPipe->hPipe;
  763. status = UsbSubmitSyncUrb(PDevObj, pUrb, FALSE, DEFAULT_BULK_TIMEOUT);
  764. if (status != STATUS_SUCCESS) {
  765. DbgDump(DBG_ERR , ("*** UsbResetOrAbortPipe ERROR: 0x%x ***\n", status));
  766. InterlockedIncrement(&PPipe->ResetOrAbortFailed);
  767. }
  768. ExFreeToNPagedLookasideList(&pDevExt->PipeRequestUrbPool, pUrb);
  769. } else {
  770. status = STATUS_INSUFFICIENT_RESOURCES;
  771. DbgDump(DBG_ERR , ("ExAllocateFromNPagedLookasideList failed (0x%x)!\n", status));
  772. }
  773. InterlockedDecrement(&PPipe->ResetOrAbortPending);
  774. ASSERT(PPipe->ResetOrAbortPending == 0);
  775. } else {
  776. //
  777. // If there is a reset/abort request pending then we are done.
  778. // Return STATUS_PENDING here so the work item won't start another transfer,
  779. // but will dequeue the item. The real item will follow-up with the correct status.
  780. //
  781. DbgDump(DBG_WRN, ("UsbResetOrAbortPipe: STATUS_PENDING\n"));
  782. TEST_TRAP();
  783. status = STATUS_PENDING;
  784. }
  785. ReleaseRemoveLock(&pDevExt->RemoveLock, UlongToPtr(Reset ? URB_FUNCTION_RESET_PIPE : URB_FUNCTION_ABORT_PIPE));
  786. DbgDump(DBG_USB, ("<UsbResetOrAbortPipe(0x%x)\n", status) );
  787. return status;
  788. }
  789. // EOF