Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1641 lines
54 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract: Human Input Device (HID) minidriver for Universal Serial Bus (USB) devices
  6. The HID USB Minidriver (HUM, Hum) provides an abstraction layer for the
  7. HID Class so that future HID devices whic are not USB devices can be supported.
  8. Author:
  9. forrestf
  10. ervinp
  11. jdunn
  12. Environment:
  13. Kernel mode
  14. Revision History:
  15. --*/
  16. #include "pch.h"
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, HumGetHidDescriptor)
  19. #pragma alloc_text(PAGE, HumGetReportDescriptor)
  20. #pragma alloc_text(PAGE, HumGetStringDescriptor)
  21. #pragma alloc_text(PAGE, HumGetPhysicalDescriptor)
  22. #pragma alloc_text(PAGE, HumGetDeviceAttributes)
  23. #pragma alloc_text(PAGE, HumGetMsGenreDescriptor)
  24. #endif
  25. resetWorkItemContext *resetWorkItemsList = NULL;
  26. KSPIN_LOCK resetWorkItemsListSpinLock;
  27. PVOID
  28. HumGetSystemAddressForMdlSafe(PMDL MdlAddress)
  29. {
  30. PVOID buf = NULL;
  31. /*
  32. * Can't call MmGetSystemAddressForMdlSafe in a WDM driver,
  33. * so set the MDL_MAPPING_CAN_FAIL bit and check the result
  34. * of the mapping.
  35. */
  36. if (MdlAddress) {
  37. MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL;
  38. buf = MmGetSystemAddressForMdl(MdlAddress);
  39. MdlAddress->MdlFlags &= ~(MDL_MAPPING_CAN_FAIL);
  40. } else {
  41. ASSERT(MdlAddress);
  42. }
  43. return buf;
  44. }
  45. /*
  46. ********************************************************************************
  47. * GetInterruptInputPipeForDevice
  48. ********************************************************************************
  49. *
  50. *
  51. * For composite devices, a device interface can be identified by the unique endpoint
  52. * (i.e. pipe) that it uses for interrupt input.
  53. * This function returns information about that pipe.
  54. *
  55. */
  56. PUSBD_PIPE_INFORMATION GetInterruptInputPipeForDevice(PDEVICE_EXTENSION DeviceExtension)
  57. {
  58. ULONG i;
  59. PUSBD_PIPE_INFORMATION pipeInfo = NULL;
  60. for (i = 0; i < DeviceExtension->Interface->NumberOfPipes; i++){
  61. UCHAR endPtAddr = DeviceExtension->Interface->Pipes[i].EndpointAddress;
  62. USBD_PIPE_TYPE pipeType = DeviceExtension->Interface->Pipes[i].PipeType;
  63. if ((endPtAddr & USB_ENDPOINT_DIRECTION_MASK) && (pipeType == UsbdPipeTypeInterrupt)){
  64. pipeInfo = &DeviceExtension->Interface->Pipes[i];
  65. break;
  66. }
  67. }
  68. return pipeInfo;
  69. }
  70. /*
  71. ********************************************************************************
  72. * GetInterruptOutputPipeForDevice
  73. ********************************************************************************
  74. *
  75. *
  76. * For composite devices, a device interface can be identified by the unique endpoint
  77. * (i.e. pipe) that it uses for interrupt input.
  78. * This function returns information about that pipe.
  79. *
  80. */
  81. PUSBD_PIPE_INFORMATION GetInterruptOutputPipeForDevice(PDEVICE_EXTENSION DeviceExtension)
  82. {
  83. ULONG i;
  84. PUSBD_PIPE_INFORMATION pipeInfo = NULL;
  85. for (i = 0; i < DeviceExtension->Interface->NumberOfPipes; i++){
  86. UCHAR endPtAddr = DeviceExtension->Interface->Pipes[i].EndpointAddress;
  87. USBD_PIPE_TYPE pipeType = DeviceExtension->Interface->Pipes[i].PipeType;
  88. if (!(endPtAddr & USB_ENDPOINT_DIRECTION_MASK) && (pipeType == UsbdPipeTypeInterrupt)){
  89. pipeInfo = &DeviceExtension->Interface->Pipes[i];
  90. break;
  91. }
  92. }
  93. return pipeInfo;
  94. }
  95. /*
  96. ********************************************************************************
  97. * HumGetHidDescriptor
  98. ********************************************************************************
  99. *
  100. * Routine Description:
  101. *
  102. * Free all the allocated resources, etc.
  103. *
  104. * Arguments:
  105. *
  106. * DeviceObject - pointer to a device object.
  107. *
  108. * Return Value:
  109. *
  110. * NT status code.
  111. *
  112. */
  113. NTSTATUS HumGetHidDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  114. {
  115. NTSTATUS ntStatus;
  116. PDEVICE_EXTENSION DeviceExtension;
  117. PIO_STACK_LOCATION IrpStack;
  118. PAGED_CODE();
  119. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  120. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  121. if (DeviceExtension->HidDescriptor.bLength > 0) {
  122. ULONG bytesToCopy = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  123. if (bytesToCopy > DeviceExtension->HidDescriptor.bLength) {
  124. bytesToCopy = DeviceExtension->HidDescriptor.bLength;
  125. }
  126. ASSERT(Irp->UserBuffer);
  127. RtlCopyMemory((PUCHAR)Irp->UserBuffer, (PUCHAR)&DeviceExtension->HidDescriptor, bytesToCopy);
  128. Irp->IoStatus.Information = bytesToCopy;
  129. ntStatus = STATUS_SUCCESS;
  130. }
  131. else {
  132. ASSERT(DeviceExtension->HidDescriptor.bLength > 0);
  133. Irp->IoStatus.Information = 0;
  134. ntStatus = STATUS_UNSUCCESSFUL;
  135. }
  136. ASSERT(NT_SUCCESS(ntStatus));
  137. return ntStatus;
  138. }
  139. /*
  140. ********************************************************************************
  141. * HumGetDeviceAttributes
  142. ********************************************************************************
  143. *
  144. * Routine Description:
  145. *
  146. * Fill in the given struct _HID_DEVICE_ATTRIBUTES
  147. *
  148. * Arguments:
  149. *
  150. * DeviceObject - pointer to a device object.
  151. *
  152. * Return Value:
  153. *
  154. * NT status code.
  155. *
  156. */
  157. NTSTATUS HumGetDeviceAttributes(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  158. {
  159. NTSTATUS ntStatus;
  160. PDEVICE_EXTENSION deviceExtension;
  161. PIO_STACK_LOCATION irpStack;
  162. PHID_DEVICE_ATTRIBUTES deviceAttributes;
  163. PAGED_CODE();
  164. irpStack = IoGetCurrentIrpStackLocation(Irp);
  165. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  166. deviceAttributes = (PHID_DEVICE_ATTRIBUTES) Irp->UserBuffer;
  167. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
  168. sizeof (HID_DEVICE_ATTRIBUTES)){
  169. //
  170. // Report how many bytes were copied
  171. //
  172. Irp->IoStatus.Information = sizeof (HID_DEVICE_ATTRIBUTES);
  173. deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
  174. deviceAttributes->VendorID = deviceExtension->DeviceDescriptor->idVendor;
  175. deviceAttributes->ProductID = deviceExtension->DeviceDescriptor->idProduct;
  176. deviceAttributes->VersionNumber = deviceExtension->DeviceDescriptor->bcdDevice;
  177. ntStatus = STATUS_SUCCESS;
  178. }
  179. else {
  180. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  181. }
  182. ASSERT(NT_SUCCESS(ntStatus));
  183. return ntStatus;
  184. }
  185. /*
  186. ********************************************************************************
  187. * HumGetReportDescriptor
  188. ********************************************************************************
  189. *
  190. *
  191. */
  192. NTSTATUS HumGetReportDescriptor(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  193. {
  194. PDEVICE_EXTENSION DeviceExtension;
  195. PIO_STACK_LOCATION IrpStack;
  196. NTSTATUS ntStatus = STATUS_SUCCESS;
  197. PVOID Report = NULL;
  198. ULONG ReportLength;
  199. ULONG bytesToCopy;
  200. PAGED_CODE();
  201. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  202. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  203. ReportLength = DeviceExtension->HidDescriptor.wReportLength + 64;
  204. if (DeviceExtension->DeviceFlags & DEVICE_FLAGS_HID_1_0_D3_COMPAT_DEVICE) {
  205. PUSBD_PIPE_INFORMATION pipeInfo;
  206. pipeInfo = GetInterruptInputPipeForDevice(DeviceExtension);
  207. if (pipeInfo){
  208. UCHAR deviceInputEndpoint = pipeInfo->EndpointAddress & ~USB_ENDPOINT_DIRECTION_MASK;
  209. ntStatus = HumGetDescriptorRequest(
  210. DeviceObject,
  211. URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT,
  212. DeviceExtension->HidDescriptor.bReportType, // better be HID_REPORT_DESCRIPTOR_TYPE
  213. &Report,
  214. &ReportLength,
  215. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  216. 0, // Specify zero for all hid class descriptors except physical
  217. deviceInputEndpoint);
  218. }
  219. else {
  220. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  221. }
  222. }
  223. else {
  224. ntStatus = HumGetDescriptorRequest(
  225. DeviceObject,
  226. URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE,
  227. DeviceExtension->HidDescriptor.bReportType, // better be HID_REPORT_DESCRIPTOR_TYPE
  228. &Report,
  229. &ReportLength,
  230. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  231. 0, // Specify zero for all hid class descriptors except physical
  232. DeviceExtension->Interface->InterfaceNumber); // Interface number when not requesting string descriptor
  233. }
  234. if (NT_SUCCESS(ntStatus)) {
  235. ASSERT(Report);
  236. bytesToCopy = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  237. if (bytesToCopy > DeviceExtension->HidDescriptor.wReportLength) {
  238. bytesToCopy = DeviceExtension->HidDescriptor.wReportLength;
  239. }
  240. if (bytesToCopy > ReportLength) {
  241. bytesToCopy = ReportLength;
  242. }
  243. ASSERT(Irp->UserBuffer);
  244. RtlCopyMemory((PUCHAR)Irp->UserBuffer, (PUCHAR)Report, bytesToCopy);
  245. //
  246. // Report how many bytes were copied
  247. //
  248. Irp->IoStatus.Information = bytesToCopy;
  249. ExFreePool(Report);
  250. }
  251. return ntStatus;
  252. }
  253. /*
  254. ********************************************************************************
  255. * HumIncrementPendingRequestCount
  256. ********************************************************************************
  257. *
  258. *
  259. */
  260. NTSTATUS HumIncrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension)
  261. {
  262. LONG newRequestCount;
  263. NTSTATUS ntStatus = STATUS_SUCCESS;
  264. newRequestCount = InterlockedIncrement(&DeviceExtension->NumPendingRequests);
  265. //
  266. // Make sure that the device is capable of receiving new requests.
  267. //
  268. if ((DeviceExtension->DeviceState != DEVICE_STATE_RUNNING) &&
  269. (DeviceExtension->DeviceState != DEVICE_STATE_STARTING)){
  270. //
  271. // Device cannot receive any more IOs, decrement back, fail the increment
  272. //
  273. HumDecrementPendingRequestCount(DeviceExtension);
  274. ntStatus = STATUS_NO_SUCH_DEVICE;
  275. }
  276. return ntStatus;
  277. }
  278. /*
  279. ********************************************************************************
  280. * HumDecrementPendingRequestCount
  281. ********************************************************************************
  282. *
  283. *
  284. */
  285. VOID HumDecrementPendingRequestCount(IN PDEVICE_EXTENSION DeviceExtension)
  286. {
  287. LONG PendingCount;
  288. ASSERT(DeviceExtension->NumPendingRequests >= 0);
  289. PendingCount = InterlockedDecrement(&DeviceExtension->NumPendingRequests);
  290. if (PendingCount < 0){
  291. ASSERT(DeviceExtension->DeviceState != DEVICE_STATE_RUNNING);
  292. /*
  293. * The device state is stopping, and the last outstanding request
  294. * has just completed.
  295. *
  296. * Note: RemoveDevice does an extra decrement, so we complete
  297. * the REMOVE IRP on the transition to -1, whether this
  298. * happens in RemoveDevice itself or subsequently while
  299. * RemoveDevice is waiting for this event to fire.
  300. */
  301. KeSetEvent(&DeviceExtension->AllRequestsCompleteEvent, 0, FALSE);
  302. }
  303. }
  304. /*
  305. ********************************************************************************
  306. * HumReadReport
  307. ********************************************************************************
  308. *
  309. * Routine Description:
  310. *
  311. *
  312. * Arguments:
  313. *
  314. * DeviceObject - Pointer to class device object.
  315. *
  316. * IrpStack - Pointer to Interrupt Request Packet.
  317. *
  318. *
  319. * Return Value:
  320. *
  321. * STATUS_SUCCESS, STATUS_UNSUCCESSFUL.
  322. *
  323. *
  324. * Note: this function cannot be pageable because reads/writes
  325. * can be made at dispatch-level.
  326. */
  327. NTSTATUS HumReadReport(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion)
  328. {
  329. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  330. PDEVICE_EXTENSION DeviceExtension;
  331. PIO_STACK_LOCATION IrpStack;
  332. PVOID ReportBuffer;
  333. ULONG ReportTotalSize;
  334. PIO_STACK_LOCATION NextStack;
  335. PURB Urb;
  336. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  337. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  338. ASSERT(Irp->UserBuffer);
  339. ReportBuffer = Irp->UserBuffer;
  340. ReportTotalSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  341. if (ReportTotalSize && ReportBuffer){
  342. PUSBD_PIPE_INFORMATION inputInterruptPipe;
  343. inputInterruptPipe = GetInterruptInputPipeForDevice(DeviceExtension);
  344. if (inputInterruptPipe){
  345. /*
  346. * Allocate a request block for the USB stack.
  347. * (It will be freed by the completion routine).
  348. */
  349. Urb = ExAllocatePoolWithTag( NonPagedPool, sizeof(URB), HIDUSB_TAG);
  350. if (Urb){
  351. //
  352. // Initialize the URB
  353. //
  354. RtlZeroMemory(Urb, sizeof(URB));
  355. Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  356. Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  357. Urb->UrbBulkOrInterruptTransfer.PipeHandle = inputInterruptPipe->PipeHandle;
  358. ASSERT (Urb->UrbBulkOrInterruptTransfer.PipeHandle != NULL);
  359. Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = ReportTotalSize;
  360. Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  361. Urb->UrbBulkOrInterruptTransfer.TransferBuffer = ReportBuffer;
  362. Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
  363. Urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  364. IoSetCompletionRoutine( Irp,
  365. HumReadCompletion,
  366. Urb, // context
  367. TRUE,
  368. TRUE,
  369. TRUE );
  370. NextStack = IoGetNextIrpStackLocation(Irp);
  371. ASSERT(NextStack);
  372. NextStack->Parameters.Others.Argument1 = Urb;
  373. NextStack->MajorFunction = IrpStack->MajorFunction;
  374. NextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  375. NextStack->DeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  376. //
  377. // We need to keep track of the number of pending requests
  378. // so that we can make sure they're all cancelled properly during
  379. // processing of a stop device request.
  380. //
  381. if (NT_SUCCESS(HumIncrementPendingRequestCount(DeviceExtension))){
  382. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  383. *NeedsCompletion = FALSE;
  384. }
  385. else {
  386. ExFreePool(Urb);
  387. ntStatus = STATUS_NO_SUCH_DEVICE;
  388. }
  389. }
  390. else {
  391. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  392. }
  393. }
  394. else {
  395. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  396. }
  397. }
  398. else {
  399. ntStatus = STATUS_INVALID_PARAMETER;
  400. }
  401. return ntStatus;
  402. }
  403. /*
  404. ********************************************************************************
  405. * HumResetInterruptPipe
  406. ********************************************************************************
  407. *
  408. * Reset The usb interrupt pipe.
  409. *
  410. */
  411. NTSTATUS HumResetInterruptPipe(IN PDEVICE_OBJECT DeviceObject)
  412. {
  413. NTSTATUS ntStatus;
  414. PURB urb;
  415. PDEVICE_EXTENSION DeviceExtension;
  416. PUSBD_PIPE_INFORMATION pipeInfo;
  417. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  418. urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), HIDUSB_TAG);
  419. if (urb) {
  420. urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
  421. urb->UrbHeader.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
  422. pipeInfo = GetInterruptInputPipeForDevice(DeviceExtension);
  423. if (pipeInfo) {
  424. urb->UrbPipeRequest.PipeHandle = pipeInfo->PipeHandle;
  425. ntStatus = HumCallUSB(DeviceObject, urb);
  426. } else {
  427. //
  428. // This device doesn't have an interrupt IN pipe.
  429. // Odd, but possible. I.e. USB monitor
  430. //
  431. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  432. }
  433. ExFreePool(urb);
  434. }
  435. else {
  436. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  437. }
  438. return ntStatus;
  439. }
  440. /*
  441. ********************************************************************************
  442. * HumGetPortStatus
  443. ********************************************************************************
  444. *
  445. * Passes a URB to the USBD class driver
  446. *
  447. */
  448. NTSTATUS HumGetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN PULONG PortStatus)
  449. {
  450. NTSTATUS ntStatus;
  451. PIRP irp;
  452. KEVENT event;
  453. IO_STATUS_BLOCK ioStatus;
  454. PIO_STACK_LOCATION nextStack;
  455. *PortStatus = 0;
  456. //
  457. // issue a synchronous request
  458. //
  459. KeInitializeEvent(&event, NotificationEvent, FALSE);
  460. irp = IoBuildDeviceIoControlRequest(
  461. IOCTL_INTERNAL_USB_GET_PORT_STATUS,
  462. GET_NEXT_DEVICE_OBJECT(DeviceObject),
  463. NULL,
  464. 0,
  465. NULL,
  466. 0,
  467. TRUE, /* INTERNAL */
  468. &event,
  469. &ioStatus);
  470. if (!irp) {
  471. return STATUS_INSUFFICIENT_RESOURCES;
  472. }
  473. //
  474. // Call the class driver to perform the operation. If the returned status
  475. // is PENDING, wait for the request to complete.
  476. //
  477. nextStack = IoGetNextIrpStackLocation(irp);
  478. ASSERT(nextStack != NULL);
  479. nextStack->Parameters.Others.Argument1 = PortStatus;
  480. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), irp);
  481. if (ntStatus == STATUS_PENDING) {
  482. ntStatus = KeWaitForSingleObject(
  483. &event,
  484. Suspended,
  485. KernelMode,
  486. FALSE,
  487. NULL);
  488. }
  489. else {
  490. ioStatus.Status = ntStatus;
  491. }
  492. //
  493. // USBD maps the error code for us
  494. //
  495. ntStatus = ioStatus.Status;
  496. return ntStatus;
  497. }
  498. /*
  499. ********************************************************************************
  500. * HumResetParentPort
  501. ********************************************************************************
  502. *
  503. * Sends a RESET_PORT request to our USB PDO.
  504. *
  505. */
  506. NTSTATUS HumResetParentPort(IN PDEVICE_OBJECT DeviceObject)
  507. {
  508. NTSTATUS ntStatus;
  509. PIRP irp;
  510. KEVENT event;
  511. IO_STATUS_BLOCK ioStatus;
  512. //
  513. // issue a synchronous request
  514. //
  515. KeInitializeEvent(&event, NotificationEvent, FALSE);
  516. irp = IoBuildDeviceIoControlRequest(
  517. IOCTL_INTERNAL_USB_RESET_PORT,
  518. GET_NEXT_DEVICE_OBJECT(DeviceObject),
  519. NULL,
  520. 0,
  521. NULL,
  522. 0,
  523. TRUE, /* INTERNAL */
  524. &event,
  525. &ioStatus);
  526. if (!irp) {
  527. return STATUS_INSUFFICIENT_RESOURCES;
  528. }
  529. //
  530. // Call the class driver to perform the operation. If the returned status
  531. // is PENDING, wait for the request to complete.
  532. //
  533. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), irp);
  534. if (ntStatus == STATUS_PENDING) {
  535. ntStatus = KeWaitForSingleObject(
  536. &event,
  537. Suspended,
  538. KernelMode,
  539. FALSE,
  540. NULL);
  541. }
  542. else {
  543. ioStatus.Status = ntStatus;
  544. }
  545. //
  546. // USBD maps the error code for us
  547. //
  548. ntStatus = ioStatus.Status;
  549. return ntStatus;
  550. }
  551. /*
  552. ********************************************************************************
  553. * HumResetWorkItem
  554. ********************************************************************************
  555. *
  556. * Resets the interrupt pipe after a read error is encountered.
  557. *
  558. */
  559. NTSTATUS HumResetWorkItem(IN PDEVICE_OBJECT deviceObject, IN PVOID Context)
  560. {
  561. resetWorkItemContext *resetWorkItemObj;
  562. PDEVICE_EXTENSION DeviceExtension;
  563. NTSTATUS ntStatus;
  564. ULONG portStatus;
  565. /*
  566. * Get the information out of the resetWorkItemContext and free it.
  567. */
  568. resetWorkItemObj = (resetWorkItemContext *)Context;
  569. ASSERT(resetWorkItemObj);
  570. ASSERT(resetWorkItemObj->sig == RESET_WORK_ITEM_CONTEXT_SIG);
  571. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(resetWorkItemObj->deviceObject);
  572. ntStatus = HumIncrementPendingRequestCount(DeviceExtension);
  573. if (NT_SUCCESS(ntStatus)){
  574. //
  575. // Check the port state, if it is disabled we will need
  576. // to re-enable it
  577. //
  578. ntStatus = HumGetPortStatus(resetWorkItemObj->deviceObject, &portStatus);
  579. if (NT_SUCCESS(ntStatus)){
  580. if (portStatus & USBD_PORT_CONNECTED){
  581. /*
  582. * Device is still present, attempt reset.
  583. *
  584. * Note: Resetting the port will close the endpoint(s).
  585. * So before resetting the port, we must make sure
  586. * that there is no pending IO.
  587. */
  588. DBGPRINT(1,("Attempting port reset"));
  589. ntStatus = HumAbortPendingRequests(resetWorkItemObj->deviceObject);
  590. if (NT_SUCCESS(ntStatus)){
  591. HumResetParentPort(resetWorkItemObj->deviceObject);
  592. }
  593. else {
  594. DBGWARN(("HumResetWorkItem: HumAbortPendingRequests failed with status %xh.", ntStatus));
  595. }
  596. }
  597. //
  598. // now attempt to reset the stalled pipe, this will clear the stall
  599. // on the device as well.
  600. //
  601. /*
  602. * This call does not close the endpoint, so it should be ok
  603. * to make this call whether or not we succeeded in aborting
  604. * all pending IO.
  605. */
  606. if (NT_SUCCESS(ntStatus)) {
  607. ntStatus = HumResetInterruptPipe(resetWorkItemObj->deviceObject);
  608. }
  609. }
  610. else {
  611. DBGWARN(("HumResetWorkItem: HumGetPortStatus failed with status %xh.", ntStatus));
  612. }
  613. HumDecrementPendingRequestCount(DeviceExtension);
  614. }
  615. /*
  616. * Clear the ResetWorkItem ptr in the device extension
  617. * AFTER resetting the pipe so we don't end up with
  618. * two threads resetting the same pipe at the same time.
  619. */
  620. (VOID)InterlockedExchange((PVOID) &DeviceExtension->ResetWorkItem, 0);
  621. /*
  622. * The IRP that returned the error which prompted us to do this reset
  623. * is still owned by HIDUSB because we returned
  624. * STATUS_MORE_PROCESSING_REQUIRED in the completion routine.
  625. * Now that the hub is reset, complete this failed IRP.
  626. */
  627. DBGPRINT(1,("Completing IRP %ph following port reset", resetWorkItemObj->irpToComplete));
  628. IoCompleteRequest(resetWorkItemObj->irpToComplete, IO_NO_INCREMENT);
  629. IoFreeWorkItem(resetWorkItemObj->ioWorkItem);
  630. ExFreePool(resetWorkItemObj);
  631. /*
  632. * Balance the increment from when we queued the workItem.
  633. */
  634. HumDecrementPendingRequestCount(DeviceExtension);
  635. return ntStatus;
  636. }
  637. /*
  638. ********************************************************************************
  639. * HumReadCompletion
  640. ********************************************************************************
  641. *
  642. *
  643. */
  644. NTSTATUS HumReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  645. {
  646. NTSTATUS ntStatus;
  647. NTSTATUS result = STATUS_SUCCESS;
  648. PURB urb;
  649. ULONG bytesRead;
  650. PDEVICE_EXTENSION deviceExtension;
  651. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  652. //
  653. // We passed a pointer to the URB as our context, get it now.
  654. //
  655. urb = (PURB)Context;
  656. ASSERT(urb);
  657. ntStatus = Irp->IoStatus.Status;
  658. if (NT_SUCCESS(ntStatus)){
  659. //
  660. // Get the bytes read and store in the status block
  661. //
  662. bytesRead = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  663. Irp->IoStatus.Information = bytesRead;
  664. }
  665. else if (ntStatus == STATUS_CANCELLED){
  666. /*
  667. * The IRP was cancelled, which means that the device is probably getting removed.
  668. */
  669. DBGPRINT(2,("Read irp %p cancelled ...", Irp));
  670. ASSERT(!Irp->CancelRoutine);
  671. }
  672. else if (ntStatus != STATUS_DEVICE_NOT_CONNECTED) {
  673. DBGWARN(("Read irp %ph failed with status %xh -- scheduling RESET ...", Irp, ntStatus));
  674. if (NT_SUCCESS(HumIncrementPendingRequestCount(deviceExtension))){
  675. resetWorkItemContext *resetWorkItemObj;
  676. resetWorkItemObj = ExAllocatePoolWithTag(NonPagedPool, sizeof(resetWorkItemContext), HIDUSB_TAG);
  677. if (resetWorkItemObj){
  678. PVOID comperand = NULL;
  679. resetWorkItemObj->ioWorkItem = IoAllocateWorkItem(deviceExtension->functionalDeviceObject);
  680. if (resetWorkItemObj->ioWorkItem){
  681. comperand = InterlockedCompareExchangePointer (
  682. &deviceExtension->ResetWorkItem, // dest
  683. &resetWorkItemObj->ioWorkItem, // exchange
  684. comperand); // comperand
  685. if (!comperand){
  686. resetWorkItemObj->sig = RESET_WORK_ITEM_CONTEXT_SIG;
  687. resetWorkItemObj->irpToComplete = Irp;
  688. resetWorkItemObj->deviceObject = DeviceObject;
  689. IoQueueWorkItem( resetWorkItemObj->ioWorkItem,
  690. HumResetWorkItem,
  691. DelayedWorkQueue,
  692. resetWorkItemObj);
  693. /*
  694. * Return STATUS_MORE_PROCESSING_REQUIRED so NTKERN doesn't
  695. * keep processing the IRP.
  696. */
  697. result = STATUS_MORE_PROCESSING_REQUIRED;
  698. }
  699. else {
  700. //
  701. // We already have a reset op queued.
  702. //
  703. IoFreeWorkItem(resetWorkItemObj->ioWorkItem);
  704. ExFreePool(resetWorkItemObj);
  705. HumDecrementPendingRequestCount(deviceExtension);
  706. }
  707. }
  708. else {
  709. ExFreePool(resetWorkItemObj);
  710. HumDecrementPendingRequestCount(deviceExtension);
  711. }
  712. }
  713. else {
  714. HumDecrementPendingRequestCount(deviceExtension);
  715. }
  716. }
  717. }
  718. //
  719. // Don't need the URB anymore
  720. //
  721. ExFreePool(urb);
  722. /*
  723. * Balance the increment we did when we issued the read.
  724. */
  725. HumDecrementPendingRequestCount(deviceExtension);
  726. /*
  727. * If the lower driver returned PENDING, mark our stack location as
  728. * pending also. This prevents the IRP's thread from being freed if
  729. * the client's call returns pending.
  730. */
  731. if (Irp->PendingReturned){
  732. IoMarkIrpPending(Irp);
  733. }
  734. return result;
  735. }
  736. /*
  737. ********************************************************************************
  738. * HumWriteReport
  739. ********************************************************************************
  740. *
  741. * Routine Description:
  742. *
  743. *
  744. * Arguments:
  745. *
  746. * DeviceObject - Pointer to class device object.
  747. *
  748. * IrpStack - Pointer to Interrupt Request Packet.
  749. *
  750. *
  751. * Return Value:
  752. *
  753. * STATUS_SUCCESS, STATUS_UNSUCCESSFUL.
  754. *
  755. *
  756. * Note: this function cannot be pageable because reads/writes
  757. * can be made at dispatch-level.
  758. */
  759. NTSTATUS HumWriteReport(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion)
  760. {
  761. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  762. PDEVICE_EXTENSION DeviceExtension;
  763. PIO_STACK_LOCATION currentIrpStack, nextIrpStack;
  764. PURB Urb;
  765. PHID_XFER_PACKET hidWritePacket;
  766. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  767. currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  768. nextIrpStack = IoGetNextIrpStackLocation(Irp);
  769. hidWritePacket = (PHID_XFER_PACKET)Irp->UserBuffer;
  770. if (hidWritePacket){
  771. if (hidWritePacket->reportBuffer && hidWritePacket->reportBufferLen){
  772. PUSBD_PIPE_INFORMATION interruptPipe;
  773. Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), HIDUSB_TAG);
  774. if (Urb){
  775. RtlZeroMemory(Urb, sizeof( URB ));
  776. if (DeviceExtension->DeviceFlags & DEVICE_FLAGS_HID_1_0_D3_COMPAT_DEVICE) {
  777. /*
  778. * This is an old device which follows the pre-final spec.
  779. * We use the endpoint address of the input pipe
  780. * with the direction bit cleared.
  781. */
  782. #if DBG
  783. interruptPipe = GetInterruptOutputPipeForDevice(DeviceExtension);
  784. ASSERT(!interruptPipe);
  785. #endif
  786. interruptPipe = GetInterruptInputPipeForDevice(DeviceExtension);
  787. if (interruptPipe){
  788. UCHAR deviceInputEndpoint = interruptPipe->EndpointAddress & ~USB_ENDPOINT_DIRECTION_MASK;
  789. /*
  790. * A control operation consists of 3 stages: setup, data, and status.
  791. * In the setup stage the device receives an 8-byte frame comprised of
  792. * the following fields of a _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure:
  793. * See section 7.2 in the USB HID specification for how to fill out these fields.
  794. *
  795. * UCHAR RequestTypeReservedBits;
  796. * UCHAR Request;
  797. * USHORT Value;
  798. * USHORT Index;
  799. *
  800. */
  801. HumBuildClassRequest(
  802. Urb,
  803. URB_FUNCTION_CLASS_ENDPOINT,
  804. 0, // transferFlags,
  805. hidWritePacket->reportBuffer,
  806. hidWritePacket->reportBufferLen,
  807. 0x22, // requestType= Set_Report Request,
  808. 0x09, // request=SET_REPORT,
  809. (0x0200 + hidWritePacket->reportId), // value= reportType 'output' &reportId,
  810. deviceInputEndpoint, // index= interrupt input endpoint for this device
  811. hidWritePacket->reportBufferLen // reqLength (not used)
  812. );
  813. }
  814. else {
  815. ntStatus = STATUS_DATA_ERROR;
  816. }
  817. }
  818. else {
  819. interruptPipe = GetInterruptOutputPipeForDevice(DeviceExtension);
  820. if (interruptPipe){
  821. /*
  822. * This device has an interrupt output pipe.
  823. */
  824. Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  825. Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  826. ASSERT(interruptPipe->PipeHandle);
  827. Urb->UrbBulkOrInterruptTransfer.PipeHandle = interruptPipe->PipeHandle;
  828. Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = hidWritePacket->reportBufferLen;
  829. Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  830. Urb->UrbBulkOrInterruptTransfer.TransferBuffer = hidWritePacket->reportBuffer;
  831. Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT;
  832. Urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  833. }
  834. else {
  835. /*
  836. * This device does not have an interrupt output pipe.
  837. * Send the report on the control pipe.
  838. */
  839. /*
  840. * A control operation consists of 3 stages: setup, data, and status.
  841. * In the setup stage the device receives an 8-byte frame comprised of
  842. * the following fields of a _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure:
  843. * See section 7.2 in the USB HID specification for how to fill out these fields.
  844. *
  845. * UCHAR RequestTypeReservedBits;
  846. * UCHAR Request;
  847. * USHORT Value;
  848. * USHORT Index;
  849. *
  850. */
  851. HumBuildClassRequest(
  852. Urb,
  853. URB_FUNCTION_CLASS_INTERFACE,
  854. 0, // transferFlags,
  855. hidWritePacket->reportBuffer,
  856. hidWritePacket->reportBufferLen,
  857. 0x22, // requestType= Set_Report Request,
  858. 0x09, // request=SET_REPORT,
  859. (0x0200 + hidWritePacket->reportId), // value= reportType 'output' &reportId,
  860. DeviceExtension->Interface->InterfaceNumber, // index= interrupt input interface for this device
  861. hidWritePacket->reportBufferLen // reqLength (not used)
  862. );
  863. }
  864. }
  865. if (ntStatus == STATUS_UNSUCCESSFUL) {
  866. IoSetCompletionRoutine(Irp, HumWriteCompletion, Urb, TRUE, TRUE, TRUE);
  867. nextIrpStack->Parameters.Others.Argument1 = Urb;
  868. nextIrpStack->MajorFunction = currentIrpStack->MajorFunction;
  869. nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  870. nextIrpStack->DeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  871. //
  872. // We need to keep track of the number of pending requests
  873. // so that we can make sure they're all cancelled properly during
  874. // processing of a stop device request.
  875. //
  876. if (NT_SUCCESS(HumIncrementPendingRequestCount( DeviceExtension )) ) {
  877. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  878. *NeedsCompletion = FALSE;
  879. } else {
  880. ExFreePool(Urb);
  881. ntStatus = STATUS_NO_SUCH_DEVICE;
  882. }
  883. } else {
  884. ExFreePool(Urb);
  885. }
  886. }
  887. else {
  888. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  889. }
  890. } else {
  891. ntStatus = STATUS_DATA_ERROR;
  892. }
  893. }
  894. else {
  895. ntStatus = STATUS_DATA_ERROR;
  896. }
  897. return ntStatus;
  898. }
  899. /*
  900. ********************************************************************************
  901. * HumWriteCompletion
  902. ********************************************************************************
  903. *
  904. *
  905. */
  906. NTSTATUS HumWriteCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  907. {
  908. PURB urb = (PURB)Context;
  909. PDEVICE_EXTENSION deviceExtension;
  910. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  911. ASSERT(urb);
  912. if (NT_SUCCESS(Irp->IoStatus.Status)){
  913. //
  914. // Record the number of bytes written.
  915. //
  916. Irp->IoStatus.Information = (ULONG)urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  917. }
  918. ExFreePool(urb);
  919. /*
  920. * If the lower driver returned PENDING, mark our stack location as
  921. * pending also. This prevents the IRP's thread from being freed if
  922. * the client's call returns pending.
  923. */
  924. if (Irp->PendingReturned){
  925. IoMarkIrpPending(Irp);
  926. }
  927. /*
  928. * Balance the increment we did when we issued the write.
  929. */
  930. HumDecrementPendingRequestCount(deviceExtension);
  931. return STATUS_SUCCESS;
  932. }
  933. /*
  934. ********************************************************************************
  935. * HumGetPhysicalDescriptor
  936. ********************************************************************************
  937. *
  938. *
  939. */
  940. NTSTATUS HumGetPhysicalDescriptor( IN PDEVICE_OBJECT DeviceObject,
  941. IN PIRP Irp,
  942. BOOLEAN *NeedsCompletion)
  943. {
  944. NTSTATUS ntStatus;
  945. PIO_STACK_LOCATION IrpStack;
  946. ULONG bufferSize;
  947. PAGED_CODE();
  948. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  949. /*
  950. * Check buffer size before trying to use Irp->MdlAddress.
  951. */
  952. bufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  953. if (bufferSize){
  954. PVOID buffer = HumGetSystemAddressForMdlSafe(Irp->MdlAddress);
  955. if (buffer){
  956. ntStatus = HumGetDescriptorRequest(DeviceObject,
  957. URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
  958. HID_PHYSICAL_DESCRIPTOR_TYPE,
  959. &buffer,
  960. &bufferSize,
  961. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  962. 0, // Index. NOTE: will only get first physical descriptor set
  963. 0);
  964. }
  965. else {
  966. ntStatus = STATUS_INVALID_USER_BUFFER;
  967. }
  968. }
  969. else {
  970. ntStatus = STATUS_INVALID_USER_BUFFER;
  971. }
  972. return ntStatus;
  973. }
  974. /*
  975. ********************************************************************************
  976. * HumGetStringDescriptor
  977. ********************************************************************************
  978. *
  979. *
  980. */
  981. NTSTATUS HumGetStringDescriptor( IN PDEVICE_OBJECT DeviceObject,
  982. IN PIRP Irp)
  983. {
  984. NTSTATUS ntStatus = STATUS_PENDING;
  985. PDEVICE_EXTENSION DeviceExtension;
  986. PIO_STACK_LOCATION IrpStack;
  987. PVOID buffer;
  988. ULONG bufferSize;
  989. BOOLEAN isIndexedString;
  990. PAGED_CODE();
  991. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  992. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  993. switch (IrpStack->Parameters.DeviceIoControl.IoControlCode){
  994. case IOCTL_HID_GET_INDEXED_STRING:
  995. /*
  996. * IOCTL_HID_GET_INDEXED_STRING uses buffering method
  997. * METHOD_OUT_DIRECT, which passes the buffer in the MDL.
  998. *
  999. * The MDL is built by the kernel for any non-zero-length
  1000. * buffer passed in by the client. So we don't need to
  1001. * verify the integrity of the MDL, but we do have to check
  1002. * that it's non-NULL.
  1003. */
  1004. buffer = HumGetSystemAddressForMdlSafe(Irp->MdlAddress);
  1005. isIndexedString = TRUE;
  1006. break;
  1007. case IOCTL_HID_GET_STRING:
  1008. /*
  1009. * IOCTL_HID_GET_STRING uses buffering method
  1010. * METHOD_NEITHER, which passes the buffer in Irp->UserBuffer.
  1011. */
  1012. buffer = Irp->UserBuffer;
  1013. isIndexedString = FALSE;
  1014. break;
  1015. default:
  1016. ASSERT(0);
  1017. buffer = NULL;
  1018. break;
  1019. }
  1020. bufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1021. if (buffer && bufferSize){
  1022. /*
  1023. * String id and language id are in Type3InputBuffer field
  1024. * of IRP stack location.
  1025. *
  1026. * Note: the string ID should be identical to the string's
  1027. * field offset given in Chapter 9 of the USB spec.
  1028. */
  1029. ULONG languageId = (PtrToUlong(IrpStack->Parameters.DeviceIoControl.Type3InputBuffer)) >> 16;
  1030. ULONG stringIndex;
  1031. if (isIndexedString){
  1032. stringIndex = (PtrToUlong(IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) & 0x0ffff);
  1033. }
  1034. else {
  1035. ULONG stringId = (PtrToUlong(IrpStack->Parameters.DeviceIoControl.Type3InputBuffer) & 0x0ffff);
  1036. switch (stringId){
  1037. case HID_STRING_ID_IMANUFACTURER:
  1038. stringIndex = DeviceExtension->DeviceDescriptor->iManufacturer;
  1039. break;
  1040. case HID_STRING_ID_IPRODUCT:
  1041. stringIndex = DeviceExtension->DeviceDescriptor->iProduct;
  1042. break;
  1043. case HID_STRING_ID_ISERIALNUMBER:
  1044. stringIndex = DeviceExtension->DeviceDescriptor->iSerialNumber;
  1045. break;
  1046. default:
  1047. stringIndex = -1;
  1048. break;
  1049. }
  1050. }
  1051. if (stringIndex == -1){
  1052. ntStatus = STATUS_INVALID_PARAMETER;
  1053. }
  1054. else {
  1055. PWCHAR tmpDescPtr;
  1056. ULONG tmpDescPtrLen;
  1057. /*
  1058. * USB descriptors begin with an extra two bytes for length and type.
  1059. * So we need to allocate a slightly larger buffer.
  1060. */
  1061. tmpDescPtrLen = bufferSize + 2;
  1062. tmpDescPtr = ExAllocatePoolWithTag(NonPagedPool, tmpDescPtrLen, HIDUSB_TAG);
  1063. if (tmpDescPtr){
  1064. ntStatus = HumGetDescriptorRequest(DeviceObject,
  1065. URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
  1066. USB_STRING_DESCRIPTOR_TYPE,
  1067. &tmpDescPtr,
  1068. &tmpDescPtrLen,
  1069. sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1070. stringIndex,
  1071. languageId); // LanguageID,
  1072. if (NT_SUCCESS(ntStatus)){
  1073. /*
  1074. * USB descriptors always begin with two bytes for the length
  1075. * and type. Remove these.
  1076. */
  1077. PWCHAR descPtr = (PWCHAR)buffer;
  1078. ULONG descLen = (ULONG)(((PCHAR)tmpDescPtr)[0]);
  1079. WCHAR unicodeNULL = UNICODE_NULL;
  1080. if (descLen <= bufferSize+2){
  1081. ULONG i;
  1082. for (i = 1; (i < descLen/sizeof(WCHAR)) && (i-1 < bufferSize/sizeof(WCHAR)); i++){
  1083. RtlCopyMemory(&descPtr[i-1], &tmpDescPtr[i], sizeof(WCHAR));
  1084. }
  1085. if (i-1 < bufferSize/sizeof(WCHAR)){
  1086. RtlCopyMemory(&descPtr[i-1], &unicodeNULL, sizeof(WCHAR));
  1087. }
  1088. }
  1089. else {
  1090. /*
  1091. * Compensate for a device bug which causes
  1092. * a partial string to be returned if the buffer is too small.
  1093. */
  1094. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  1095. }
  1096. }
  1097. ExFreePool(tmpDescPtr);
  1098. }
  1099. else {
  1100. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1101. }
  1102. }
  1103. }
  1104. else {
  1105. ntStatus = STATUS_INVALID_USER_BUFFER;
  1106. }
  1107. return ntStatus;
  1108. }
  1109. /*
  1110. ********************************************************************************
  1111. * HumGetSetReportCompletion
  1112. ********************************************************************************
  1113. *
  1114. *
  1115. */
  1116. NTSTATUS HumGetSetReportCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  1117. {
  1118. PURB urb = (PURB)Context;
  1119. PDEVICE_EXTENSION deviceExtension;
  1120. deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  1121. if (NT_SUCCESS(Irp->IoStatus.Status)){
  1122. /*
  1123. * Record the number of bytes written.
  1124. */
  1125. Irp->IoStatus.Information = (ULONG)urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  1126. }
  1127. ExFreePool(urb);
  1128. /*
  1129. * If the lower driver returned PENDING, mark our stack location as
  1130. * pending also. This prevents the IRP's thread from being freed if
  1131. * the client's call returns pending.
  1132. */
  1133. if (Irp->PendingReturned){
  1134. IoMarkIrpPending(Irp);
  1135. }
  1136. /*
  1137. * Balance the increment we did when we issued this IRP.
  1138. */
  1139. HumDecrementPendingRequestCount(deviceExtension);
  1140. return STATUS_SUCCESS;
  1141. }
  1142. /*
  1143. ********************************************************************************
  1144. * HumGetSetReport
  1145. ********************************************************************************
  1146. *
  1147. *
  1148. */
  1149. NTSTATUS HumGetSetReport(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN *NeedsCompletion)
  1150. {
  1151. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  1152. PDEVICE_EXTENSION DeviceExtension;
  1153. PIO_STACK_LOCATION currentIrpStack, nextIrpStack;
  1154. PHID_XFER_PACKET reportPacket;
  1155. ULONG transferFlags;
  1156. UCHAR request;
  1157. USHORT value;
  1158. PIO_STACK_LOCATION irpSp;
  1159. PAGED_CODE();
  1160. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1161. switch (irpSp->Parameters.DeviceIoControl.IoControlCode){
  1162. case IOCTL_HID_GET_INPUT_REPORT:
  1163. transferFlags = USBD_TRANSFER_DIRECTION_IN;
  1164. request = 0x01;
  1165. value = 0x0100;
  1166. break;
  1167. case IOCTL_HID_SET_OUTPUT_REPORT:
  1168. transferFlags = USBD_TRANSFER_DIRECTION_OUT;
  1169. request = 0x09;
  1170. value = 0x0200;
  1171. break;
  1172. case IOCTL_HID_SET_FEATURE:
  1173. transferFlags = USBD_TRANSFER_DIRECTION_OUT;
  1174. request = 0x09;
  1175. value = 0x0300;
  1176. break;
  1177. case IOCTL_HID_GET_FEATURE:
  1178. transferFlags = USBD_TRANSFER_DIRECTION_IN;
  1179. request = 0x01;
  1180. value = 0x0300;
  1181. break;
  1182. default:
  1183. DBGBREAK;
  1184. }
  1185. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  1186. currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1187. nextIrpStack = IoGetNextIrpStackLocation(Irp);
  1188. reportPacket = Irp->UserBuffer;
  1189. if (reportPacket && reportPacket->reportBuffer && reportPacket->reportBufferLen){
  1190. PURB Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(URB), HIDUSB_TAG);
  1191. if (Urb){
  1192. RtlZeroMemory(Urb, sizeof( URB ));
  1193. value += reportPacket->reportId;
  1194. /*
  1195. * A control operation consists of 3 stages: setup, data, and status.
  1196. * In the setup stage the device receives an 8-byte frame comprised of
  1197. * the following fields of a _URB_CONTROL_VENDOR_OR_CLASS_REQUEST structure:
  1198. * See section 7.2 in the USB HID specification for how to fill out these fields.
  1199. *
  1200. * UCHAR RequestTypeReservedBits;
  1201. * UCHAR Request;
  1202. * USHORT Value;
  1203. * USHORT Index;
  1204. *
  1205. */
  1206. if (DeviceExtension->DeviceFlags & DEVICE_FLAGS_HID_1_0_D3_COMPAT_DEVICE) {
  1207. HumBuildClassRequest(
  1208. Urb,
  1209. URB_FUNCTION_CLASS_ENDPOINT,
  1210. transferFlags,
  1211. reportPacket->reportBuffer,
  1212. reportPacket->reportBufferLen,
  1213. 0x22, // requestType= Set_Report Request,
  1214. request,
  1215. value, // value= reportType 'report' &reportId,
  1216. 1, // index= endpoint 1,
  1217. hidWritePacket->reportBufferLen // reqLength (not used)
  1218. );
  1219. }
  1220. else {
  1221. HumBuildClassRequest(
  1222. Urb,
  1223. URB_FUNCTION_CLASS_INTERFACE,
  1224. transferFlags,
  1225. reportPacket->reportBuffer,
  1226. reportPacket->reportBufferLen,
  1227. 0x22, // requestType= Set_Report Request,
  1228. request,
  1229. value, // value= reportType 'report' &reportId,
  1230. DeviceExtension->Interface->InterfaceNumber, // index= interface,
  1231. hidWritePacket->reportBufferLen // reqLength (not used)
  1232. );
  1233. }
  1234. IoSetCompletionRoutine(Irp, HumGetSetReportCompletion, Urb, TRUE, TRUE, TRUE);
  1235. nextIrpStack->Parameters.Others.Argument1 = Urb;
  1236. nextIrpStack->MajorFunction = currentIrpStack->MajorFunction;
  1237. nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  1238. nextIrpStack->DeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  1239. //
  1240. // We need to keep track of the number of pending requests
  1241. // so that we can make sure they're all cancelled properly during
  1242. // processing of a stop device request.
  1243. //
  1244. if (NT_SUCCESS(HumIncrementPendingRequestCount( DeviceExtension )) ) {
  1245. ntStatus = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  1246. *NeedsCompletion = FALSE;
  1247. } else {
  1248. ExFreePool(Urb);
  1249. ntStatus = STATUS_NO_SUCH_DEVICE;
  1250. }
  1251. }
  1252. else {
  1253. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1254. }
  1255. }
  1256. else {
  1257. ntStatus = STATUS_DATA_ERROR;
  1258. }
  1259. return ntStatus;
  1260. }
  1261. /*
  1262. ********************************************************************************
  1263. * HumGetMsGenreDescriptor
  1264. ********************************************************************************
  1265. *
  1266. *
  1267. */
  1268. NTSTATUS HumGetMsGenreDescriptor(
  1269. IN PDEVICE_OBJECT DeviceObject,
  1270. IN PIRP Irp)
  1271. {
  1272. NTSTATUS ntStatus;
  1273. PIO_STACK_LOCATION IrpStack;
  1274. ULONG bufferSize;
  1275. PDEVICE_EXTENSION DeviceExtension;
  1276. PAGED_CODE();
  1277. DeviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(DeviceObject);
  1278. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1279. DBGOUT(("Received request for genre descriptor in hidusb"))
  1280. /*
  1281. * Check buffer size before trying to use Irp->MdlAddress.
  1282. */
  1283. bufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1284. if (bufferSize){
  1285. PVOID buffer = HumGetSystemAddressForMdlSafe(Irp->MdlAddress);
  1286. if (buffer){
  1287. PURB Urb;
  1288. //
  1289. // Allocate Descriptor buffer
  1290. //
  1291. Urb = ExAllocatePoolWithTag(NonPagedPool,
  1292. sizeof(struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST),
  1293. HIDUSB_TAG);
  1294. if (!Urb){
  1295. return STATUS_INSUFFICIENT_RESOURCES;
  1296. }
  1297. RtlZeroMemory(Urb, sizeof(struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST));
  1298. RtlZeroMemory(buffer, bufferSize);
  1299. HumBuildOsFeatureDescriptorRequest(Urb,
  1300. sizeof(struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST),
  1301. DeviceExtension->Interface->InterfaceNumber,
  1302. MS_GENRE_DESCRIPTOR_INDEX,
  1303. buffer,
  1304. NULL,
  1305. bufferSize,
  1306. NULL);
  1307. DBGOUT(("Sending os feature request to usbhub"))
  1308. ntStatus = HumCallUSB(DeviceObject, Urb);
  1309. if (NT_SUCCESS(ntStatus)){
  1310. if (USBD_SUCCESS(Urb->UrbHeader.Status)){
  1311. DBGOUT(("Genre descriptor request successful!"))
  1312. ntStatus = STATUS_SUCCESS;
  1313. } else {
  1314. DBGOUT(("Genre descriptor request unsuccessful"))
  1315. ntStatus = STATUS_UNSUCCESSFUL;
  1316. }
  1317. }
  1318. ExFreePool(Urb);
  1319. }
  1320. else {
  1321. ntStatus = STATUS_INVALID_USER_BUFFER;
  1322. }
  1323. }
  1324. else {
  1325. ntStatus = STATUS_INVALID_USER_BUFFER;
  1326. }
  1327. return ntStatus;
  1328. }
  1329. NTSTATUS
  1330. HumSendIdleNotificationRequest(
  1331. PDEVICE_OBJECT DeviceObject,
  1332. PIRP Irp,
  1333. BOOLEAN *NeedsCompletion
  1334. )
  1335. {
  1336. PIO_STACK_LOCATION current, next;
  1337. current = IoGetCurrentIrpStackLocation(Irp);
  1338. next = IoGetNextIrpStackLocation(Irp);
  1339. if (current->Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)) {
  1340. return STATUS_BUFFER_TOO_SMALL;
  1341. }
  1342. ASSERT(sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) == sizeof(USB_IDLE_CALLBACK_INFO));
  1343. if (sizeof(HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO) != sizeof(USB_IDLE_CALLBACK_INFO)) {
  1344. return STATUS_INFO_LENGTH_MISMATCH;
  1345. }
  1346. *NeedsCompletion = FALSE;
  1347. next->MajorFunction = current->MajorFunction;
  1348. next->Parameters.DeviceIoControl.InputBufferLength =
  1349. current->Parameters.DeviceIoControl.InputBufferLength;
  1350. next->Parameters.DeviceIoControl.Type3InputBuffer =
  1351. current->Parameters.DeviceIoControl.Type3InputBuffer;
  1352. next->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
  1353. next->DeviceObject = GET_NEXT_DEVICE_OBJECT(DeviceObject);
  1354. return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
  1355. }