#include "hidusb.h"
+PUSBD_PIPE_INFORMATION
+HidUsb_GetInputInterruptInterfaceHandle(
+ PUSBD_INTERFACE_INFORMATION InterfaceInformation)
+{
+ ULONG Index;
+
+ //
+ // sanity check
+ //
+ ASSERT(InterfaceInformation->NumberOfPipes);
+
+ for(Index = 0; Index < InterfaceInformation->NumberOfPipes; Index++)
+ {
+ //DPRINT1("[HIDUSB] EndpointAddress %x PipeType %x PipeHandle %x\n", InterfaceInformation->Pipes[Index].EndpointAddress, InterfaceInformation->Pipes[Index].PipeType, InterfaceInformation->Pipes[Index].PipeHandle);
+ if (InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeInterrupt && (InterfaceInformation->Pipes[Index].EndpointAddress & USB_ENDPOINT_DIRECTION_MASK))
+ {
+ //
+ // found handle
+ //
+ return &InterfaceInformation->Pipes[Index];
+ }
+ }
+
+ //
+ // not found
+ //
+ return NULL;
+}
+
+NTSTATUS
+HidUsb_GetPortStatus(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PULONG PortStatus)
+{
+ PIRP Irp;
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatus;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // init result
+ //
+ *PortStatus = 0;
+
+ //
+ // init event
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ //
+ // build irp
+ //
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS, DeviceExtension->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus);
+ if (!Irp)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get stack location
+ //
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ //
+ // store result buffer
+ //
+ IoStack->Parameters.Others.Argument1 = (PVOID)PortStatus;
+
+ //
+ // call driver
+ //
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ //
+ // wait for completion
+ //
+ KeWaitForSingleObject(&Event, Executive, KernelMode, 0, NULL);
+ return IoStatus.Status;
+ }
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+HidUsb_ResetInterruptPipe(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PUSBD_PIPE_INFORMATION PipeInformation;
+ PURB Urb;
+ NTSTATUS Status;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // get interrupt pipe handle
+ //
+ ASSERT(HidDeviceExtension->InterfaceInfo);
+ PipeInformation = HidUsb_GetInputInterruptInterfaceHandle(HidDeviceExtension->InterfaceInfo);
+ ASSERT(PipeInformation);
+ ASSERT(PipeInformation->PipeHandle);
+
+ //
+ // allocate urb
+ //
+ Urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // init urb
+ //
+ RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
+ Urb->UrbHeader.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
+ Urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
+ Urb->UrbPipeRequest.PipeHandle = PipeInformation->PipeHandle;
+
+ //
+ // dispatch request
+ //
+ Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+HidUsb_AbortPipe(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PURB Urb;
+ NTSTATUS Status;
+ PUSBD_PIPE_INFORMATION PipeInformation;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // allocate urb
+ //
+ Urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get pipe information
+ //
+ PipeInformation = HidUsb_GetInputInterruptInterfaceHandle(HidDeviceExtension->InterfaceInfo);
+ ASSERT(PipeInformation);
+ ASSERT(PipeInformation->PipeHandle);
+
+ //
+ // init urb
+ //
+ RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST));
+ Urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
+ Urb->UrbHeader.Length = sizeof(struct _URB_PIPE_REQUEST);
+ Urb->UrbPipeRequest.PipeHandle = PipeInformation->PipeHandle;
+
+ //
+ // dispatch request
+ //
+ Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+HidUsb_ResetPort(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ KEVENT Event;
+ PIRP Irp;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // init event
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ //
+ // build irp
+ //
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_RESET_PORT, DeviceExtension->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatusBlock);
+ if (!Irp)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // send the irp
+ //
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ //
+ // wait for request completion
+ //
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ //
+ // done
+ //
+ return IoStatusBlock.Status;
+}
+
NTSTATUS
NTAPI
HidCreate(
//
// informal debug print
//
- DPRINT1("HIDUSB Request: %x\n", IoStack->MajorFunction);
+ DPRINT("HIDUSB Request: %x\n", IoStack->MajorFunction);
//
// done
return STATUS_SUCCESS;
}
-NTSTATUS
+VOID
NTAPI
-HidInternalDeviceControl(
+HidUsb_ResetWorkerRoutine(
IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
+ IN PVOID Ctx)
{
- UNIMPLEMENTED
- ASSERT(FALSE);
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ ULONG PortStatus;
+ PHID_USB_RESET_CONTEXT ResetContext;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+
+ DPRINT("[HIDUSB] ResetWorkerRoutine\n");
+
+ //
+ // get context
+ //
+ ResetContext = (PHID_USB_RESET_CONTEXT)Ctx;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)ResetContext->DeviceObject->DeviceExtension;
+
+ //
+ // get port status
+ //
+ Status = HidUsb_GetPortStatus(ResetContext->DeviceObject, &PortStatus);
+ DPRINT("[HIDUSB] ResetWorkerRoutine GetPortStatus %x PortStatus %x\n", Status, PortStatus);
+ if (NT_SUCCESS(Status))
+ {
+ if (!(PortStatus & USB_PORT_STATUS_ENABLE))
+ {
+ //
+ // port is disabled
+ //
+ Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject);
+ DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status);
+ }
+ else
+ {
+ //
+ // abort pipe
+ //
+ Status = HidUsb_AbortPipe(ResetContext->DeviceObject);
+ DPRINT1("[HIDUSB] ResetWorkerRoutine AbortPipe %x\n", Status);
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // reset port
+ //
+ Status = HidUsb_ResetPort(ResetContext->DeviceObject);
+ DPRINT1("[HIDUSB] ResetPort %x\n", Status);
+ if (Status == STATUS_DEVICE_DATA_ERROR)
+ {
+ //
+ // invalidate device state
+ //
+ IoInvalidateDeviceState(DeviceExtension->PhysicalDeviceObject);
+ }
+
+ //
+ // reset interrupt pipe
+ //
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // reset pipe
+ //
+ Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject);
+ DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status);
+ }
+ }
+ }
+ }
+
+ //
+ // cleanup
+ //
+ ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ IoFreeWorkItem(ResetContext->WorkItem);
+ IoCompleteRequest(ResetContext->Irp, IO_NO_INCREMENT);
+ ExFreePool(ResetContext);
}
+
NTSTATUS
NTAPI
-HidPower(
+HidUsb_ReadReportCompletion(
IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp)
+ IN PIRP Irp,
+ IN PVOID Context)
{
- UNIMPLEMENTED
- ASSERT(FALSE);
- return STATUS_NOT_IMPLEMENTED;
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PURB Urb;
+ PHID_USB_RESET_CONTEXT ResetContext;
+
+ //
+ // get urb
+ //
+ Urb = (PURB)Context;
+ ASSERT(Urb);
+
+ DPRINT("[HIDUSB] HidUsb_ReadReportCompletion %p Status %x Urb Status %x\n", Irp, Irp->IoStatus, Urb->UrbHeader.Status);
+
+ if (Irp->PendingReturned)
+ {
+ //
+ // mark irp pending
+ //
+ IoMarkIrpPending(Irp);
+ }
+
+ //
+ // did the reading report succeed / cancelled
+ //
+ if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->IoStatus.Status == STATUS_CANCELLED || Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED)
+ {
+ //
+ // store result length
+ //
+ Irp->IoStatus.Information = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+
+ //
+ // FIXME handle error
+ //
+ ASSERT(Urb->UrbHeader.Status == USBD_STATUS_SUCCESS);
+
+ //
+ // free the urb
+ //
+ ExFreePool(Context);
+
+ //
+ // finish completion
+ //
+ return STATUS_CONTINUE_COMPLETION;
+ }
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // allocate reset context
+ //
+ ResetContext = (PHID_USB_RESET_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(HID_USB_RESET_CONTEXT));
+ if (ResetContext)
+ {
+ //
+ // allocate work item
+ //
+ ResetContext->WorkItem = IoAllocateWorkItem(DeviceObject);
+ if (ResetContext->WorkItem)
+ {
+ //
+ // init reset context
+ //
+ ResetContext->Irp = Irp;
+ ResetContext->DeviceObject = DeviceObject;
+
+ //
+ // queue the work item
+ //
+ IoQueueWorkItem(ResetContext->WorkItem, HidUsb_ResetWorkerRoutine, DelayedWorkQueue, ResetContext);
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // defer completion
+ //
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ //
+ // free context
+ //
+ ExFreePool(ResetContext);
+ }
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // complete request
+ //
+ return STATUS_CONTINUE_COMPLETION;
}
+
NTSTATUS
NTAPI
-HidSystemControl(
+HidUsb_ReadReport(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
PHID_DEVICE_EXTENSION DeviceExtension;
+ PIO_STACK_LOCATION IoStack;
+ PURB Urb;
+ PUSBD_PIPE_INFORMATION PipeInformation;
//
- // get hid device extension
+ // get device extension
//
DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
//
- // copy stack location
+ // get current stack location
//
- IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
//
- // submit request
+ // sanity checks
+ //
+ ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+ ASSERT(Irp->UserBuffer);
+ ASSERT(HidDeviceExtension->InterfaceInfo);
+
+ //
+ // get interrupt input pipe
+ //
+ PipeInformation = HidUsb_GetInputInterruptInterfaceHandle(HidDeviceExtension->InterfaceInfo);
+ ASSERT(PipeInformation);
+
+ //
+ // lets allocate urb
+ //
+ Urb = (PURB)ExAllocatePool(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // init urb
+ //
+ RtlZeroMemory(Urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
+
+ //
+ // sanity check
+ //
+ ASSERT(Irp->UserBuffer);
+ ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+ ASSERT(PipeInformation->PipeHandle);
+
+ //
+ // build the urb
+ //
+ UsbBuildInterruptOrBulkTransferRequest(Urb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ PipeInformation->PipeHandle,
+ Irp->UserBuffer,
+ NULL,
+ IoStack->Parameters.DeviceIoControl.OutputBufferLength,
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ NULL);
+
+ //
+ // store configuration handle
+ //
+ Urb->UrbHeader.UsbdDeviceHandle = HidDeviceExtension->ConfigurationHandle;
+
+ //
+ // get next location to setup irp
+ //
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ //
+ // init irp for lower driver
+ //
+ IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+ IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
+ IoStack->Parameters.DeviceIoControl.OutputBufferLength = 0;
+ IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
+ IoStack->Parameters.Others.Argument1 = (PVOID)Urb;
+
+
+ //
+ // set completion routine
+ //
+ IoSetCompletionRoutine(Irp, HidUsb_ReadReportCompletion, (PVOID)Urb, TRUE, TRUE, TRUE);
+
+ //
+ // call driver
//
return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
}
+
NTSTATUS
NTAPI
-HidPnp(
+HidUsb_GetReportDescriptor(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
- UNIMPLEMENTED
- ASSERT(FALSE);
- return STATUS_NOT_IMPLEMENTED;
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PVOID Report = NULL;
+ ULONG BufferLength, Length;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // sanity checks
+ //
+ ASSERT(HidDeviceExtension);
+ ASSERT(HidDeviceExtension->HidDescriptor);
+ ASSERT(HidDeviceExtension->HidDescriptor->bNumDescriptors >= 1);
+ ASSERT(HidDeviceExtension->HidDescriptor->DescriptorList[0].bReportType == HID_REPORT_DESCRIPTOR_TYPE);
+ ASSERT(HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength > 0);
+
+ //
+ // FIXME: support old hid version
+ //
+ BufferLength = HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength;
+ Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), &Report, &BufferLength, HidDeviceExtension->HidDescriptor->DescriptorList[0].bReportType, 0, HidDeviceExtension->InterfaceInfo->InterfaceNumber);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed to get descriptor
+ // try with old hid version
+ //
+ BufferLength = HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength;
+ Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), &Report, &BufferLength, HidDeviceExtension->HidDescriptor->DescriptorList[0].bReportType, 0, 0 /* FIXME*/);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("[HIDUSB] failed to get report descriptor with %x\n", Status);
+ return Status;
+ }
+ }
+
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ DPRINT("[HIDUSB] GetReportDescriptor: Status %x ReportLength %lu OutputBufferLength %lu TransferredLength %lu\n", Status, HidDeviceExtension->HidDescriptor->DescriptorList[0].wReportLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength, BufferLength);
+
+ //
+ // get length to copy
+ //
+ Length = min(IoStack->Parameters.DeviceIoControl.OutputBufferLength, BufferLength);
+ ASSERT(Length);
+
+ //
+ // copy result
+ //
+ RtlCopyMemory(Irp->UserBuffer, Report, Length);
+
+ //
+ // store result length
+ //
+ Irp->IoStatus.Information = Length;
+
+ //
+ // done
+ //
+ return Status;
+
}
+NTSTATUS
+NTAPI
+HidInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION IoStack;
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PHID_DEVICE_ATTRIBUTES Attributes;
+ ULONG Length;
+ NTSTATUS Status;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
+ {
+ if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_DEVICE_ATTRIBUTES))
+ {
+ //
+ // invalid request
+ //
+ Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
+ DPRINT1("[HIDUSB] IOCTL_HID_GET_DEVICE_ATTRIBUTES invalid buffer\n");
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INVALID_BUFFER_SIZE;
+ }
+ //
+ // store result
+ //
+ DPRINT("[HIDUSB] IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
+ ASSERT(HidDeviceExtension->DeviceDescriptor);
+ Irp->IoStatus.Information = sizeof(HID_DESCRIPTOR);
+ Attributes = (PHID_DEVICE_ATTRIBUTES)Irp->UserBuffer;
+ Attributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
+ Attributes->VendorID = HidDeviceExtension->DeviceDescriptor->idVendor;
+ Attributes->ProductID = HidDeviceExtension->DeviceDescriptor->idProduct;
+ Attributes->VersionNumber = HidDeviceExtension->DeviceDescriptor->bcdDevice;
+
+ //
+ // complete request
+ //
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+ case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
+ {
+ //
+ // sanity check
+ //
+ ASSERT(HidDeviceExtension->HidDescriptor);
+ DPRINT("[HIDUSB] IOCTL_HID_GET_DEVICE_DESCRIPTOR DescriptorLength %lu OutputBufferLength %lu\n", HidDeviceExtension->HidDescriptor->bLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+
+ //
+ // store length
+ //
+ Length = min(HidDeviceExtension->HidDescriptor->bLength, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+
+ //
+ // copy descriptor
+ //
+ RtlCopyMemory(Irp->UserBuffer, HidDeviceExtension->HidDescriptor, Length);
+
+ //
+ // store result length
+ //
+ Irp->IoStatus.Information = HidDeviceExtension->HidDescriptor->bLength;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ /* complete request */
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+ case IOCTL_HID_GET_REPORT_DESCRIPTOR:
+ {
+ Status = HidUsb_GetReportDescriptor(DeviceObject, Irp);
+ DPRINT("[HIDUSB] IOCTL_HID_GET_REPORT_DESCRIPTOR Status %x\n", Status);
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+ case IOCTL_HID_READ_REPORT:
+ {
+ DPRINT("[HIDUSB] IOCTL_HID_READ_REPORT\n");
+ Status = HidUsb_ReadReport(DeviceObject, Irp);
+ return Status;
+ }
+ case IOCTL_HID_WRITE_REPORT:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_WRITE_REPORT not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_GET_PHYSICAL_DESCRIPTOR:
+ {
+ DPRINT1("[HIDUSB] IOCTL_GET_PHYSICAL_DESCRIPTOR not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_GET_FEATURE:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_GET_FEATURE not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_SET_FEATURE:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_SET_FEATURE not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_SET_OUTPUT_REPORT:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_SET_OUTPUT_REPORT not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_GET_INPUT_REPORT:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_GET_INPUT_REPORT not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_GET_INDEXED_STRING:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_GET_INDEXED_STRING not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ case IOCTL_HID_GET_MS_GENRE_DESCRIPTOR:
+ {
+ DPRINT1("[HIDUSB] IOCTL_HID_GET_MS_GENRE_DESCRIPTOR not implemented \n");
+ ASSERT(FALSE);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ default:
+ {
+ UNIMPLEMENTED
+ ASSERT(FALSE);
+ Status = Irp->IoStatus.Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+ }
+}
+
+NTSTATUS
+NTAPI
+HidPower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ UNIMPLEMENTED
+ ASSERT(FALSE);
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+HidSystemControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PHID_DEVICE_EXTENSION DeviceExtension;
+
+ //
+ // get hid device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+ //
+ // copy stack location
+ //
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ //
+ // submit request
+ //
+ return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+Hid_PnpCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ //
+ // signal event
+ //
+ KeSetEvent((PRKEVENT)Context, 0, FALSE);
+
+ //
+ // done
+ //
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+NTSTATUS
+Hid_DispatchUrb(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PURB Urb)
+{
+ PIRP Irp;
+ KEVENT Event;
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ IO_STATUS_BLOCK IoStatus;
+ PIO_STACK_LOCATION IoStack;
+ NTSTATUS Status;
+
+ //
+ // init event
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+
+ //
+ // build irp
+ //
+ Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, DeviceExtension->NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus);
+ if (!Irp)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get next stack location
+ //
+ IoStack = IoGetNextIrpStackLocation(Irp);
+
+ //
+ // store urb
+ //
+ IoStack->Parameters.Others.Argument1 = (PVOID)Urb;
+
+ //
+ // set completion routine
+ //
+ IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+
+ //
+ // call driver
+ //
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+
+ //
+ // wait for the request to finish
+ //
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ //
+ // complete request
+ //
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ if (Status == STATUS_PENDING)
+ {
+ //
+ // get final status
+ //
+ Status = IoStatus.Status;
+ }
+
+ DPRINT("[HIDUSB] DispatchUrb %x\n", Status);
+
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+Hid_GetDescriptor(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN USHORT UrbFunction,
+ IN USHORT UrbLength,
+ IN OUT PVOID *UrbBuffer,
+ IN OUT PULONG UrbBufferLength,
+ IN UCHAR DescriptorType,
+ IN UCHAR Index,
+ IN USHORT LanguageIndex)
+{
+ PURB Urb;
+ NTSTATUS Status;
+ UCHAR Allocated = FALSE;
+
+ //
+ // allocate urb
+ //
+ Urb = (PURB)ExAllocatePool(NonPagedPool, UrbLength);
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // is there an urb buffer
+ //
+ if (!*UrbBuffer)
+ {
+ //
+ // allocate buffer
+ //
+ *UrbBuffer = ExAllocatePool(NonPagedPool, *UrbBufferLength);
+ if (!*UrbBuffer)
+ {
+ //
+ // no memory
+ //
+ ExFreePool(Urb);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // zero buffer
+ //
+ RtlZeroMemory(*UrbBuffer, *UrbBufferLength);
+ Allocated = TRUE;
+ }
+
+ //
+ // zero urb
+ //
+ RtlZeroMemory(Urb, UrbLength);
+
+ //
+ // build descriptor request
+ //
+ UsbBuildGetDescriptorRequest(Urb, UrbLength, DescriptorType, Index, LanguageIndex, *UrbBuffer, NULL, *UrbBufferLength, NULL);
+
+ //
+ // set urb function
+ //
+ Urb->UrbHeader.Function = UrbFunction;
+
+ //
+ // dispatch urb
+ //
+ Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+ //
+ // did the request fail
+ //
+ if (!NT_SUCCESS(Status))
+ {
+ if (Allocated)
+ {
+ //
+ // free allocated buffer
+ //
+ ExFreePool(*UrbBuffer);
+ *UrbBuffer = NULL;
+ }
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+ *UrbBufferLength = 0;
+ return Status;
+ }
+
+ //
+ // did urb request fail
+ //
+ if (!NT_SUCCESS(Urb->UrbHeader.Status))
+ {
+ if (Allocated)
+ {
+ //
+ // free allocated buffer
+ //
+ ExFreePool(*UrbBuffer);
+ *UrbBuffer = NULL;
+ }
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+ *UrbBufferLength = 0;
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // store result length
+ //
+ *UrbBufferLength = Urb->UrbControlDescriptorRequest.TransferBufferLength;
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // completed successfully
+ //
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+Hid_SelectConfiguration(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ NTSTATUS Status;
+ USBD_INTERFACE_LIST_ENTRY InterfaceList[2];
+ PURB Urb;
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // now parse the descriptors
+ //
+ InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(HidDeviceExtension->ConfigurationDescriptor,
+ HidDeviceExtension->ConfigurationDescriptor,
+ -1,
+ -1,
+ USB_DEVICE_CLASS_HUMAN_INTERFACE,
+ -1,
+ -1);
+ if (!InterfaceDescriptor)
+ {
+ //
+ // bogus configuration descriptor
+ //
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // sanity check
+ //
+ ASSERT(InterfaceDescriptor);
+ ASSERT(InterfaceDescriptor->bInterfaceClass == USB_DEVICE_CLASS_HUMAN_INTERFACE);
+ ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+ ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+
+ //
+ // setup interface list
+ //
+ RtlZeroMemory(InterfaceList, sizeof(InterfaceList));
+ InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor;
+
+ //
+ // build urb
+ //
+ Urb = USBD_CreateConfigurationRequestEx(HidDeviceExtension->ConfigurationDescriptor, InterfaceList);
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // dispatch request
+ //
+ Status = Hid_DispatchUrb(DeviceObject, Urb);
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // store configuration handle
+ //
+ HidDeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
+
+ //
+ // copy interface info
+ //
+ HidDeviceExtension->InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)ExAllocatePool(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
+ if (HidDeviceExtension->InterfaceInfo)
+ {
+ //
+ // copy interface info
+ //
+ RtlCopyMemory(HidDeviceExtension->InterfaceInfo, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
+ }
+ }
+
+ //
+ // free urb request
+ //
+ ExFreePool(Urb);
+
+ //
+ // done
+ //
+ return Status;
+}
+
+NTSTATUS
+Hid_SetIdle(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PURB Urb;
+ NTSTATUS Status;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // allocate urb
+ //
+ Urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // zero urb
+ //
+ RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+ //
+ // format urb
+ //
+ UsbBuildVendorRequest(Urb,
+ URB_FUNCTION_CLASS_INTERFACE,
+ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+ 0,
+ 0,
+ USB_SET_IDLE_REQUEST, // HID_SET_IDLE
+ 0,
+ 0,
+ NULL,
+ NULL,
+ 0,
+ NULL);
+
+ //
+ // dispatch urb
+ //
+ Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // print status
+ //
+ DPRINT1("Status %x\n", Status);
+ return Status;
+}
+
+
+VOID
+Hid_GetProtocol(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ PURB Urb;
+ NTSTATUS Status;
+ UCHAR Protocol[1];
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+ ASSERT(HidDeviceExtension->InterfaceInfo);
+
+ if (HidDeviceExtension->InterfaceInfo->SubClass != 0x1)
+ {
+ //
+ // device does not support the boot protocol
+ //
+ return;
+ }
+
+
+ //
+ // allocate urb
+ //
+ Urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+ if (!Urb)
+ {
+ //
+ // no memory
+ //
+ return;
+ }
+
+ //
+ // zero urb
+ //
+ RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+ //
+ // format urb
+ //
+ UsbBuildVendorRequest(Urb,
+ URB_FUNCTION_CLASS_INTERFACE,
+ sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+ USBD_TRANSFER_DIRECTION_IN,
+ 0,
+ USB_GET_PROTOCOL_REQUEST,
+ 0,
+ 0,
+ Protocol,
+ NULL,
+ 1,
+ NULL);
+ Protocol[0] = 0xFF;
+ //
+ // dispatch urb
+ //
+ Status = Hid_DispatchUrb(DeviceObject, Urb);
+
+ //
+ // free urb
+ //
+ ExFreePool(Urb);
+
+ //
+ // boot protocol active 0x00 disabled 0x1
+ //
+ if (Protocol[0] != 0x1)
+ {
+ if (Protocol[0] == 0x00)
+ {
+ DPRINT1("[HIDUSB] Need to disable boot protocol!\n");
+ }
+ else
+ {
+ DPRINT1("[HIDUSB] Unexpected protocol value %x\n", Protocol[0] & 0xFF);
+ }
+ }
+}
+
+NTSTATUS
+Hid_PnpStart(
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+ ULONG DescriptorLength;
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ PHID_DESCRIPTOR HidDescriptor;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // get device descriptor
+ //
+ DescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR);
+ Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->DeviceDescriptor, &DescriptorLength, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed to obtain device descriptor
+ //
+ DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status);
+ return Status;
+ }
+
+ //
+ // now get the configuration descriptor
+ //
+ DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
+ Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->ConfigurationDescriptor, &DescriptorLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed to obtain device descriptor
+ //
+ DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status);
+ return Status;
+ }
+
+ //
+ // sanity check
+ //
+ ASSERT(DescriptorLength);
+ ASSERT(HidDeviceExtension->ConfigurationDescriptor);
+ ASSERT(HidDeviceExtension->ConfigurationDescriptor->bLength);
+
+ //
+ // store full length
+ //
+ DescriptorLength = HidDeviceExtension->ConfigurationDescriptor->wTotalLength;
+
+ //
+ // delete partial configuration descriptor
+ //
+ ExFreePool(HidDeviceExtension->ConfigurationDescriptor);
+ HidDeviceExtension->ConfigurationDescriptor = NULL;
+
+ //
+ // get full configuration descriptor
+ //
+ Status = Hid_GetDescriptor(DeviceObject, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), (PVOID*)&HidDeviceExtension->ConfigurationDescriptor, &DescriptorLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed to obtain device descriptor
+ //
+ DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status);
+ return Status;
+ }
+
+ //
+ // now parse the descriptors
+ //
+ InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(HidDeviceExtension->ConfigurationDescriptor,
+ HidDeviceExtension->ConfigurationDescriptor,
+ -1,
+ -1,
+ USB_DEVICE_CLASS_HUMAN_INTERFACE,
+ -1,
+ -1);
+ if (!InterfaceDescriptor)
+ {
+ //
+ // no interface class
+ //
+ DPRINT1("[HIDUSB] HID Interface descriptor not found\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // sanity check
+ //
+ ASSERT(InterfaceDescriptor->bInterfaceClass == USB_DEVICE_CLASS_HUMAN_INTERFACE);
+ ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+ ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+
+ //
+ // move to next descriptor
+ //
+ HidDescriptor = (PHID_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
+ ASSERT(HidDescriptor->bLength >= 2);
+
+ //
+ // check if this is the hid descriptor
+ //
+ if (HidDescriptor->bLength == sizeof(HID_DESCRIPTOR) && HidDescriptor->bDescriptorType == HID_HID_DESCRIPTOR_TYPE)
+ {
+ //
+ // found
+ //
+ HidDeviceExtension->HidDescriptor = HidDescriptor;
+
+ //
+ // select configuration
+ //
+ Status = Hid_SelectConfiguration(DeviceObject);
+
+ //
+ // done
+ //
+ DPRINT1("[HIDUSB] SelectConfiguration %x\n", Status);
+
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // now set the device idle
+ //
+ Hid_SetIdle(DeviceObject);
+
+ //
+ // get protocol
+ //
+ Hid_GetProtocol(DeviceObject);
+ return Status;
+ }
+ }
+ else
+ {
+ //
+ // FIXME parse hid descriptor
+ // select configuration
+ // set idle
+ // and get protocol
+ //
+ UNIMPLEMENTED
+ ASSERT(FALSE);
+ }
+ return Status;
+}
+
+
+NTSTATUS
+NTAPI
+HidPnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IoStack;
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+ KEVENT Event;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // get current stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ DPRINT("[HIDUSB] Pnp %x\n", IoStack->MinorFunction);
+
+ //
+ // handle requests based on request type
+ //
+ switch(IoStack->MinorFunction)
+ {
+ case IRP_MN_REMOVE_DEVICE:
+ {
+ //
+ // pass request onto lower driver
+ //
+ IoSkipCurrentIrpStackLocation(Irp);
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+
+ //
+ // free resources
+ //
+ if (HidDeviceExtension->ConfigurationDescriptor)
+ {
+ ExFreePool(HidDeviceExtension->ConfigurationDescriptor);
+ HidDeviceExtension->ConfigurationDescriptor = NULL;
+ }
+
+ //
+ // delete and detach device
+ //
+ IoDetachDevice(DeviceExtension->NextDeviceObject);
+ IoDeleteDevice(DeviceObject);
+
+ return Status;
+ }
+ case IRP_MN_QUERY_PNP_DEVICE_STATE:
+ {
+ //
+ // device can not be disabled
+ //
+ Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
+
+ //
+ // pass request to next request
+ //
+ IoSkipCurrentIrpStackLocation(Irp);
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+
+ //
+ // done
+ //
+ return Status;
+ }
+ case IRP_MN_QUERY_STOP_DEVICE:
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ {
+ //
+ // we're fine with it
+ //
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ //
+ // pass request to next driver
+ //
+ IoSkipCurrentIrpStackLocation(Irp);
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+
+ //
+ // done
+ //
+ return Status;
+ }
+ case IRP_MN_STOP_DEVICE:
+ {
+ //
+ // FIXME: unconfigure the device
+ //
+
+ //
+ // prepare irp
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+
+ //
+ // send irp and wait for completion
+ //
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Irp->IoStatus.Status;
+ }
+
+ //
+ // free resources
+ //
+ if (HidDeviceExtension->HidDescriptor)
+ {
+ ExFreePool(HidDeviceExtension->HidDescriptor);
+ HidDeviceExtension->HidDescriptor = NULL;
+ }
+
+ //
+ // done
+ //
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+ case IRP_MN_QUERY_CAPABILITIES:
+ {
+ //
+ // prepare irp
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+
+ //
+ // send irp and wait for completion
+ //
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Irp->IoStatus.Status;
+ }
+
+ if (NT_SUCCESS(Status) && IoStack->Parameters.DeviceCapabilities.Capabilities != NULL)
+ {
+ //
+ // don't need to safely remove
+ //
+ IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
+ }
+
+ //
+ // done
+ //
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+ case IRP_MN_START_DEVICE:
+ {
+ //
+ // prepare irp
+ //
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp, Hid_PnpCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
+
+ //
+ // send irp and wait for completion
+ //
+ Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ Status = Irp->IoStatus.Status;
+ }
+
+ //
+ // did the device successfully start
+ //
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed
+ //
+ DPRINT1("HIDUSB: IRP_MN_START_DEVICE failed with %x\n", Status);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+
+ //
+ // start device
+ //
+ Status = Hid_PnpStart(DeviceObject);
+
+ //
+ // complete request
+ //
+ Irp->IoStatus.Status = Status;
+ DPRINT("[HIDUSB] IRP_MN_START_DEVICE Status %x\n", Status);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+ }
+ default:
+ {
+ //
+ // forward and forget request
+ //
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
+ }
+ }
+}
+
+NTSTATUS
+NTAPI
+HidAddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject)
+{
+ PHID_USB_DEVICE_EXTENSION HidDeviceExtension;
+ PHID_DEVICE_EXTENSION DeviceExtension;
+
+ //
+ // get device extension
+ //
+ DeviceExtension = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)DeviceExtension->MiniDeviceExtension;
+
+ //
+ // init event
+ //
+ KeInitializeEvent(&HidDeviceExtension->Event, NotificationEvent, FALSE);
+
+ //
+ // done
+ //
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+Hid_Unload(
+ IN PDRIVER_OBJECT DriverObject)
+{
+ UNIMPLEMENTED
+}
+
+
NTSTATUS
NTAPI
DriverEntry(
DriverObject->MajorFunction[IRP_MJ_POWER] = HidPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HidSystemControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = HidPnp;
+ DriverObject->DriverExtension->AddDevice = HidAddDevice;
+ DriverObject->DriverUnload = Hid_Unload;
//
// prepare registration info
//
// informal debug
//
- DPRINT1("********* HIDUSB *********\n");
- DPRINT1("HIDUSB Registration Status %x\n", Status);
+ DPRINT("********* HIDUSB *********\n");
+ DPRINT("HIDUSB Registration Status %x\n", Status);
return Status;
}