reactos/drivers/hid/hidusb/hidusb.c

1966 lines
51 KiB
C

/*
* 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;
}