mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 16:20:37 +00:00
07ae01f96c
- Create PDO for each top level collection found - Use the specified collection index instead of the first - add collection id to hardware id when the device has more than one top level collection, see http://msdn.microsoft.com/en-us/windows/hardware/gg487473 for details svn path=/branches/usb-bringup/; revision=54808
587 lines
14 KiB
C
587 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/hid/hidclass/fdo.c
|
|
* PURPOSE: HID Class Driver
|
|
* PROGRAMMERS:
|
|
* Michael Martin (michael.martin@reactos.org)
|
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
*/
|
|
#include "precomp.h"
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HidClassFDO_QueryCapabilitiesCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
//
|
|
// set event
|
|
//
|
|
KeSetEvent((PRKEVENT)Context, 0, FALSE);
|
|
|
|
//
|
|
// completion is done in the HidClassFDO_QueryCapabilities routine
|
|
//
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
HidClassFDO_QueryCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PDEVICE_CAPABILITIES Capabilities)
|
|
{
|
|
PIRP Irp;
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(FDODeviceExtension->Common.IsFDO);
|
|
|
|
//
|
|
// init event
|
|
//
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
//
|
|
// now allocte the irp
|
|
//
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
if (!Irp)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// get next stack location
|
|
//
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
//
|
|
// init stack location
|
|
//
|
|
IoStack->MajorFunction = IRP_MJ_PNP;
|
|
IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
|
|
IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
|
|
|
|
//
|
|
// set completion routine
|
|
//
|
|
IoSetCompletionRoutine(Irp, HidClassFDO_QueryCapabilitiesCompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
|
|
|
|
//
|
|
// init capabilities
|
|
//
|
|
RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
|
|
Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
|
|
Capabilities->Version = 1; // FIXME hardcoded constant
|
|
Capabilities->Address = MAXULONG;
|
|
Capabilities->UINumber = MAXULONG;
|
|
|
|
//
|
|
// pnp irps have default completion code
|
|
//
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
//
|
|
// call lower device
|
|
//
|
|
Status = IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
//
|
|
// wait for completion
|
|
//
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
//
|
|
// get status
|
|
//
|
|
Status = Irp->IoStatus.Status;
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
IoFreeIrp(Irp);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HidClassFDO_DispatchRequestSynchronousCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
//
|
|
// signal event
|
|
//
|
|
KeSetEvent((PRKEVENT)Context, 0, FALSE);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HidClassFDO_DispatchRequestSynchronous(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
KEVENT Event;
|
|
PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
//
|
|
// init event
|
|
//
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// set completion routine
|
|
//
|
|
IoSetCompletionRoutine(Irp, HidClassFDO_DispatchRequestSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
|
|
|
|
ASSERT(Irp->CurrentLocation > 0);
|
|
//
|
|
// create stack location
|
|
//
|
|
IoSetNextIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get next stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// store device object
|
|
//
|
|
IoStack->DeviceObject = DeviceObject;
|
|
|
|
//
|
|
// call driver
|
|
//
|
|
DPRINT1("IoStack MajorFunction %x MinorFunction %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
|
|
Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp);
|
|
|
|
//
|
|
// wait for the request to finish
|
|
//
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
//
|
|
// update status
|
|
//
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// done
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
HidClassFDO_GetDescriptors(
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(FDODeviceExtension->Common.IsFDO);
|
|
|
|
//
|
|
// lets allocate irp
|
|
//
|
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
if (!Irp)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// get stack location
|
|
//
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
//
|
|
// init stack location
|
|
//
|
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_DESCRIPTOR;
|
|
IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR);
|
|
IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
|
|
IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
|
|
Irp->UserBuffer = &FDODeviceExtension->HidDescriptor;
|
|
|
|
//
|
|
// send request
|
|
//
|
|
Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed to get device descriptor
|
|
//
|
|
DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status);
|
|
IoFreeIrp(Irp);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// lets get device attributes
|
|
//
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES;
|
|
IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES);
|
|
Irp->UserBuffer = &FDODeviceExtension->Common.Attributes;
|
|
|
|
//
|
|
// send request
|
|
//
|
|
Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed to get device descriptor
|
|
//
|
|
DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status);
|
|
IoFreeIrp(Irp);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// sanity checks
|
|
//
|
|
ASSERT(FDODeviceExtension->HidDescriptor.bLength == sizeof(HID_DESCRIPTOR));
|
|
ASSERT(FDODeviceExtension->HidDescriptor.bNumDescriptors > 0);
|
|
ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength > 0);
|
|
ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].bReportType == HID_REPORT_DESCRIPTOR_TYPE);
|
|
|
|
|
|
//
|
|
// now allocate space for the report descriptor
|
|
//
|
|
FDODeviceExtension->ReportDescriptor = (PUCHAR)ExAllocatePool(NonPagedPool, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength);
|
|
if (!FDODeviceExtension->ReportDescriptor)
|
|
{
|
|
//
|
|
// not enough memory
|
|
//
|
|
IoFreeIrp(Irp);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// init stack location
|
|
//
|
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_REPORT_DESCRIPTOR;
|
|
IoStack->Parameters.DeviceIoControl.OutputBufferLength = FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength;
|
|
Irp->UserBuffer = FDODeviceExtension->ReportDescriptor;
|
|
|
|
//
|
|
// send request
|
|
//
|
|
Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed to get device descriptor
|
|
//
|
|
DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status);
|
|
IoFreeIrp(Irp);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// completed successfully
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HidClassFDO_StartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status;
|
|
PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(FDODeviceExtension->Common.IsFDO);
|
|
|
|
//
|
|
// query capabilities
|
|
//
|
|
Status = HidClassFDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// lets start the lower device too
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// lets get the descriptors
|
|
//
|
|
Status = HidClassFDO_GetDescriptors(DeviceObject);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// now get the the collection description
|
|
//
|
|
Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, NonPagedPool, &FDODeviceExtension->Common.DeviceDescription);
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
HidClassFDO_RemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
UNIMPLEMENTED
|
|
ASSERT(FALSE);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
HidClassFDO_CopyDeviceRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PDEVICE_RELATIONS *OutRelations)
|
|
{
|
|
PDEVICE_RELATIONS DeviceRelations;
|
|
PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
|
|
ULONG Index;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(FDODeviceExtension->Common.IsFDO);
|
|
|
|
//
|
|
// allocate result
|
|
//
|
|
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS) + (FDODeviceExtension->DeviceRelations->Count-1) * sizeof(PDEVICE_OBJECT));
|
|
if (!DeviceRelations)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
*OutRelations = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// copy device objects
|
|
//
|
|
for(Index = 0; Index < FDODeviceExtension->DeviceRelations->Count; Index++)
|
|
{
|
|
//
|
|
// reference pdo
|
|
//
|
|
ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[Index]);
|
|
|
|
//
|
|
// store object
|
|
//
|
|
DeviceRelations->Objects[Index] = FDODeviceExtension->DeviceRelations->Objects[Index];
|
|
}
|
|
|
|
//
|
|
// set object count
|
|
//
|
|
DeviceRelations->Count = FDODeviceExtension->DeviceRelations->Count;
|
|
|
|
//
|
|
// store result
|
|
//
|
|
*OutRelations = DeviceRelations;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
HidClassFDO_DeviceRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
PDEVICE_RELATIONS DeviceRelations;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(FDODeviceExtension->Common.IsFDO);
|
|
|
|
//
|
|
// get current irp stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// check relations type
|
|
//
|
|
if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
|
|
{
|
|
//
|
|
// only bus relations are handled
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
|
|
}
|
|
|
|
if (FDODeviceExtension->DeviceRelations == NULL)
|
|
{
|
|
//
|
|
// time to create the pdos
|
|
//
|
|
Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed
|
|
//
|
|
DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status);
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(FDODeviceExtension->DeviceRelations->Count > 0);
|
|
}
|
|
|
|
//
|
|
// now copy device relations
|
|
//
|
|
Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations);
|
|
//
|
|
// store result
|
|
//
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
HidClassFDO_PnP(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(FDODeviceExtension->Common.IsFDO);
|
|
|
|
//
|
|
// get current irp stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
switch(IoStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
{
|
|
return HidClassFDO_StartDevice(DeviceObject, Irp);
|
|
}
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
{
|
|
return HidClassFDO_RemoveDevice(DeviceObject, Irp);
|
|
}
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
{
|
|
//
|
|
// set status to succes
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// forward to lower device
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
|
|
}
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
{
|
|
//
|
|
// set status to succes
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// forward to lower device
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
|
|
}
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
{
|
|
return HidClassFDO_DeviceRelations(DeviceObject, Irp);
|
|
}
|
|
default:
|
|
{
|
|
//
|
|
// dispatch to lower device
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp);
|
|
}
|
|
}
|
|
}
|