/* * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/usb/hidusb/hidusb.c * PURPOSE: HID USB Interface Driver * PROGRAMMERS: * Michael Martin (michael.martin@reactos.org) * Johannes Anderwald (johannes.anderwald@reactos.org) */ #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 = 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 = 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 = DeviceObject->DeviceExtension; HidDeviceExtension = DeviceExtension->MiniDeviceExtension; // // get interrupt pipe handle // ASSERT(HidDeviceExtension->InterfaceInfo); PipeInformation = HidUsb_GetInputInterruptInterfaceHandle(HidDeviceExtension->InterfaceInfo); ASSERT(PipeInformation); ASSERT(PipeInformation->PipeHandle); // // allocate urb // Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), HIDUSB_URB_TAG); 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 // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // 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 = DeviceObject->DeviceExtension; HidDeviceExtension = DeviceExtension->MiniDeviceExtension; // // allocate urb // Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST), HIDUSB_URB_TAG); 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 // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // 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 = 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( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStack; // // get current irp stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // sanity check for hidclass driver // ASSERT(IoStack->MajorFunction == IRP_MJ_CREATE || IoStack->MajorFunction == IRP_MJ_CLOSE); // // informational debug print // DPRINT("HIDUSB Request: %x\n", IoStack->MajorFunction); // // complete request // Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); // // done // return STATUS_SUCCESS; } VOID NTAPI HidUsb_ResetWorkerRoutine( IN PDEVICE_OBJECT DeviceObject, IN PVOID Ctx) { NTSTATUS Status; ULONG PortStatus; PHID_USB_RESET_CONTEXT ResetContext; PHID_DEVICE_EXTENSION DeviceExtension; DPRINT("[HIDUSB] ResetWorkerRoutine\n"); // // get context // ResetContext = Ctx; // // get device extension // DeviceExtension = 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); ExFreePoolWithTag(ResetContext, HIDUSB_TAG); } NTSTATUS NTAPI HidUsb_ReadReportCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PURB Urb; PHID_USB_RESET_CONTEXT ResetContext; // // get urb // Urb = 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 || Urb->UrbHeader.Status == USBD_STATUS_DEVICE_GONE); // // free the urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // finish completion // return STATUS_CONTINUE_COMPLETION; } // // allocate reset context // ResetContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HID_USB_RESET_CONTEXT), HIDUSB_TAG); 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 // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // defer completion // return STATUS_MORE_PROCESSING_REQUIRED; } // // free context // ExFreePoolWithTag(ResetContext, HIDUSB_TAG); } // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // complete request // return STATUS_CONTINUE_COMPLETION; } NTSTATUS NTAPI 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 device extension // DeviceExtension = DeviceObject->DeviceExtension; HidDeviceExtension = DeviceExtension->MiniDeviceExtension; // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // 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 = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), HIDUSB_URB_TAG); 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 = Urb; // // set completion routine // IoSetCompletionRoutine(Irp, HidUsb_ReadReportCompletion, Urb, TRUE, TRUE, TRUE); // // call driver // return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); } NTSTATUS NTAPI HidUsb_GetReportDescriptor( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 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 = DeviceObject->DeviceExtension; HidDeviceExtension = 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; // // free the report buffer // ExFreePoolWithTag(Report, HIDUSB_TAG); // // 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 = DeviceObject->DeviceExtension; HidDeviceExtension = 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 = 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) { PHID_DEVICE_EXTENSION DeviceExtension; DeviceExtension = DeviceObject->DeviceExtension; PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(DeviceExtension->NextDeviceObject, Irp); } NTSTATUS NTAPI HidSystemControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PHID_DEVICE_EXTENSION DeviceExtension; // // get hid device extension // DeviceExtension = DeviceObject->DeviceExtension; // // skip stack location // IoSkipCurrentIrpStackLocation(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(Context, 0, FALSE); // // done // return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS Hid_DispatchUrb( IN PDEVICE_OBJECT DeviceObject, IN PURB Urb) { PIRP Irp; KEVENT Event; PHID_DEVICE_EXTENSION DeviceExtension; IO_STATUS_BLOCK IoStatus; PIO_STACK_LOCATION IoStack; NTSTATUS Status; // // init event // KeInitializeEvent(&Event, NotificationEvent, FALSE); // // get device extension // DeviceExtension = DeviceObject->DeviceExtension; // // 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 = Urb; // // set completion routine // IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &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 = ExAllocatePoolWithTag(NonPagedPool, UrbLength, HIDUSB_URB_TAG); if (!Urb) { // // no memory // return STATUS_INSUFFICIENT_RESOURCES; } // // is there an urb buffer // if (!*UrbBuffer) { // // allocate buffer // *UrbBuffer = ExAllocatePoolWithTag(NonPagedPool, *UrbBufferLength, HIDUSB_TAG); if (!*UrbBuffer) { // // no memory // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); 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 // ExFreePoolWithTag(*UrbBuffer, HIDUSB_TAG); *UrbBuffer = NULL; } // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); *UrbBufferLength = 0; return Status; } // // did urb request fail // if (!NT_SUCCESS(Urb->UrbHeader.Status)) { if (Allocated) { // // free allocated buffer // ExFreePoolWithTag(*UrbBuffer, HIDUSB_TAG); *UrbBuffer = NULL; } // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); *UrbBufferLength = 0; return STATUS_UNSUCCESSFUL; } // // store result length // *UrbBufferLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // 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 = DeviceObject->DeviceExtension; HidDeviceExtension = 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 = ExAllocatePoolWithTag(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length, HIDUSB_TAG); if (HidDeviceExtension->InterfaceInfo) { // // copy interface info // RtlCopyMemory(HidDeviceExtension->InterfaceInfo, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length); } } // // free urb request // ExFreePoolWithTag(Urb, 0); // // done // return Status; } NTSTATUS Hid_DisableConfiguration( IN PDEVICE_OBJECT DeviceObject) { PHID_DEVICE_EXTENSION DeviceExtension; PHID_USB_DEVICE_EXTENSION HidDeviceExtension; NTSTATUS Status; PURB Urb; // // get device extension // DeviceExtension = DeviceObject->DeviceExtension; HidDeviceExtension = DeviceExtension->MiniDeviceExtension; // // build urb // Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_SELECT_CONFIGURATION), HIDUSB_URB_TAG); if (!Urb) { // // no memory // return STATUS_INSUFFICIENT_RESOURCES; } // // format urb // UsbBuildSelectConfigurationRequest(Urb, sizeof(struct _URB_SELECT_CONFIGURATION), NULL); // // dispatch request // Status = Hid_DispatchUrb(DeviceObject, Urb); if (!NT_SUCCESS(Status)) { DPRINT1("[HIDUSB] Dispatching unconfigure URB failed with %lx\n", Status); } else if (!USBD_SUCCESS(Urb->UrbHeader.Status)) { DPRINT("[HIDUSB] Unconfigure URB failed with %lx\n", Status); } // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // free resources // HidDeviceExtension->ConfigurationHandle = NULL; if (HidDeviceExtension->InterfaceInfo) { ExFreePoolWithTag(HidDeviceExtension->InterfaceInfo, HIDUSB_TAG); HidDeviceExtension->InterfaceInfo = NULL; } if (HidDeviceExtension->ConfigurationDescriptor) { ExFreePoolWithTag(HidDeviceExtension->ConfigurationDescriptor, HIDUSB_TAG); HidDeviceExtension->ConfigurationDescriptor = NULL; HidDeviceExtension->HidDescriptor = NULL; } if (HidDeviceExtension->DeviceDescriptor) { ExFreePoolWithTag(HidDeviceExtension->DeviceDescriptor, HIDUSB_TAG); HidDeviceExtension->DeviceDescriptor = NULL; } // // done // return Status; } NTSTATUS Hid_SetIdle( IN PDEVICE_OBJECT DeviceObject) { PURB Urb; NTSTATUS Status; // // allocate urb // Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), HIDUSB_URB_TAG); 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 // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // 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; UCHAR Protocol[1]; // // get device extension // DeviceExtension = DeviceObject->DeviceExtension; HidDeviceExtension = DeviceExtension->MiniDeviceExtension; ASSERT(HidDeviceExtension->InterfaceInfo); if (HidDeviceExtension->InterfaceInfo->SubClass != 0x1) { // // device does not support the boot protocol // return; } // // allocate urb // Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), HIDUSB_URB_TAG); 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 // Hid_DispatchUrb(DeviceObject, Urb); // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); // // 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 = DeviceObject->DeviceExtension; HidDeviceExtension = 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 // ExFreePoolWithTag(HidDeviceExtension->ConfigurationDescriptor, HIDUSB_TAG); 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 // DPRINT("[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_DEVICE_EXTENSION DeviceExtension; KEVENT Event; // // get device extension // DeviceExtension = DeviceObject->DeviceExtension; // // 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: { // // unconfigure device // FIXME: Call this on IRP_MN_SURPRISE_REMOVAL, but don't send URBs // FIXME: Don't call this after we've already seen a surprise removal or stop // Hid_DisableConfiguration(DeviceObject); // // pass request onto lower driver // IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); 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: { // // unconfigure device // Hid_DisableConfiguration(DeviceObject); // // prepare irp // KeInitializeEvent(&Event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &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; } // // 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, &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, &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 = DeviceObject->DeviceExtension; HidDeviceExtension = 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( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegPath) { HID_MINIDRIVER_REGISTRATION Registration; NTSTATUS Status; // // initialize driver object // DriverObject->MajorFunction[IRP_MJ_CREATE] = HidCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidCreate; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidInternalDeviceControl; 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 // RtlZeroMemory(&Registration, sizeof(HID_MINIDRIVER_REGISTRATION)); // // fill in registration info // Registration.Revision = HID_REVISION; Registration.DriverObject = DriverObject; Registration.RegistryPath = RegPath; Registration.DeviceExtensionSize = sizeof(HID_USB_DEVICE_EXTENSION); Registration.DevicesArePolled = FALSE; // // register driver // Status = HidRegisterMinidriver(&Registration); // // informal debug // DPRINT("********* HIDUSB *********\n"); DPRINT("HIDUSB Registration Status %x\n", Status); return Status; }