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.

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