[HIDCLASS] Implement IOCTL_HID_GET_FEATURE/IOCTL_HID_SET_FEATURE
authorHervé Poussineau <hpoussin@reactos.org>
Fri, 19 Apr 2019 20:40:32 +0000 (22:40 +0200)
committerHervé Poussineau <hpoussin@reactos.org>
Fri, 19 Apr 2019 20:46:03 +0000 (22:46 +0200)
drivers/hid/hidclass/hidclass.c
drivers/hid/hidclass/pdo.c
drivers/hid/hidclass/precomp.h

index 6d21f14..30d6f8d 100644 (file)
@@ -934,6 +934,120 @@ HidClass_DeviceControl(
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return STATUS_SUCCESS;
         }
             IoCompleteRequest(Irp, IO_NO_INCREMENT);
             return STATUS_SUCCESS;
         }
+        case IOCTL_HID_GET_FEATURE:
+        {
+            PIRP SubIrp;
+            KEVENT Event;
+            IO_STATUS_BLOCK IoStatusBlock;
+            HID_XFER_PACKET XferPacket;
+            NTSTATUS Status;
+            PHIDP_REPORT_IDS ReportDescription;
+
+            if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
+            {
+                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_INVALID_PARAMETER;
+            }
+            ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
+            if (!ReportDescription || IoStack->Parameters.DeviceIoControl.OutputBufferLength < ReportDescription->FeatureLength)
+            {
+                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_INVALID_PARAMETER;
+            }
+
+            RtlZeroMemory(&XferPacket, sizeof(XferPacket));
+            XferPacket.reportBufferLen = ReportDescription->FeatureLength;
+            XferPacket.reportBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            XferPacket.reportId = ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0];
+            if (!XferPacket.reportBuffer)
+            {
+                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            SubIrp = IoBuildDeviceIoControlRequest(
+                IOCTL_HID_GET_FEATURE,
+                CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
+                NULL, 0,
+                NULL, 0,
+                TRUE,
+                &Event,
+                &IoStatusBlock);
+            if (!SubIrp)
+            {
+                Irp->IoStatus.Status = STATUS_NO_MEMORY;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_NOT_IMPLEMENTED;
+            }
+            SubIrp->UserBuffer = &XferPacket;
+            KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+            Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
+            if (Status == STATUS_PENDING)
+            {
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = IoStatusBlock.Status;
+            }
+            Irp->IoStatus.Status = Status;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return Status;
+        }
+        case IOCTL_HID_SET_FEATURE:
+        {
+            PIRP SubIrp;
+            KEVENT Event;
+            IO_STATUS_BLOCK IoStatusBlock;
+            HID_XFER_PACKET XferPacket;
+            NTSTATUS Status;
+            PHIDP_REPORT_IDS ReportDescription;
+
+            if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
+            {
+                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_INVALID_PARAMETER;
+            }
+            ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
+            if (!ReportDescription || IoStack->Parameters.DeviceIoControl.InputBufferLength < ReportDescription->FeatureLength)
+            {
+                Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_INVALID_PARAMETER;
+            }
+
+            RtlZeroMemory(&XferPacket, sizeof(XferPacket));
+            XferPacket.reportBufferLen = ReportDescription->FeatureLength;
+            XferPacket.reportBuffer = Irp->AssociatedIrp.SystemBuffer;
+            XferPacket.reportId = XferPacket.reportBuffer[0];
+
+            SubIrp = IoBuildDeviceIoControlRequest(
+                IOCTL_HID_SET_FEATURE,
+                CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
+                NULL, 0,
+                NULL, 0,
+                TRUE,
+                &Event,
+                &IoStatusBlock);
+            if (!SubIrp)
+            {
+                Irp->IoStatus.Status = STATUS_NO_MEMORY;
+                IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                return STATUS_NOT_IMPLEMENTED;
+            }
+            SubIrp->UserBuffer = &XferPacket;
+            KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+            Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
+            if (Status == STATUS_PENDING)
+            {
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = IoStatusBlock.Status;
+            }
+            Irp->IoStatus.Status = Status;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return Status;
+        }
         default:
         {
             DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
         default:
         {
             DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
index 761cb24..f629ebd 100644 (file)
@@ -67,6 +67,32 @@ HidClassPDO_GetReportDescription(
     return NULL;
 }
 
     return NULL;
 }
 
+PHIDP_REPORT_IDS
+HidClassPDO_GetReportDescriptionByReportID(
+    PHIDP_DEVICE_DESC DeviceDescription,
+    UCHAR ReportID)
+{
+    ULONG Index;
+
+    for (Index = 0; Index < DeviceDescription->ReportIDsLength; Index++)
+    {
+        if (DeviceDescription->ReportIDs[Index].ReportID == ReportID)
+        {
+            //
+            // found report id
+            //
+            return &DeviceDescription->ReportIDs[Index];
+        }
+    }
+
+    //
+    // failed to find report id
+    //
+    DPRINT1("[HIDCLASS] GetReportDescriptionByReportID ReportID %x not found\n", ReportID);
+    ASSERT(FALSE);
+    return NULL;
+}
+
 NTSTATUS
 HidClassPDO_HandleQueryDeviceId(
     IN PDEVICE_OBJECT DeviceObject,
 NTSTATUS
 HidClassPDO_HandleQueryDeviceId(
     IN PDEVICE_OBJECT DeviceObject,
index afaa571..d3b0be8 100644 (file)
@@ -213,4 +213,9 @@ HidClassPDO_GetReportDescription(
     PHIDP_DEVICE_DESC DeviceDescription,
     ULONG CollectionNumber);
 
     PHIDP_DEVICE_DESC DeviceDescription,
     ULONG CollectionNumber);
 
+PHIDP_REPORT_IDS
+HidClassPDO_GetReportDescriptionByReportID(
+    PHIDP_DEVICE_DESC DeviceDescription,
+    UCHAR ReportID);
+
 #endif /* _HIDCLASS_PCH_ */
 #endif /* _HIDCLASS_PCH_ */