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.

1350 lines
45 KiB

  1. /***************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Dot4Usb.sys - Lower Filter Driver for Dot4.sys for USB connected
  5. IEEE 1284.4 devices.
  6. File Name:
  7. Usb.c
  8. Abstract:
  9. Interface USB DeviceObject below us
  10. Environment:
  11. Kernel mode only
  12. Notes:
  13. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  14. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  15. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  16. PURPOSE.
  17. Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
  18. Revision History:
  19. 01/18/2000 : created
  20. Author(s):
  21. Joby Lafky (JobyL)
  22. Doug Fritz (DFritz)
  23. ****************************************************************************/
  24. #include "pch.h"
  25. NTSTATUS
  26. UsbBuildPipeList(
  27. IN PDEVICE_OBJECT DevObj
  28. )
  29. // Parse the interface descriptor to find the pipes that we want
  30. // to use and save pointers to those pipes in our extension for
  31. // easier access
  32. {
  33. PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
  34. PUSBD_INTERFACE_INFORMATION InterfaceDescriptor;
  35. ULONG i;
  36. KIRQL oldIrql;
  37. NTSTATUS status = STATUS_SUCCESS;
  38. TR_VERBOSE(("UsbBuildPipeList - enter"));
  39. // need to lock extension to prevent Remove handler from freeing
  40. // Interface out from under us causing an AV
  41. KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
  42. InterfaceDescriptor = devExt->Interface;
  43. if( !InterfaceDescriptor ) {
  44. KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
  45. status = STATUS_INSUFFICIENT_RESOURCES;
  46. goto targetExit;
  47. }
  48. for( i=0; i<InterfaceDescriptor->NumberOfPipes; i++ ) {
  49. TR_VERBOSE(("about to look at endpoint with address 0x%x)",InterfaceDescriptor->Pipes[i].EndpointAddress));
  50. if(((InterfaceDescriptor->Pipes[i].EndpointAddress)&0x80)==0) {
  51. // EndPointAddress bit 7 == 0 means OUT endpoint - WritePipe
  52. TR_VERBOSE(("Found write pipe"));
  53. devExt->WritePipe = &(InterfaceDescriptor->Pipes[i]);
  54. } else {
  55. // EndPointAddress bit 7 == 1 means IN endpoint - ReadPipe
  56. if( InterfaceDescriptor->Pipes[i].PipeType == UsbdPipeTypeBulk ) {
  57. TR_VERBOSE(("Found bulk read pipe"));
  58. devExt->ReadPipe = &(InterfaceDescriptor->Pipes[i]);
  59. } else if( InterfaceDescriptor->Pipes[i].PipeType == UsbdPipeTypeInterrupt ) {
  60. TR_VERBOSE(("Found interrupt read pipe"));
  61. devExt->InterruptPipe = &(InterfaceDescriptor->Pipes[i]);
  62. }
  63. }
  64. }
  65. KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
  66. targetExit:
  67. return status;
  68. }
  69. LONG
  70. UsbGet1284Id(
  71. IN PDEVICE_OBJECT DevObj,
  72. PVOID Buffer,
  73. LONG BufferLength
  74. )
  75. /*++
  76. Routine Description:
  77. Requests and returns Printer 1284 Device ID
  78. Arguments:
  79. DeviceObject - pointer to the device object for this instance of the printer device.
  80. pIoBuffer - pointer to IO buffer from user mode
  81. iLen - Length of *pIoBuffer;
  82. Return Value:
  83. Success: Length of data written to *pIoBuffer (icluding lenght field in first two bytes of data)
  84. Failure: -1
  85. --*/
  86. {
  87. NTSTATUS ntStatus = STATUS_SUCCESS;
  88. PURB urb;
  89. LONG iReturn = -1;
  90. PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
  91. LARGE_INTEGER timeOut;
  92. KIRQL oldIrql;
  93. TR_VERBOSE(("UsbGet1284Id - enter"));
  94. urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
  95. if( !urb ) {
  96. iReturn = -1;
  97. goto targetExit;
  98. }
  99. KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
  100. if( !devExt->Interface ) {
  101. KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
  102. iReturn = -1;
  103. goto targetCleanup;
  104. }
  105. UsbBuildVendorRequest( urb,
  106. URB_FUNCTION_CLASS_INTERFACE, //request target
  107. sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), //request len
  108. USBD_TRANSFER_DIRECTION_IN|USBD_SHORT_TRANSFER_OK, //flags
  109. 0, //reserved bits
  110. 0, //request code
  111. 0, //wValue
  112. (USHORT)(devExt->Interface->InterfaceNumber<<8), //wIndex
  113. Buffer, //return buffer address
  114. NULL, //mdl
  115. BufferLength, //return length
  116. NULL); //link param
  117. KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
  118. timeOut.QuadPart = FAILURE_TIMEOUT;
  119. ntStatus = UsbCallUsbd(DevObj, urb, &timeOut);
  120. TR_VERBOSE(("urb->Hdr.Status=%d",((struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *)urb)->Hdr.Status));
  121. if( NT_SUCCESS(ntStatus) && urb->UrbControlVendorClassRequest.TransferBufferLength > 2) {
  122. iReturn= (LONG)(*((unsigned char *)Buffer));
  123. iReturn<<=8;
  124. iReturn+=(LONG)(*(((unsigned char *)Buffer)+1));
  125. if ( iReturn > 0 && iReturn < BufferLength ) {
  126. *(((char *)Buffer)+iReturn)='\0';
  127. } else {
  128. iReturn = -1;
  129. }
  130. } else {
  131. iReturn=-1;
  132. }
  133. targetCleanup:
  134. ExFreePool(urb);
  135. targetExit:
  136. TR_VERBOSE(("UsbGet1284Id - exit w/return value = decimal %d",iReturn));
  137. return iReturn;
  138. }
  139. NTSTATUS
  140. UsbGetDescriptor(
  141. IN PDEVICE_EXTENSION DevExt
  142. )
  143. // get USB descriptor
  144. {
  145. NTSTATUS status = STATUS_SUCCESS;
  146. PURB urb = ExAllocatePool(NonPagedPool, sizeof(URB));
  147. PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
  148. ULONG siz;
  149. LARGE_INTEGER timeOut;
  150. TR_VERBOSE(("UsbGetDescriptor - enter"));
  151. if( urb ) {
  152. siz = sizeof(USB_DEVICE_DESCRIPTOR);
  153. deviceDescriptor = ExAllocatePool(NonPagedPool,siz);
  154. if (deviceDescriptor) {
  155. UsbBuildGetDescriptorRequest(urb,
  156. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  157. USB_DEVICE_DESCRIPTOR_TYPE,
  158. 0,
  159. 0,
  160. deviceDescriptor,
  161. NULL,
  162. siz,
  163. NULL);
  164. timeOut.QuadPart = FAILURE_TIMEOUT;
  165. status = UsbCallUsbd(DevExt->DevObj, urb, &timeOut);
  166. }
  167. } else {
  168. TR_VERBOSE(("UsbGetDescriptor - no pool for urb"));
  169. return STATUS_INSUFFICIENT_RESOURCES;
  170. }
  171. if( NT_SUCCESS(status) ) {
  172. TR_VERBOSE(("Device Descriptor = %x, len %x", deviceDescriptor, urb->UrbControlDescriptorRequest.TransferBufferLength));
  173. TR_VERBOSE(("bLength........... 0x%x", deviceDescriptor->bLength));
  174. TR_VERBOSE(("bDescriptorType 0x%x", deviceDescriptor->bDescriptorType));
  175. TR_VERBOSE(("bcdUSB 0x%x", deviceDescriptor->bcdUSB));
  176. TR_VERBOSE(("bDeviceClass 0x%x", deviceDescriptor->bDeviceClass));
  177. TR_VERBOSE(("bDeviceSubClass....0x%x", deviceDescriptor->bDeviceSubClass));
  178. TR_VERBOSE(("bDeviceProtocol 0x%x", deviceDescriptor->bDeviceProtocol));
  179. TR_VERBOSE(("bMaxPacketSize0 0x%x", deviceDescriptor->bMaxPacketSize0));
  180. TR_VERBOSE(("idVendor 0x%x", deviceDescriptor->idVendor));
  181. TR_VERBOSE(("idProduct......... 0x%x", deviceDescriptor->idProduct));
  182. TR_VERBOSE(("bcdDevice 0x%x", deviceDescriptor->bcdDevice));
  183. TR_VERBOSE(("iManufacturer 0x%x", deviceDescriptor->iManufacturer));
  184. TR_VERBOSE(("iProduct 0x%x", deviceDescriptor->iProduct));
  185. TR_VERBOSE(("iSerialNumber..... 0x%x", deviceDescriptor->iSerialNumber));
  186. TR_VERBOSE(("bNumConfigurations 0x%x", deviceDescriptor->bNumConfigurations));
  187. }
  188. if( urb ) {
  189. ExFreePool( urb );
  190. urb = NULL;
  191. }
  192. if( deviceDescriptor ) {
  193. ExFreePool( deviceDescriptor );
  194. deviceDescriptor = NULL;
  195. }
  196. return status;
  197. }
  198. NTSTATUS
  199. UsbConfigureDevice(
  200. IN PDEVICE_EXTENSION DevExt
  201. )
  202. {
  203. NTSTATUS status;
  204. PURB urb;
  205. ULONG siz;
  206. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
  207. LARGE_INTEGER timeOut;
  208. timeOut.QuadPart = FAILURE_TIMEOUT;
  209. urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  210. if (urb) {
  211. siz = sizeof(USB_CONFIGURATION_DESCRIPTOR)+256;
  212. get_config_descriptor_retry:
  213. configurationDescriptor = ExAllocatePool(NonPagedPool,siz);
  214. if (configurationDescriptor) {
  215. UsbBuildGetDescriptorRequest(urb,
  216. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  217. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  218. 0,
  219. 0,
  220. configurationDescriptor,
  221. NULL,
  222. siz,
  223. NULL);
  224. status = UsbCallUsbd(DevExt->DevObj, urb, &timeOut);
  225. if(!NT_SUCCESS(status)) {
  226. TR_VERBOSE(("Get Configuration descriptor failed"));
  227. } else {
  228. //
  229. // if we got some data see if it was enough.
  230. //
  231. // NOTE: we may get an error in URB because of buffer overrun
  232. if( ( urb->UrbControlDescriptorRequest.TransferBufferLength > 0 ) &&
  233. ( configurationDescriptor->wTotalLength > siz ) ) {
  234. siz = configurationDescriptor->wTotalLength;
  235. ExFreePool(configurationDescriptor);
  236. configurationDescriptor = NULL;
  237. goto get_config_descriptor_retry;
  238. }
  239. }
  240. TR_VERBOSE(("Configuration Descriptor = %x, len %x",
  241. configurationDescriptor, urb->UrbControlDescriptorRequest.TransferBufferLength));
  242. } else {
  243. status = STATUS_INSUFFICIENT_RESOURCES;
  244. }
  245. ExFreePool( urb );
  246. } else {
  247. status = STATUS_INSUFFICIENT_RESOURCES;
  248. }
  249. if( configurationDescriptor ) {
  250. //
  251. // We have the configuration descriptor for the configuration
  252. // we want.
  253. //
  254. // Now we issue the select configuration command to get
  255. // the pipes associated with this configuration.
  256. //
  257. if( NT_SUCCESS(status) ) {
  258. TR_VERBOSE(("got a configurationDescriptor - next try to select interface"));
  259. status = UsbSelectInterface( DevExt->DevObj, configurationDescriptor );
  260. }
  261. ExFreePool( configurationDescriptor );
  262. }
  263. TR_VERBOSE(("dbgUSB2 - exit w/status = %x", status));
  264. return status;
  265. }
  266. NTSTATUS
  267. UsbSelectInterface(
  268. IN PDEVICE_OBJECT DevObj,
  269. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
  270. )
  271. {
  272. PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
  273. NTSTATUS status;
  274. PURB urb = NULL;
  275. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
  276. PUSBD_INTERFACE_INFORMATION Interface = NULL;
  277. USBD_INTERFACE_LIST_ENTRY InterfaceList[2];
  278. LARGE_INTEGER timeOut;
  279. timeOut.QuadPart = FAILURE_TIMEOUT;
  280. TR_VERBOSE(("dbgUSB3 - enter"));
  281. //
  282. // Look for a *.*.3 interface in the ConfigurationDescriptor
  283. //
  284. interfaceDescriptor = USBD_ParseConfigurationDescriptorEx( ConfigurationDescriptor,
  285. ConfigurationDescriptor,
  286. -1, // InterfaceNumber - ignore
  287. -1, // AlternateSetting - ignore
  288. -1, // InterfaceClass - ignore
  289. -1, // InterfaceSubClass - ignore
  290. 3 // InterfaceProtocol
  291. );
  292. if( !interfaceDescriptor ) {
  293. TR_VERBOSE(("ParseConfigurationDescriptorEx FAILED"));
  294. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  295. goto targetExit;
  296. }
  297. TR_VERBOSE(("ParseConfigurationDescriptorEx SUCCESS"));
  298. InterfaceList[0].InterfaceDescriptor=interfaceDescriptor;
  299. InterfaceList[1].InterfaceDescriptor=NULL;
  300. urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor,InterfaceList);
  301. if( !urb ) {
  302. TR_VERBOSE(("no pool for URB - dbgUSB3"));
  303. status = STATUS_INSUFFICIENT_RESOURCES;
  304. goto targetExit;
  305. }
  306. Interface = InterfaceList[0].Interface;
  307. // handle larger transfers on pipes (perf requirement by scanning)
  308. {
  309. PUSBD_INTERFACE_INFORMATION myInterface = &urb->UrbSelectConfiguration.Interface;
  310. ULONG i;
  311. ULONG pipeCount = Interface->NumberOfPipes;
  312. ULONG newMax = 128 * 1024 - 1;
  313. for( i=0 ; i < pipeCount ; ++i ) {
  314. myInterface->Pipes[i].MaximumTransferSize = newMax;
  315. }
  316. }
  317. status = UsbCallUsbd(DevObj, urb, &timeOut);
  318. if (NT_SUCCESS(status)) {
  319. //
  320. // Save the configuration handle for this device
  321. //
  322. devExt->ConfigHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
  323. devExt->Interface = ExAllocatePool(NonPagedPool,Interface->Length);
  324. if( devExt->Interface ) {
  325. ULONG j;
  326. //
  327. // save a copy of the interface information returned
  328. //
  329. RtlCopyMemory(devExt->Interface, Interface, Interface->Length);
  330. //
  331. // Dump the interface to the debugger
  332. //
  333. TR_VERBOSE(("NumberOfPipes 0x%x", devExt->Interface->NumberOfPipes));
  334. TR_VERBOSE(("Length 0x%x", devExt->Interface->Length));
  335. TR_VERBOSE(("Alt Setting 0x%x", devExt->Interface->AlternateSetting));
  336. TR_VERBOSE(("Interface Number 0x%x", devExt->Interface->InterfaceNumber));
  337. TR_VERBOSE(("Class, subclass, protocol 0x%x 0x%x 0x%x",
  338. devExt->Interface->Class, devExt->Interface->SubClass, devExt->Interface->Protocol));
  339. // Dump the pipe info
  340. for( j=0; j<Interface->NumberOfPipes; ++j ) {
  341. PUSBD_PIPE_INFORMATION pipeInformation;
  342. pipeInformation = &devExt->Interface->Pipes[j];
  343. TR_VERBOSE(("PipeType 0x%x", pipeInformation->PipeType));
  344. TR_VERBOSE(("EndpointAddress 0x%x", pipeInformation->EndpointAddress));
  345. TR_VERBOSE(("MaxPacketSize 0x%x", pipeInformation->MaximumPacketSize));
  346. TR_VERBOSE(("Interval 0x%x", pipeInformation->Interval));
  347. TR_VERBOSE(("Handle 0x%x", pipeInformation->PipeHandle));
  348. TR_VERBOSE(("MaximumTransferSize 0x%x", pipeInformation->MaximumTransferSize));
  349. }
  350. } else {
  351. TR_VERBOSE(("Alloc failed in SelectInterface"));
  352. status = STATUS_INSUFFICIENT_RESOURCES;
  353. }
  354. }
  355. if( urb ) {
  356. ExFreePool( urb );
  357. }
  358. targetExit:
  359. TR_VERBOSE(("dbgUSB3 exit w/status = %x", status));
  360. return status;
  361. }
  362. PURB
  363. UsbBuildAsyncRequest(
  364. IN PDEVICE_OBJECT DeviceObject,
  365. IN PIRP Irp,
  366. IN PUSBD_PIPE_INFORMATION PipeHandle,
  367. IN BOOLEAN Read
  368. )
  369. // return an initialized async URB, or NULL on error
  370. {
  371. ULONG siz;
  372. PURB urb;
  373. UNREFERENCED_PARAMETER( DeviceObject );
  374. if( NULL == Irp->MdlAddress ) {
  375. return NULL;
  376. }
  377. siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  378. urb = ExAllocatePool( NonPagedPool, siz );
  379. if( urb ) {
  380. RtlZeroMemory(urb, siz);
  381. urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
  382. urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  383. urb->UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle->PipeHandle;
  384. urb->UrbBulkOrInterruptTransfer.TransferFlags = Read ? USBD_TRANSFER_DIRECTION_IN : 0;
  385. // short packet is not treated as an error.
  386. urb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  387. // no linkage for now
  388. urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  389. urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = Irp->MdlAddress;
  390. urb->UrbBulkOrInterruptTransfer.TransferBufferLength = MmGetMdlByteCount(Irp->MdlAddress);
  391. }
  392. return urb;
  393. }
  394. NTSTATUS
  395. UsbAsyncReadWriteComplete(
  396. IN PDEVICE_OBJECT DeviceObject,
  397. IN PIRP Irp,
  398. IN PVOID Context
  399. )
  400. /*++
  401. Routine Description:
  402. Arguments:
  403. DeviceObject - Pointer to the device object for the USBPRINT device.
  404. Irp - Irp completed.
  405. Context - Driver defined context.
  406. Return Value:
  407. The function value is the final status from the operation.
  408. --*/
  409. {
  410. NTSTATUS status = STATUS_SUCCESS;
  411. PUSB_RW_CONTEXT rwContext = Context;
  412. PURB urb;
  413. LONG ResetPending;
  414. PDOT4USB_WORKITEM_CONTEXT pResetWorkItemObj;
  415. PDEVICE_EXTENSION deviceExtension;
  416. deviceExtension=DeviceObject->DeviceExtension;
  417. if (Irp->PendingReturned) {
  418. IoMarkIrpPending(Irp);
  419. }
  420. urb = rwContext->Urb;
  421. TR_VERBOSE(("UsbAsyncReadWriteComplete - enter - TransferBufferLength= %d, UrbStatus= 0x%08X",
  422. urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
  423. urb->UrbHeader.Status));
  424. status=urb->UrbHeader.Status;
  425. // set the length based on the TransferBufferLength value in the URB
  426. Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  427. if((!NT_SUCCESS(status))&&(status!=STATUS_CANCELLED)&&(status!=STATUS_DEVICE_NOT_CONNECTED))
  428. {
  429. ResetPending=InterlockedCompareExchange(&deviceExtension->ResetWorkItemPending,1,0); //Check to see if ResetWorkItem is 0, if so, set it to 1, and start a Reset
  430. if(!ResetPending)
  431. {
  432. pResetWorkItemObj=ExAllocatePool(NonPagedPool,sizeof(DOT4USB_WORKITEM_CONTEXT));
  433. if(pResetWorkItemObj)
  434. {
  435. pResetWorkItemObj->ioWorkItem=IoAllocateWorkItem(DeviceObject);
  436. if(pResetWorkItemObj==NULL)
  437. {
  438. TR_FAIL(("DOT4USB.SYS: Unable to allocate IoAllocateWorkItem in ReadWrite_Complete\n"));
  439. ExFreePool(pResetWorkItemObj);
  440. pResetWorkItemObj=NULL;
  441. }
  442. } //if ALloc RestWorkItem OK
  443. else
  444. {
  445. TR_FAIL(("DOT4USB.SYS: Unable to allocate WorkItemObj in ReadWrite_Complete\n"));
  446. }
  447. if(pResetWorkItemObj)
  448. {
  449. pResetWorkItemObj->irp=Irp;
  450. pResetWorkItemObj->deviceObject=DeviceObject;
  451. if(rwContext->IsWrite)
  452. pResetWorkItemObj->pPipeInfo=deviceExtension->WritePipe;
  453. else
  454. pResetWorkItemObj->pPipeInfo=deviceExtension->ReadPipe;
  455. IoQueueWorkItem(pResetWorkItemObj->ioWorkItem,DOT4USB_ResetWorkItem,DelayedWorkQueue,pResetWorkItemObj);
  456. status=STATUS_MORE_PROCESSING_REQUIRED;
  457. } //end if allocs all OK
  458. } //end if not already resetting
  459. } //end if we need to reset
  460. IoReleaseRemoveLock( &(deviceExtension->RemoveLock), Irp );
  461. ExFreePool(rwContext);
  462. ExFreePool(urb);
  463. return status;
  464. }
  465. NTSTATUS DOT4USB_ResetWorkItem(IN PDEVICE_OBJECT deviceObject, IN PVOID Context)
  466. {
  467. PDOT4USB_WORKITEM_CONTEXT pResetWorkItemObj;
  468. PDEVICE_EXTENSION DeviceExtension;
  469. NTSTATUS ntStatus;
  470. PDEVICE_OBJECT devObj;
  471. UNREFERENCED_PARAMETER(deviceObject);
  472. TR_VERBOSE(("USBPRINT.SYS: Entering USBPRINT_ResetWorkItem\n"));
  473. pResetWorkItemObj=(PDOT4USB_WORKITEM_CONTEXT)Context;
  474. DeviceExtension=pResetWorkItemObj->deviceObject->DeviceExtension;
  475. ntStatus=UsbResetPipe(pResetWorkItemObj->deviceObject,pResetWorkItemObj->pPipeInfo,FALSE);
  476. IoCompleteRequest(pResetWorkItemObj->irp,IO_NO_INCREMENT);
  477. IoFreeWorkItem(pResetWorkItemObj->ioWorkItem);
  478. // save off work item device object before freeing work item
  479. devObj = pResetWorkItemObj->deviceObject;
  480. ExFreePool(pResetWorkItemObj);
  481. InterlockedExchange(&(DeviceExtension->ResetWorkItemPending),0);
  482. return ntStatus;
  483. }
  484. NTSTATUS
  485. UsbReadInterruptPipeLoopCompletionRoutine(
  486. IN PDEVICE_OBJECT DevObj,
  487. IN PIRP Irp,
  488. IN PDEVICE_EXTENSION devExt
  489. )
  490. {
  491. PURB urb;
  492. PDEVICE_OBJECT devObj;
  493. PUSB_RW_CONTEXT context;
  494. PCHAR scratchBuffer;
  495. KIRQL oldIrql;
  496. ULONG sizeOfUrb;
  497. PIO_STACK_LOCATION irpSp;
  498. NTSTATUS status;
  499. BOOLEAN queueNewRequest;
  500. UNREFERENCED_PARAMETER( DevObj ); // we created this Irp via IoAllocateIrp() and we didn't reserve an IO_STACK_LOCATION
  501. // for ourselves, so we can't use this
  502. if(devExt->InterruptContext)
  503. {
  504. context = devExt->InterruptContext;
  505. urb = context->Urb;
  506. devObj = context->DevObj;
  507. scratchBuffer = urb->UrbBulkOrInterruptTransfer.TransferBuffer;
  508. }
  509. else
  510. {
  511. return STATUS_MORE_PROCESSING_REQUIRED;
  512. }
  513. // must have freed up the context stuff, so just return
  514. KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
  515. if( !Irp->Cancel && devExt->Dot4Event && NT_SUCCESS(Irp->IoStatus.Status) ) {
  516. queueNewRequest = TRUE;
  517. KeSetEvent( devExt->Dot4Event, 1, FALSE ); // signal dot4.sys that peripheral has data to be read
  518. } else {
  519. TR_TMP1(("UsbReadInterruptPipeLoopCompletionRoutine - cancel, Dot4 event gone, or bad status in irp - time to clean up"));
  520. if( STATUS_SUCCESS != Irp->IoStatus.Status ) {
  521. TR_TMP1(("UsbReadInterruptPipeLoopCompletionRoutine - IoStatus.Status = %x\n",Irp->IoStatus.Status));
  522. }
  523. queueNewRequest = FALSE;
  524. }
  525. KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
  526. if( queueNewRequest ) {
  527. // queue another read request in the interrupt pipe
  528. sizeOfUrb = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  529. RtlZeroMemory( urb, sizeOfUrb );
  530. urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeOfUrb;
  531. urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  532. urb->UrbBulkOrInterruptTransfer.PipeHandle = devExt->InterruptPipe->PipeHandle;
  533. urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
  534. urb->UrbBulkOrInterruptTransfer.TransferBuffer = scratchBuffer;
  535. urb->UrbBulkOrInterruptTransfer.TransferBufferLength = SCRATCH_BUFFER_SIZE;
  536. urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  537. urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  538. IoReuseIrp( Irp, STATUS_NOT_SUPPORTED );
  539. irpSp = IoGetNextIrpStackLocation( Irp );
  540. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  541. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  542. irpSp->Parameters.Others.Argument1 = urb;
  543. IoSetCompletionRoutine( Irp, UsbReadInterruptPipeLoopCompletionRoutine, devExt, TRUE, TRUE, TRUE );
  544. status = IoCallDriver(devExt->LowerDevObj, Irp);
  545. if( !NT_SUCCESS( status ) ) {
  546. // bummer - Irp is in limbo - stop polling and mark Irp for cleanup
  547. D4UAssert(!"UsbReadInterruptPipeLoopCompletionRoutine - IoCallDriver failed");
  548. if(devExt->InterruptContext)
  549. {
  550. InterlockedExchangePointer(&devExt->InterruptContext, NULL);
  551. ExFreePool( urb );
  552. ExFreePool( context );
  553. ExFreePool( scratchBuffer );
  554. KeSetEvent( &devExt->PollIrpEvent, 0, FALSE ); // signal dispatch routine that it is safe to touch the Irp - including IoFreeIrp()
  555. }
  556. }
  557. } else {
  558. if(devExt->InterruptContext)
  559. {
  560. // clean up - either Irp was cancelled or we got a datalink disconnect IOCTL from dot4
  561. InterlockedExchangePointer(&devExt->InterruptContext, NULL);
  562. ExFreePool( urb );
  563. ExFreePool( context );
  564. ExFreePool( scratchBuffer );
  565. TR_TMP1(("UsbReadInterruptPipeLoopCompletionRoutine - signalling PollIrpEvent"));
  566. KeSetEvent( &devExt->PollIrpEvent, 0, FALSE ); // signal dispatch routine that it is safe to touch the Irp - including IoFreeIrp()
  567. }
  568. }
  569. return STATUS_MORE_PROCESSING_REQUIRED; // always
  570. }
  571. /************************************************************************/
  572. /* UsbStopReadInterruptPipeLoop */
  573. /************************************************************************/
  574. //
  575. // Routine Description:
  576. //
  577. // - Stop the polling of the device interrupt pipe started by
  578. // UsbStartReadInterruptPipeLoop and free the Irp.
  579. //
  580. // - It is legal for devExt->PollIrp to be NULL on entry to this function.
  581. //
  582. // - This function is called from the DataLink Disconnect IOCTL
  583. // handler, from the PnP Surprise Removal handler and from the
  584. // PnP Remove handler. It is safe to call this function multiple
  585. // times between PollIrp creations.
  586. //
  587. // - This is the only function in the driver that should call
  588. // IoFreeIrp on devExt->PollIrp and it is the only function
  589. // that should change devExt->PollIrp from !NULL -> NULL
  590. //
  591. // - This function will block until the PollIrp, if any, has
  592. // been cleaned up. The block should be for a very short
  593. // period of time unless there is a driver bug here or in
  594. // the USB stack below us.
  595. //
  596. // Arguments:
  597. //
  598. // DevObj - pointer to Dot4Usb.sys driver object
  599. //
  600. // Return Value:
  601. //
  602. // NONE
  603. //
  604. /************************************************************************/
  605. VOID
  606. UsbStopReadInterruptPipeLoop(
  607. IN PDEVICE_OBJECT DevObj
  608. )
  609. {
  610. PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
  611. KIRQL oldIrql;
  612. TR_VERBOSE(("UsbStopReadInterruptPipeLoop - enter"));
  613. //
  614. // We must hold this SpinLock in order to change devExt->PollIrp
  615. //
  616. KeAcquireSpinLock( &devExt->PollIrpSpinLock, &oldIrql );
  617. if( devExt->PollIrp ) {
  618. //
  619. // We have a PollIrp - Cancel the Irp so that the completion
  620. // routine detects that it should take the Irp out of play and
  621. // signal us when it is safe for us to touch the irp.
  622. //
  623. NTSTATUS status;
  624. LARGE_INTEGER timeOut;
  625. PIRP irp;
  626. irp = devExt->PollIrp;
  627. devExt->PollIrp = NULL;
  628. //
  629. // Safe to let go of the SpinLock - everything from here on is local to this function
  630. //
  631. KeReleaseSpinLock( &devExt->PollIrpSpinLock, oldIrql );
  632. //
  633. // Completion routine will detect that the Irp has been cancelled
  634. //
  635. retryCancel:
  636. IoCancelIrp( irp );
  637. //
  638. // Completion routine will set PollIrpEvent when it has taken
  639. // the Irp out of play and it is safe for us to touch the Irp
  640. //
  641. // 500ms (in 100ns units) - magic number chosen as "reasonable" timeout
  642. //
  643. timeOut.QuadPart = - 500 * 10 * 1000;
  644. status = KeWaitForSingleObject( &devExt->PollIrpEvent, Executive, KernelMode, FALSE, &timeOut );
  645. if( STATUS_SUCCESS == status ) {
  646. //
  647. // Completion routine has signalled that we now own the irp - clean it up
  648. //
  649. IoFreeIrp( irp );
  650. //
  651. // This irp will no longer block a Remove
  652. //
  653. IoReleaseRemoveLock( &devExt->RemoveLock, irp );
  654. } else if( STATUS_TIMEOUT == status ) {
  655. //
  656. // Cancel and wait again - either we hit a timing window where our completion
  657. // routine lost our cancel request, or the Irp is wedged in a driver somewhere
  658. // below us.
  659. //
  660. goto retryCancel;
  661. } else {
  662. //
  663. // We specified that we were NOT alertable - but check for this condition anyway
  664. //
  665. D4UAssert(!"UsbStopReadInterruptPipeLoop - unexpected status from KeWaitForSingleObject?!?");
  666. goto retryCancel;
  667. }
  668. } else {
  669. //
  670. // We don't have a PollIrp - nothing for us to clean up.
  671. //
  672. TR_VERBOSE(("UsbStopReadInterruptPipeLoop - NULL PollIrp"));
  673. KeReleaseSpinLock( &devExt->PollIrpSpinLock, oldIrql );
  674. }
  675. }
  676. /************************************************************************/
  677. /* UsbStartReadInterruptPipeLoop */
  678. /************************************************************************/
  679. //
  680. // Routine Description:
  681. //
  682. // - Create a read request (Irp) for the device's interrupt pipe. Save a
  683. // pointer to the Irp in our device extension for cleanup later by
  684. // UsbStopReadInterruptPipeLoop().
  685. //
  686. // - This is the only function in the driver that should change
  687. // devExt->PollIrp from NULL -> !NULL
  688. //
  689. // Arguments:
  690. //
  691. // DevObj - pointer to Dot4Usb.sys driver object
  692. //
  693. // Return Value:
  694. //
  695. // NTSTATUS
  696. //
  697. /************************************************************************/
  698. NTSTATUS
  699. UsbStartReadInterruptPipeLoop(
  700. IN PDEVICE_OBJECT DevObj
  701. )
  702. {
  703. NTSTATUS status;
  704. PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
  705. PUSBD_PIPE_INFORMATION pipe;
  706. ULONG sizeOfUrb;
  707. PIRP irp;
  708. PIO_STACK_LOCATION irpSp;
  709. PURB urb;
  710. PUSB_RW_CONTEXT context;
  711. PCHAR scratchBuffer;
  712. KIRQL oldIrql;
  713. TR_VERBOSE(("UsbStartReadInterruptPipeLoop - enter"));
  714. //
  715. // We must hold this SpinLock in order to change devExt->PollIrp
  716. //
  717. // BUGBUG - This SpinLock is protecting some code that doesn't need protection,
  718. // which means that we are at Raised Irql when we don't need to be.
  719. // Revisit this later to move the Acquire and Release of this SpinLock
  720. // so that it only protects code that needs protection.
  721. //
  722. KeAcquireSpinLock( &devExt->PollIrpSpinLock, &oldIrql );
  723. //
  724. // Driver state machine check - we should never get two calls to this
  725. // function without a cleanup (UsbStopReadInterruptPipeLoop) call in between.
  726. //
  727. D4UAssert( !devExt->PollIrp );
  728. //
  729. // Verify that we have an interrupt pipe
  730. //
  731. pipe = devExt->InterruptPipe;
  732. if( !pipe ) {
  733. TR_FAIL(("UsbStartReadInterruptPipeLoop - no interrupt pipe"));
  734. status = STATUS_INVALID_HANDLE;
  735. goto targetError;
  736. }
  737. //
  738. // Pipe type/look ok?
  739. //
  740. D4UAssert( UsbdPipeTypeInterrupt == pipe->PipeType && USBD_PIPE_DIRECTION_IN(pipe) );
  741. //
  742. // Allocate pool that we need for this request
  743. //
  744. sizeOfUrb = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  745. urb = ExAllocatePool( NonPagedPool, sizeOfUrb );
  746. if( !urb ) {
  747. status = STATUS_INSUFFICIENT_RESOURCES;
  748. goto targetError;
  749. }
  750. context = ExAllocatePool( NonPagedPool, sizeof(USB_RW_CONTEXT) );
  751. if( !context ) {
  752. ExFreePool( urb );
  753. status = STATUS_INSUFFICIENT_RESOURCES;
  754. goto targetError;
  755. }
  756. scratchBuffer = ExAllocatePool( NonPagedPool, SCRATCH_BUFFER_SIZE );
  757. if( !scratchBuffer ) {
  758. ExFreePool( urb );
  759. ExFreePool( context );
  760. status = STATUS_INSUFFICIENT_RESOURCES;
  761. goto targetError;
  762. }
  763. //
  764. // Set up Context for completion routine
  765. //
  766. // - We send down a pointer to our Device Object in context
  767. // because we create this IRP via IoAllocateIrp and we don't
  768. // reserve a stack location for ourselves, so the PDEVICE_OBJECT
  769. // parameter that our completion routine receives is bogus
  770. // (probably NULL)
  771. //
  772. context->Urb = urb;
  773. context->DevObj = DevObj;
  774. //
  775. // Initialize URB for read on interrupt pipe
  776. //
  777. RtlZeroMemory( urb, sizeOfUrb );
  778. urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeOfUrb;
  779. urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  780. urb->UrbBulkOrInterruptTransfer.PipeHandle = pipe->PipeHandle;
  781. urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
  782. urb->UrbBulkOrInterruptTransfer.TransferBuffer = scratchBuffer;
  783. urb->UrbBulkOrInterruptTransfer.TransferBufferLength = SCRATCH_BUFFER_SIZE; // note - likely only one byte to read
  784. urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  785. urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  786. //
  787. // Allocate and set up the IRP, stack location, and completion routine
  788. //
  789. irp = IoAllocateIrp( devExt->LowerDevObj->StackSize, FALSE );
  790. if( !irp ) {
  791. ExFreePool( urb );
  792. ExFreePool( context );
  793. ExFreePool( scratchBuffer );
  794. status = STATUS_INSUFFICIENT_RESOURCES;
  795. goto targetError;
  796. }
  797. irpSp = IoGetNextIrpStackLocation( irp );
  798. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  799. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  800. irpSp->Parameters.Others.Argument1 = urb;
  801. IoSetCompletionRoutine( irp, UsbReadInterruptPipeLoopCompletionRoutine, devExt, TRUE, TRUE, TRUE );
  802. //
  803. // This event will be SET by the completion routine when it is
  804. // safe for a dispatch routine to touch this Irp
  805. //
  806. KeClearEvent( &devExt->PollIrpEvent );
  807. //
  808. // We're about to put the Irp in play - make sure that our device
  809. // doesn't get removed while this Irp is in use
  810. //
  811. status = IoAcquireRemoveLock( &devExt->RemoveLock, irp );
  812. if( STATUS_SUCCESS != status ) {
  813. //
  814. // We're being removed - clean up and bail out
  815. //
  816. IoFreeIrp( irp );
  817. ExFreePool( urb );
  818. ExFreePool( context );
  819. ExFreePool( scratchBuffer );
  820. status = STATUS_DELETE_PENDING;
  821. goto targetError;
  822. }
  823. //
  824. // Save a pointer to this Irp in our extension so that UsbStopReadInterruptPipeLoop()
  825. // can find it to IoFreeIrp() it later.
  826. //
  827. D4UAssert( !devExt->PollIrp );
  828. devExt->PollIrp = irp;
  829. // save interrupt context in device extension
  830. InterlockedExchangePointer(&devExt->InterruptContext, context);
  831. //
  832. // Kick off the first read. Subsequent reads will come from the
  833. // completion routine as it reuses/bounces the IRP. The completion routine
  834. // is responsible taking the Irp out of play when it detects either a termination
  835. // condition or request error. UsbStopReadInterruptPipeLoop() will clean up the
  836. // Irp after the completion routine has taken the Irp out of play and signaled
  837. // PollIrpEvent that it is safe to touch the Irp.
  838. //
  839. status = IoCallDriver( devExt->LowerDevObj, irp );
  840. targetError:
  841. //
  842. // CURRENTLY... all paths to here hold the SpinLock - this should change after cleanup
  843. //
  844. KeReleaseSpinLock( &devExt->PollIrpSpinLock, oldIrql );
  845. //
  846. // If the Irp is Pending then we have been successful
  847. //
  848. if( STATUS_PENDING == status ) {
  849. status = STATUS_SUCCESS;
  850. }
  851. return status;
  852. }
  853. NTSTATUS
  854. UsbDeferIrpCompletion(
  855. IN PDEVICE_OBJECT DeviceObject,
  856. IN PIRP Irp,
  857. IN PVOID Event
  858. )
  859. {
  860. UNREFERENCED_PARAMETER( DeviceObject );
  861. UNREFERENCED_PARAMETER( Irp );
  862. KeSetEvent( (PKEVENT)Event, 1, FALSE );
  863. return STATUS_MORE_PROCESSING_REQUIRED;
  864. }
  865. NTSTATUS
  866. UsbCallUsbd(
  867. IN PDEVICE_OBJECT DevObj,
  868. IN PURB Urb,
  869. IN PLARGE_INTEGER pTimeout
  870. )
  871. /*++
  872. Routine Description:
  873. Passes a URB to the USBD class driver
  874. Arguments:
  875. DeviceObject - pointer to the device object for this printer
  876. Urb - pointer to Urb request block
  877. Return Value:
  878. STATUS_SUCCESS if successful,
  879. STATUS_UNSUCCESSFUL otherwise
  880. --*/
  881. {
  882. NTSTATUS ntStatus, status = STATUS_SUCCESS;
  883. PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
  884. PIRP irp;
  885. KEVENT event;
  886. PIO_STACK_LOCATION nextStack;
  887. TR_VERBOSE(("UsbCallUsbd - enter"));
  888. //
  889. // issue a synchronous request
  890. //
  891. KeInitializeEvent(&event, NotificationEvent, FALSE);
  892. if ( (irp = IoAllocateIrp(devExt->LowerDevObj->StackSize,
  893. FALSE)) == NULL )
  894. return STATUS_INSUFFICIENT_RESOURCES;
  895. //
  896. // Call the class driver to perform the operation. If the returned status
  897. // is PENDING, wait for the request to complete.
  898. //
  899. nextStack = IoGetNextIrpStackLocation(irp);
  900. D4UAssert(nextStack != NULL);
  901. //
  902. // pass the URB to the USB driver stack
  903. //
  904. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  905. nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  906. nextStack->Parameters.Others.Argument1 = Urb;
  907. IoSetCompletionRoutine(irp,
  908. UsbDeferIrpCompletion,
  909. &event,
  910. TRUE,
  911. TRUE,
  912. TRUE);
  913. ntStatus = IoCallDriver(devExt->LowerDevObj, irp);
  914. if ( ntStatus == STATUS_PENDING ) {
  915. status = KeWaitForSingleObject(&event,Suspended,KernelMode,FALSE,pTimeout);
  916. //
  917. // If the request timed out cancel the request
  918. // and wait for it to complete
  919. //
  920. if ( status == STATUS_TIMEOUT ) {
  921. TR_VERBOSE(("UsbCallUsbd: Cancelling IRP %x because of timeout", irp));
  922. IoCancelIrp(irp);
  923. KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
  924. }
  925. ntStatus = irp->IoStatus.Status;
  926. }
  927. IoFreeIrp(irp);
  928. TR_VERBOSE(("UsbCallUsbd - exit w/status=%x", ntStatus));
  929. return ntStatus;
  930. }
  931. NTSTATUS
  932. UsbResetPipe(
  933. IN PDEVICE_OBJECT DeviceObject,
  934. IN PUSBD_PIPE_INFORMATION Pipe,
  935. IN BOOLEAN IsoClearStall
  936. )
  937. /*++
  938. Routine Description:
  939. Reset a given USB pipe.
  940. NOTES:
  941. This will reset the host to Data0 and should also reset the device
  942. to Data0 for Bulk and Interrupt pipes.
  943. For Iso pipes this will set the virgin state of pipe so that ASAP
  944. transfers begin with the current bus frame instead of the next frame
  945. after the last transfer occurred.
  946. Arguments:
  947. Return Value:
  948. --*/
  949. {
  950. NTSTATUS ntStatus;
  951. PURB urb;
  952. LARGE_INTEGER timeOut;
  953. timeOut.QuadPart = FAILURE_TIMEOUT;
  954. TR_VERBOSE(("Entering UsbResetPipe; pipe # %x\n", Pipe));
  955. urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_PIPE_REQUEST));
  956. if (urb) {
  957. urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
  958. urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
  959. urb->UrbPipeRequest.PipeHandle =
  960. Pipe->PipeHandle;
  961. ntStatus = UsbCallUsbd(DeviceObject, urb, &timeOut);
  962. ExFreePool(urb);
  963. } else {
  964. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  965. }
  966. //
  967. // Memphis RESET_PIPE will send a Clear-Feature Endpoint Stall to
  968. // reset the data toggle of non-Iso pipes as part of a RESET_PIPE
  969. // request. It does not do this for Iso pipes as Iso pipes do not use
  970. // the data toggle (all Iso packets are Data0). However, we also use
  971. // the Clear-Feature Endpoint Stall request in our device firmware to
  972. // reset data buffer points inside the device so we explicitly send
  973. // this request to the device for Iso pipes if desired.
  974. //
  975. if (NT_SUCCESS(ntStatus) && IsoClearStall &&
  976. (Pipe->PipeType == UsbdPipeTypeIsochronous)) {
  977. urb = ExAllocatePool(NonPagedPool,sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
  978. if (urb) {
  979. UsbBuildFeatureRequest(urb,
  980. URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT,
  981. USB_FEATURE_ENDPOINT_STALL,
  982. Pipe->EndpointAddress,
  983. NULL);
  984. ntStatus = UsbCallUsbd(DeviceObject, urb, &timeOut);
  985. ExFreePool(urb);
  986. } else {
  987. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  988. }
  989. }
  990. return ntStatus;
  991. }
  992. NTSTATUS
  993. UsbReadWrite(
  994. IN PDEVICE_OBJECT DevObj,
  995. IN PIRP Irp,
  996. PUSBD_PIPE_INFORMATION Pipe,
  997. USB_REQUEST_TYPE RequestType
  998. )
  999. /*
  1000. - Caller must verify that:
  1001. - Irp->MdlAddress != NULL
  1002. - Pipe != NULL
  1003. - RequestType matches Pipe->PipeType
  1004. */
  1005. {
  1006. PDEVICE_EXTENSION devExt;
  1007. PIO_STACK_LOCATION nextIrpSp;
  1008. PURB urb;
  1009. PUSB_RW_CONTEXT context;
  1010. ULONG sizeOfUrb = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
  1011. NTSTATUS status = STATUS_SUCCESS;
  1012. TR_VERBOSE(("UsbReadWrite - enter"));
  1013. D4UAssert( Irp->MdlAddress ); // calling routine should catch and fail this case
  1014. D4UAssert( Pipe ); // calling routine should catch and fail this case
  1015. urb = ExAllocatePool( NonPagedPool, sizeOfUrb );
  1016. if( !urb ) {
  1017. TR_FAIL(("UsbReadWrite - no pool for URB"));
  1018. status = STATUS_INSUFFICIENT_RESOURCES;
  1019. goto targetError;
  1020. }
  1021. context = ExAllocatePool( NonPagedPool, sizeof(USB_RW_CONTEXT) );
  1022. if( !context ) {
  1023. TR_FAIL(("UsbReadWrite - no pool for context"));
  1024. ExFreePool( urb );
  1025. status = STATUS_INSUFFICIENT_RESOURCES;
  1026. goto targetError;
  1027. }
  1028. context->Urb = (PURB)urb;
  1029. context->DevObj = DevObj;
  1030. RtlZeroMemory(urb, sizeOfUrb);
  1031. UsbBuildInterruptOrBulkTransferRequest( urb,
  1032. (USHORT)sizeOfUrb,
  1033. Pipe->PipeHandle,
  1034. NULL, // transferBuffer
  1035. Irp->MdlAddress,
  1036. MmGetMdlByteCount(Irp->MdlAddress),
  1037. 0, // transfer Flags
  1038. NULL );
  1039. if( UsbReadRequest == RequestType ) {
  1040. context->IsWrite=FALSE;
  1041. TR_VERBOSE(("UsbReadWrite - requesttype is READ"))
  1042. urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
  1043. urb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  1044. } else {
  1045. context->IsWrite=TRUE;
  1046. TR_VERBOSE(("UsbReadWrite - requesttype is WRITE"))
  1047. }
  1048. nextIrpSp = IoGetNextIrpStackLocation( Irp );
  1049. nextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1050. nextIrpSp->Parameters.Others.Argument1 = urb;
  1051. nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  1052. IoSetCompletionRoutine( Irp, UsbAsyncReadWriteComplete, context, TRUE, TRUE, TRUE );
  1053. devExt = DevObj->DeviceExtension;
  1054. IoMarkIrpPending(Irp);
  1055. status = IoCallDriver( devExt->LowerDevObj, Irp );
  1056. status = STATUS_PENDING;
  1057. goto targetDone;
  1058. targetError:
  1059. Irp->IoStatus.Status = status;
  1060. Irp->IoStatus.Information = 0;
  1061. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1062. targetDone:
  1063. TR_VERBOSE(("UsbReadWrite - exit - status= %x",status));
  1064. return status;
  1065. }