diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 3960ee1e993..35be3e07957 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(battery) add_subdirectory(bus) add_subdirectory(directx) add_subdirectory(filesystems) +add_subdirectory(hid) add_subdirectory(input) add_subdirectory(ksfilter) add_subdirectory(network) diff --git a/drivers/hid/CMakeLists.txt b/drivers/hid/CMakeLists.txt new file mode 100644 index 00000000000..6051356e048 --- /dev/null +++ b/drivers/hid/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(hidclass) +add_subdirectory(hidparse) +add_subdirectory(hidusb) +add_subdirectory(kbdhid) +add_subdirectory(mouhid) diff --git a/drivers/hid/hidclass/CMakeLists.txt b/drivers/hid/hidclass/CMakeLists.txt new file mode 100644 index 00000000000..1f8691bc5a6 --- /dev/null +++ b/drivers/hid/hidclass/CMakeLists.txt @@ -0,0 +1,21 @@ + +spec2def(hidclass.sys hidclass.spec) + +list(APPEND SOURCE + fdo.c + hidclass.c + hidclass.rc + pdo.c + ${CMAKE_CURRENT_BINARY_DIR}/hidclass.def) + +add_library(hidclass SHARED ${SOURCE}) + +set_entrypoint(hidclass 0) +set_image_base(hidclass 0x00010000) +set_subsystem(hidclass native) +set_target_properties(hidclass PROPERTIES SUFFIX ".sys") + + +add_importlibs(hidclass ntoskrnl hidparse hal) +add_cab_target(hidclass 2) +add_importlib_target(hidclass.spec) \ No newline at end of file diff --git a/drivers/hid/hidclass/fdo.c b/drivers/hid/hidclass/fdo.c new file mode 100644 index 00000000000..d6844315ed6 --- /dev/null +++ b/drivers/hid/hidclass/fdo.c @@ -0,0 +1,587 @@ +/* + * 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); + } + } +} diff --git a/drivers/hid/hidclass/hidclass.c b/drivers/hid/hidclass/hidclass.c new file mode 100644 index 00000000000..392f7a49ba3 --- /dev/null +++ b/drivers/hid/hidclass/hidclass.c @@ -0,0 +1,1012 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/hid/hidclass/hidclass.c + * PURPOSE: HID Class Driver + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "precomp.h" + +static LPWSTR ClientIdentificationAddress = L"HIDCLASS"; +static ULONG HidClassDeviceNumber = 0; + +ULONG +NTAPI +DllInitialize(ULONG Unknown) +{ + return 0; +} + +ULONG +NTAPI +DllUnload() +{ + return 0; +} + +NTSTATUS +NTAPI +HidClassAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + WCHAR CharDeviceName[64]; + NTSTATUS Status; + UNICODE_STRING DeviceName; + PDEVICE_OBJECT NewDeviceObject; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + ULONG DeviceExtensionSize; + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + + + /* increment device number */ + InterlockedIncrement((PLONG)&HidClassDeviceNumber); + + /* construct device name */ + swprintf(CharDeviceName, L"\\Device\\_HID%08x", HidClassDeviceNumber); + + /* initialize device name */ + RtlInitUnicodeString(&DeviceName, CharDeviceName); + + /* get driver object extension */ + DriverExtension = (PHIDCLASS_DRIVER_EXTENSION) IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress); + if (!DriverExtension) + { + /* device removed */ + ASSERT(FALSE); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + /* calculate device extension size */ + DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + DriverExtension->DeviceExtensionSize; + + /* now create the device */ + Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &NewDeviceObject); + if (!NT_SUCCESS(Status)) + { + /* failed to create device object */ + ASSERT(FALSE); + return Status; + } + + /* get device extension */ + FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)NewDeviceObject->DeviceExtension; + + /* zero device extension */ + RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION)); + + /* initialize device extension */ + FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = PhysicalDeviceObject; + FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = (PVOID)((ULONG_PTR)FDODeviceExtension + sizeof(HIDCLASS_FDO_EXTENSION)); + FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, PhysicalDeviceObject); + FDODeviceExtension->Common.IsFDO = TRUE; + FDODeviceExtension->Common.DriverExtension = DriverExtension; + + /* sanity check */ + ASSERT(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); + + /* increment stack size */ + NewDeviceObject->StackSize++; + + /* init device object */ + NewDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; + NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + /* now call driver provided add device routine */ + ASSERT(DriverExtension->AddDevice != 0); + Status = DriverExtension->AddDevice(DriverObject, NewDeviceObject); + if (!NT_SUCCESS(Status)) + { + /* failed */ + DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status); + IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); + IoDeleteDevice(NewDeviceObject); + return Status; + } + + /* succeeded */ + return Status; +} + +VOID +NTAPI +HidClassDriverUnload( + IN PDRIVER_OBJECT DriverObject) +{ + UNIMPLEMENTED + ASSERT(FALSE); +} + +NTSTATUS +NTAPI +HidClass_Create( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FILEOP_CONTEXT Context; + + // + // get device extension + // + CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + if (CommonDeviceExtension->IsFDO) + { +#ifndef __REACTOS__ + + // + // only supported for PDO + // + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_UNSUCCESSFUL; +#else + // + // ReactOS PnP manager [...] + // + DPRINT1("[HIDCLASS] PnP HACK\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +#endif + } + + // + // must be a PDO + // + ASSERT(CommonDeviceExtension->IsFDO == FALSE); + + // + // get device extension + // + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)CommonDeviceExtension; + + // + // get stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + DPRINT1("ShareAccess %x\n", IoStack->Parameters.Create.ShareAccess); + DPRINT1("Options %x\n", IoStack->Parameters.Create.Options); + DPRINT1("DesiredAccess %x\n", IoStack->Parameters.Create.SecurityContext->DesiredAccess); + + // + // allocate context + // + Context = (PHIDCLASS_FILEOP_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT)); + if (!Context) + { + // + // no memory + // + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // init context + // + RtlZeroMemory(Context, sizeof(HIDCLASS_FILEOP_CONTEXT)); + Context->DeviceExtension = PDODeviceExtension; + KeInitializeSpinLock(&Context->Lock); + InitializeListHead(&Context->ReadPendingIrpListHead); + InitializeListHead(&Context->IrpCompletedListHead); + + // + // store context + // + ASSERT(IoStack->FileObject); + IoStack->FileObject->FsContext = (PVOID)Context; + + // + // done + // + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HidClass_Close( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_IRP_CONTEXT IrpContext; + + // + // get device extension + // + CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // is it a FDO request + // + if (CommonDeviceExtension->IsFDO) + { + // + // how did the request get there + // + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER_1; + } + + // + // get stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // sanity checks + // + ASSERT(IoStack->FileObject); + ASSERT(IoStack->FileObject->FsContext); + + // + // get irp context + // + IrpContext = (PHIDCLASS_IRP_CONTEXT)IoStack->FileObject->FsContext; + + // + // cancel pending irps + // + UNIMPLEMENTED + + // + // remove context + // + IoStack->FileObject->FsContext = NULL; + + // + // free context + // + ExFreePool(IrpContext); + + // + // complete request + // + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +PVOID +HidClass_GetSystemAddress( + IN PMDL ReportMDL) +{ + // + // sanity check + // + ASSERT(ReportMDL); + + if (ReportMDL->MdlFlags & (MDL_SOURCE_IS_NONPAGED_POOL | MDL_MAPPED_TO_SYSTEM_VA)) + { + // + // buffer is non paged pool + // + return ReportMDL->MappedSystemVa; + } + else + { + // + // map mdl + // + return MmMapLockedPages(ReportMDL, KernelMode); + } +} + +NTSTATUS +NTAPI +HidClass_ReadCompleteIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Ctx) +{ + PHIDCLASS_IRP_CONTEXT IrpContext; + KIRQL OldLevel; + PUCHAR Address; + ULONG Offset; + PHIDP_COLLECTION_DESC CollectionDescription; + PHIDP_REPORT_IDS ReportDescription; + + // + // get irp context + // + IrpContext = (PHIDCLASS_IRP_CONTEXT)Ctx; + + DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql()); + DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp->IoStatus.Status); + DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp->IoStatus.Information); + DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp); + DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext->InputReportBuffer); + DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext->InputReportBufferLength); + DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext->OriginalIrp); + + // + // copy result + // + if (Irp->IoStatus.Information) + { + // + // get address + // + Address = (PUCHAR)HidClass_GetSystemAddress(IrpContext->OriginalIrp->MdlAddress); + if (Address) + { + // + // reports may have a report id prepended + // + Offset = 0; + + // + // get collection description + // + CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber); + ASSERT(CollectionDescription); + + // + // get report description + // + ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber); + ASSERT(ReportDescription); + + if (CollectionDescription && ReportDescription) + { + // + // calculate offset + // + ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); + Offset = CollectionDescription->InputLength - ReportDescription->InputLength; + } + + // + // copy result + // + RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength); + } + } + + // + // copy result status + // + IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status; + Irp->IoStatus.Information = Irp->IoStatus.Information; + + // + // free input report buffer + // + ExFreePool(IrpContext->InputReportBuffer); + + // + // remove us from pending list + // + KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel); + + // + // remove from pending list + // + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + + // + // insert into completed list + // + InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry); + + // + // release lock + // + KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel); + + // + // complete original request + // + IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT); + + // + // free irp context + // + ExFreePool(IrpContext); + + // + // done + // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +PIRP +HidClass_GetIrp( + IN PHIDCLASS_FILEOP_CONTEXT Context) +{ + KIRQL OldLevel; + PIRP Irp = NULL; + PLIST_ENTRY ListEntry; + + // + // acquire lock + // + KeAcquireSpinLock(&Context->Lock, &OldLevel); + + // + // is list empty? + // + if (!IsListEmpty(&Context->IrpCompletedListHead)) + { + // + // grab first entry + // + ListEntry = RemoveHeadList(&Context->IrpCompletedListHead); + + // + // get irp + // + Irp = (PIRP)CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); + } + + // + // release lock + // + KeReleaseSpinLock(&Context->Lock, OldLevel); + + // + // done + // + return Irp; +} + +NTSTATUS +HidClass_BuildIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP RequestIrp, + IN PHIDCLASS_FILEOP_CONTEXT Context, + IN ULONG DeviceIoControlCode, + IN ULONG BufferLength, + OUT PIRP *OutIrp, + OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + PHIDCLASS_IRP_CONTEXT IrpContext; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDP_COLLECTION_DESC CollectionDescription; + PHIDP_REPORT_IDS ReportDescription; + + // + // get an irp from fresh list + // + Irp = HidClass_GetIrp(Context); + if (!Irp) + { + // + // build new irp + // + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + // + // re-use irp + // + IoReuseIrp(Irp, STATUS_SUCCESS); + } + + // + // allocate completion context + // + IrpContext = (PHIDCLASS_IRP_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT)); + if (!IrpContext) + { + // + // no memory + // + IoFreeIrp(Irp); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get device extension + // + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // init irp context + // + RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT)); + IrpContext->OriginalIrp = RequestIrp; + IrpContext->FileOp = Context; + + // + // get collection description + // + CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber); + ASSERT(CollectionDescription); + + // + // get report description + // + ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber); + ASSERT(ReportDescription); + + // + // sanity check + // + ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); + + // + // store report length + // + IrpContext->InputReportBufferLength = ReportDescription->InputLength; + + // + // allocate buffer + // + IrpContext->InputReportBuffer = ExAllocatePool(NonPagedPool, IrpContext->InputReportBufferLength); + if (!IrpContext->InputReportBuffer) + { + // + // no memory + // + IoFreeIrp(Irp); + ExFreePool(IrpContext); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get stack location + // + IoStack = IoGetNextIrpStackLocation(Irp); + + // + // init stack location + // + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode; + IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength; + IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; + IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; + Irp->UserBuffer = IrpContext->InputReportBuffer; + IoStack->DeviceObject = DeviceObject; + + // + // store result + // + *OutIrp = Irp; + *OutIrpContext = IrpContext; + + // + // done + // + return STATUS_SUCCESS; +} + + +NTSTATUS +NTAPI +HidClass_Read( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PHIDCLASS_FILEOP_CONTEXT Context; + KIRQL OldLevel; + NTSTATUS Status; + PIRP NewIrp; + PHIDCLASS_IRP_CONTEXT NewIrpContext; + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get device extension + // + CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(CommonDeviceExtension->IsFDO == FALSE); + + // + // sanity check + // + ASSERT(IoStack->FileObject); + ASSERT(IoStack->FileObject->FsContext); + + // + // get context + // + Context = (PHIDCLASS_FILEOP_CONTEXT)IoStack->FileObject->FsContext; + ASSERT(Context); + + // + // FIXME support polled devices + // + ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE); + + // + // build irp request + // + Status = HidClass_BuildIrp(DeviceObject, Irp, Context, IOCTL_HID_READ_REPORT, IoStack->Parameters.Read.Length, &NewIrp, &NewIrpContext); + if (!NT_SUCCESS(Status)) + { + // + // failed + // + DPRINT1("HidClass_BuildIrp failed with %x\n", Status); + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + // + // acquire lock + // + KeAcquireSpinLock(&Context->Lock, &OldLevel); + + // + // insert irp into pending list + // + InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry); + + // + // set completion routine + // + IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE); + + // + // make next location current + // + IoSetNextIrpStackLocation(NewIrp); + + // + // release spin lock + // + KeReleaseSpinLock(&Context->Lock, OldLevel); + + // + // mark irp pending + // + IoMarkIrpPending(Irp); + + // + // lets dispatch the request + // + ASSERT(Context->DeviceExtension); + Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp); + + // + // complete + // + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +HidClass_Write( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HidClass_DeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHID_COLLECTION_INFORMATION CollectionInformation; + PHIDP_COLLECTION_DESC CollectionDescription; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + + // + // get device extension + // + CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(CommonDeviceExtension->IsFDO == FALSE); + + // + // get pdo device extension + // + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // get stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + switch(IoStack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_HID_GET_COLLECTION_INFORMATION: + { + // + // check if output buffer is big enough + // + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION)) + { + // + // invalid buffer size + // + Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_BUFFER_SIZE; + } + + // + // get output buffer + // + CollectionInformation = (PHID_COLLECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + ASSERT(CollectionInformation); + + // + // get collection description + // + CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription, PDODeviceExtension->CollectionNumber); + ASSERT(CollectionDescription); + + // + // init result buffer + // + CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength; + CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled; + CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID; + CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID; + CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber; + + // + // complete request + // + Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + case IOCTL_HID_GET_COLLECTION_DESCRIPTOR: + { + // + // get collection description + // + CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription, PDODeviceExtension->CollectionNumber); + ASSERT(CollectionDescription); + + // + // check if output buffer is big enough + // + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength) + { + // + // invalid buffer size + // + Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_BUFFER_SIZE; + } + + // + // copy result + // + ASSERT(Irp->UserBuffer); + RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength); + + // + // complete request + // + Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + default: + { + DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + } +} + +NTSTATUS +NTAPI +HidClass_InternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS +NTAPI +HidClass_Power( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HidClass_PnP( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + + // + // get common device extension + // + CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // check type of device object + // + if (CommonDeviceExtension->IsFDO) + { + // + // handle request + // + return HidClassFDO_PnP(DeviceObject, Irp); + } + else + { + // + // handle request + // + return HidClassPDO_PnP(DeviceObject, Irp); + } +} + +NTSTATUS +NTAPI +HidClass_DispatchDefault( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + + // + // get common device extension + // + CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // FIXME: support PDO + // + ASSERT(CommonDeviceExtension->IsFDO == TRUE); + + // + // skip current irp stack location + // + IoSkipCurrentIrpStackLocation(Irp); + + // + // dispatch to lower device object + // + return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp); +} + + +NTSTATUS +NTAPI +HidClassDispatch( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction); + + // + // dispatch request based on major function + // + switch(IoStack->MajorFunction) + { + case IRP_MJ_CREATE: + return HidClass_Create(DeviceObject, Irp); + case IRP_MJ_CLOSE: + return HidClass_Close(DeviceObject, Irp); + case IRP_MJ_READ: + return HidClass_Read(DeviceObject, Irp); + case IRP_MJ_WRITE: + return HidClass_Write(DeviceObject, Irp); + case IRP_MJ_DEVICE_CONTROL: + return HidClass_DeviceControl(DeviceObject, Irp); + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + return HidClass_InternalDeviceControl(DeviceObject, Irp); + case IRP_MJ_POWER: + return HidClass_Power(DeviceObject, Irp); + case IRP_MJ_PNP: + return HidClass_PnP(DeviceObject, Irp); + default: + return HidClass_DispatchDefault(DeviceObject, Irp); + } +} + +NTSTATUS +NTAPI +HidRegisterMinidriver( + IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration) +{ + NTSTATUS Status; + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + + /* check if the version matches */ + if (MinidriverRegistration->Revision > HID_REVISION) + { + /* revision mismatch */ + ASSERT(FALSE); + return STATUS_REVISION_MISMATCH; + } + + /* now allocate the driver object extension */ + Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject, (PVOID)ClientIdentificationAddress, sizeof(HIDCLASS_DRIVER_EXTENSION), (PVOID*)&DriverExtension); + if (!NT_SUCCESS(Status)) + { + /* failed to allocate driver extension */ + ASSERT(FALSE); + return Status; + } + + /* zero driver extension */ + RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION)); + + /* init driver extension */ + DriverExtension->DriverObject = MinidriverRegistration->DriverObject; + DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize; + DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled; + DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice; + DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload; + + /* copy driver dispatch routines */ + RtlCopyMemory(DriverExtension->MajorFunction, MinidriverRegistration->DriverObject->MajorFunction, sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION+1)); + + /* initialize lock */ + KeInitializeSpinLock(&DriverExtension->Lock); + + /* now replace dispatch routines */ + DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice; + DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch; + DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch; + + /* done */ + return STATUS_SUCCESS; +} diff --git a/drivers/hid/hidclass/hidclass.rc b/drivers/hid/hidclass/hidclass.rc new file mode 100644 index 00000000000..a700199fb14 --- /dev/null +++ b/drivers/hid/hidclass/hidclass.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB HID Bus Driver\0" +#define REACTOS_STR_INTERNAL_NAME "hidclass\0" +#define REACTOS_STR_ORIGINAL_FILENAME "hidclass.sys\0" +#include diff --git a/drivers/hid/hidclass/hidclass.spec b/drivers/hid/hidclass/hidclass.spec new file mode 100644 index 00000000000..3539f1f6aea --- /dev/null +++ b/drivers/hid/hidclass/hidclass.spec @@ -0,0 +1,4 @@ +@ stdcall -private DllInitialize(long) +@ stdcall -private DllUnload() +@ stdcall HidRegisterMinidriver(ptr) + diff --git a/drivers/hid/hidclass/pdo.c b/drivers/hid/hidclass/pdo.c new file mode 100644 index 00000000000..097c9788d99 --- /dev/null +++ b/drivers/hid/hidclass/pdo.c @@ -0,0 +1,711 @@ +/* + * 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" + +PHIDP_COLLECTION_DESC +HidClassPDO_GetCollectionDescription( + PHIDP_DEVICE_DESC DeviceDescription, + ULONG CollectionNumber) +{ + ULONG Index; + + for(Index = 0; Index < DeviceDescription->CollectionDescLength; Index++) + { + if (DeviceDescription->CollectionDesc[Index].CollectionNumber == CollectionNumber) + { + // + // found collection + // + return &DeviceDescription->CollectionDesc[Index]; + } + } + + // + // failed to find collection + // + DPRINT1("[HIDCLASS] GetCollectionDescription CollectionNumber %x not found\n", CollectionNumber); + ASSERT(FALSE); + return NULL; +} + +PHIDP_REPORT_IDS +HidClassPDO_GetReportDescription( + PHIDP_DEVICE_DESC DeviceDescription, + ULONG CollectionNumber) +{ + ULONG Index; + + for(Index = 0; Index < DeviceDescription->ReportIDsLength; Index++) + { + if (DeviceDescription->ReportIDs[Index].CollectionNumber == CollectionNumber) + { + // + // found collection + // + return &DeviceDescription->ReportIDs[Index]; + } + } + + // + // failed to find collection + // + DPRINT1("[HIDCLASS] GetReportDescription CollectionNumber %x not found\n", CollectionNumber); + ASSERT(FALSE); + return NULL; +} + +NTSTATUS +HidClassPDO_HandleQueryDeviceId( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + NTSTATUS Status; + LPWSTR Buffer; + LPWSTR NewBuffer, Ptr; + ULONG Length; + + // + // copy current stack location + // + IoCopyCurrentIrpStackLocationToNext(Irp); + + // + // call mini-driver + // + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed + // + return Status; + } + + // + // get buffer + // + Buffer = (LPWSTR)Irp->IoStatus.Information; + Length = wcslen(Buffer); + + // + // allocate new buffer + // + NewBuffer = (LPWSTR)ExAllocatePool(NonPagedPool, (Length + 1) * sizeof(WCHAR)); + if (!NewBuffer) + { + // + // failed to allocate buffer + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // replace bus + // + wcscpy(NewBuffer, L"HID\\"); + + // + // get offset to first '\\' + // + Ptr = wcschr(Buffer, L'\\'); + if (Ptr) + { + // + // append result + // + wcscat(NewBuffer, Ptr + 1); + } + + // + // free old buffer + // + ExFreePool(Buffer); + + // + // store result + // + DPRINT1("NewBuffer %S\n", NewBuffer); + ASSERT(FALSE); + Irp->IoStatus.Information = (ULONG_PTR)NewBuffer; + return STATUS_SUCCESS; +} + +NTSTATUS +HidClassPDO_HandleQueryHardwareId( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + NTSTATUS Status; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + WCHAR Buffer[100]; + ULONG Offset = 0; + LPWSTR Ptr; + PHIDP_COLLECTION_DESC CollectionDescription; + + // + // get device extension + // + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // copy current stack location + // + IoCopyCurrentIrpStackLocationToNext(Irp); + + // + // call mini-driver + // + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed + // + return Status; + } + + if (PDODeviceExtension->Common.DeviceDescription.CollectionDescLength > 1) + { + // + // multi-tlc device + // + Offset = swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Rev_%04x&Col%02x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->Common.Attributes.VersionNumber, PDODeviceExtension->CollectionNumber) + 1; + Offset += swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->CollectionNumber) + 1; + } + else + { + // + // single tlc device + // + Offset = swprintf(&Buffer[Offset], L"HID\\Vix_%04x&Pid_%04x&Rev_%04x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->Common.Attributes.VersionNumber) + 1; + Offset += swprintf(&Buffer[Offset], L"HID\\Vix_%04x&Pid_%04x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID) + 1; + } + + // + // get collection description + // + CollectionDescription = HidClassPDO_GetCollectionDescription(&PDODeviceExtension->Common.DeviceDescription, PDODeviceExtension->CollectionNumber); + ASSERT(CollectionDescription); + + if (CollectionDescription->UsagePage == HID_USAGE_PAGE_GENERIC) + { + switch(CollectionDescription->Usage) + { + case HID_USAGE_GENERIC_POINTER: + case HID_USAGE_GENERIC_MOUSE: + // + // Pointer / Mouse + // + Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_MOUSE") + 1; + break; + case HID_USAGE_GENERIC_GAMEPAD: + case HID_USAGE_GENERIC_JOYSTICK: + // + // Joystick / Gamepad + // + Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_GAME") + 1; + break; + case HID_USAGE_GENERIC_KEYBOARD: + case HID_USAGE_GENERIC_KEYPAD: + // + // Keyboard / Keypad + // + Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_KEYBOARD") + 1; + break; + case HID_USAGE_GENERIC_SYSTEM_CTL: + // + // System Control + // + Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONTROL") + 1; + break; + } + } + else if (CollectionDescription->UsagePage == HID_USAGE_PAGE_CONSUMER && CollectionDescription->Usage == HID_USAGE_CONSUMERCTRL) + { + // + // Consumer Audio Control + // + Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONSUMER") + 1; + } + + // + // FIXME: add 'HID_DEVICE_UP:0001_U:0002' + // + + // + // add HID + // + Offset +=swprintf(&Buffer[Offset], L"HID_DEVICE") + 1; + + // + // free old buffer + // + ExFreePool((PVOID)Irp->IoStatus.Information); + + // + // allocate buffer + // + Ptr = (LPWSTR)ExAllocatePool(NonPagedPool, (Offset +1)* sizeof(WCHAR)); + if (!Ptr) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // copy buffer + // + RtlCopyMemory(Ptr, Buffer, Offset * sizeof(WCHAR)); + Ptr[Offset] = UNICODE_NULL; + + // + // store result + // + ASSERT(FALSE); + Irp->IoStatus.Information = (ULONG_PTR)Ptr; + return STATUS_SUCCESS; +} + +NTSTATUS +HidClassPDO_HandleQueryInstanceId( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + NTSTATUS Status; + + // + // copy current stack location + // + IoCopyCurrentIrpStackLocationToNext(Irp); + + // + // call mini-driver + // + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed + // + return Status; + } + DPRINT1("HidClassPDO_HandleQueryInstanceId Buffer %S\n", Irp->IoStatus.Information); + return Status; +} + +NTSTATUS +HidClassPDO_HandleQueryCompatibleId( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + LPWSTR Buffer; + + Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR)); + if (!Buffer) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // zero buffer + // + Buffer[0] = 0; + Buffer[1] = 0; + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)Buffer; + return STATUS_SUCCESS; +} + + +NTSTATUS +HidClassPDO_PnP( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + PPNP_BUS_INFORMATION BusInformation; + PDEVICE_RELATIONS DeviceRelation; + + // + // get device extension + // + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // get current irp stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // handle request + // + switch(IoStack->MinorFunction) + { + case IRP_MN_QUERY_ID: + { + if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID) + { + // + // handle query device id + // + Status = HidClassPDO_HandleQueryDeviceId(DeviceObject, Irp); + break; + } + else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) + { + // + // handle instance id + // + Status = HidClassPDO_HandleQueryHardwareId(DeviceObject, Irp); + break; + } + else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID) + { + // + // handle instance id + // + Status = HidClassPDO_HandleQueryInstanceId(DeviceObject, Irp); + break; + } + else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) + { + // + // handle instance id + // + Status = HidClassPDO_HandleQueryCompatibleId(DeviceObject, Irp); + break; + } + + DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType); + Status = STATUS_NOT_SUPPORTED; + Irp->IoStatus.Information = 0; + break; + } + case IRP_MN_QUERY_CAPABILITIES: + { + if (IoStack->Parameters.DeviceCapabilities.Capabilities == NULL) + { + // + // invalid request + // + Status = STATUS_DEVICE_CONFIGURATION_ERROR; + } + + // + // copy capabilities + // + RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_BUS_INFORMATION: + { + // + // + // + BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(PNP_BUS_INFORMATION)); + + // + // fill in result + // + RtlCopyMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_HID, sizeof(GUID)); + BusInformation->LegacyBusType = PNPBus; + BusInformation->BusNumber = 0; //FIXME + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)BusInformation; + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_PNP_DEVICE_STATE: + { + // + // FIXME set flags when driver fails / disabled + // + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + // + // only target relations are supported + // + if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + { + // + // not supported + // + Status = Irp->IoStatus.Status; + break; + } + + // + // allocate device relations + // + DeviceRelation = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS)); + if (!DeviceRelation) + { + // + // no memory + // + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + // + // init device relation + // + DeviceRelation->Count = 1; + DeviceRelation->Objects[0] = DeviceObject; + ObReferenceObject(DeviceRelation->Objects[0]); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation; + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_START_DEVICE: + { + // + // FIXME: support polled devices + // + ASSERT(PDODeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE); + + // + // now register the device interface + // + Status = IoRegisterDeviceInterface(PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject, &GUID_DEVINTERFACE_HID, NULL, &PDODeviceExtension->DeviceInterface); + DPRINT1("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status); + if (NT_SUCCESS(Status)) + { + // + // enable device interface + // + Status = IoSetDeviceInterfaceState(&PDODeviceExtension->DeviceInterface, TRUE); + DPRINT1("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status); + } + ASSERT(Status == STATUS_SUCCESS); + // + // break + // + break; + } + case IRP_MN_REMOVE_DEVICE: + { + DPRINT1("[HIDCLASS] PDO IRP_MN_REMOVE_DEVICE not implemented\n"); + ASSERT(FALSE); + + // + // do nothing + // + Status = STATUS_SUCCESS; //Irp->IoStatus.Status; + break; + } + case IRP_MN_QUERY_INTERFACE: + { + DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n"); + ASSERT(FALSE); + + // + // do nothing + // + Status = Irp->IoStatus.Status; + break; + } + default: + { + // + // do nothing + // + Status = Irp->IoStatus.Status; + break; + } + } + + // + // complete request + // + if (Status != STATUS_PENDING) + { + // + // store result + // + Irp->IoStatus.Status = Status; + + // + // complete request + // + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + // + // done processing + // + return Status; +} + +NTSTATUS +HidClassPDO_CreatePDO( + IN PDEVICE_OBJECT DeviceObject, + OUT PDEVICE_RELATIONS *OutDeviceRelations) +{ + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + NTSTATUS Status; + PDEVICE_OBJECT PDODeviceObject; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + ULONG Index; + PDEVICE_RELATIONS DeviceRelations; + ULONG Length; + + // + // get device extension + // + FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // first allocate device relations + // + Length = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * FDODeviceExtension->Common.DeviceDescription.CollectionDescLength; + DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, Length); + if (!DeviceRelations) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // zero device relations + // + RtlZeroMemory(DeviceRelations, Length); + + // + // lets create a PDO for top level collection + // + Index = 0; + do + { + // + // lets create the device object + // + Status = IoCreateDevice(FDODeviceExtension->Common.DriverExtension->DriverObject, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject); + if (!NT_SUCCESS(Status)) + { + // + // failed to create device + // + DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status); + break; + } + + // + // patch stack size + // + PDODeviceObject->StackSize = DeviceObject->StackSize + 1; + + // + // get device extension + // + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; + + // + // init device extension + // + PDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension; + PDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject; + PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject; + PDODeviceExtension->Common.IsFDO = FALSE; + PDODeviceExtension->FDODeviceObject = DeviceObject; + PDODeviceExtension->Common.DriverExtension = FDODeviceExtension->Common.DriverExtension; + PDODeviceExtension->CollectionNumber = FDODeviceExtension->Common.DeviceDescription.CollectionDesc[Index].CollectionNumber; + + // + // copy device data + // + RtlCopyMemory(&PDODeviceExtension->Common.Attributes, &FDODeviceExtension->Common.Attributes, sizeof(HID_DEVICE_ATTRIBUTES)); + RtlCopyMemory(&PDODeviceExtension->Common.DeviceDescription, &FDODeviceExtension->Common.DeviceDescription, sizeof(HIDP_DEVICE_DESC)); + RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); + + // + // set device flags + // + PDODeviceObject->Flags |= DO_MAP_IO_BUFFER; + + // + // device is initialized + // + PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + // + // store device object in device relations + // + DeviceRelations->Objects[Index] = PDODeviceObject; + DeviceRelations->Count++; + + // + // move to next + // + Index++; + + }while(Index < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength); + + + // + // check if creating succeeded + // + if (!NT_SUCCESS(Status)) + { + // + // failed + // + for(Index = 0; Index < DeviceRelations->Count; Index++) + { + // + // delete device + // + IoDeleteDevice(DeviceRelations->Objects[Index]); + } + + // + // free device relations + // + ExFreePool(DeviceRelations); + return Status; + } + + // + // store device relations + // + *OutDeviceRelations = DeviceRelations; + + // + // done + // + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/drivers/hid/hidclass/precomp.h b/drivers/hid/hidclass/precomp.h new file mode 100644 index 00000000000..db0159c3fa3 --- /dev/null +++ b/drivers/hid/hidclass/precomp.h @@ -0,0 +1,197 @@ +#pragma once + +#define _HIDPI_NO_FUNCTION_MACROS_ +#define NDEBUG +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + PDRIVER_OBJECT DriverObject; + ULONG DeviceExtensionSize; + BOOLEAN DevicesArePolled; + PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; + PDRIVER_ADD_DEVICE AddDevice; + PDRIVER_UNLOAD DriverUnload; + KSPIN_LOCK Lock; + +}HIDCLASS_DRIVER_EXTENSION, *PHIDCLASS_DRIVER_EXTENSION; + +typedef struct +{ + // + // hid device extension + // + HID_DEVICE_EXTENSION HidDeviceExtension; + + // + // if it is a pdo + // + BOOLEAN IsFDO; + + // + // driver extension + // + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + + // + // device description + // + HIDP_DEVICE_DESC DeviceDescription; + + // + // hid attributes + // + HID_DEVICE_ATTRIBUTES Attributes; + +}HIDCLASS_COMMON_DEVICE_EXTENSION, *PHIDCLASS_COMMON_DEVICE_EXTENSION; + +typedef struct +{ + // + // parts shared by fdo and pdo + // + HIDCLASS_COMMON_DEVICE_EXTENSION Common; + + // + // device capabilities + // + DEVICE_CAPABILITIES Capabilities; + + // + // hid descriptor + // + HID_DESCRIPTOR HidDescriptor; + + // + // report descriptor + // + PUCHAR ReportDescriptor; + + // + // device relations + // + PDEVICE_RELATIONS DeviceRelations; + +}HIDCLASS_FDO_EXTENSION, *PHIDCLASS_FDO_EXTENSION; + +typedef struct +{ + // + // parts shared by fdo and pdo + // + HIDCLASS_COMMON_DEVICE_EXTENSION Common; + + // + // device capabilities + // + DEVICE_CAPABILITIES Capabilities; + + // + // collection index + // + ULONG CollectionNumber; + + // + // device interface + // + UNICODE_STRING DeviceInterface; + + // + // FDO device object + // + PDEVICE_OBJECT FDODeviceObject; + +}HIDCLASS_PDO_DEVICE_EXTENSION, *PHIDCLASS_PDO_DEVICE_EXTENSION; + +typedef struct __HIDCLASS_FILEOP_CONTEXT__ +{ + // + // device extension + // + PHIDCLASS_PDO_DEVICE_EXTENSION DeviceExtension; + + // + // spin lock + // + KSPIN_LOCK Lock; + + // + // read irp pending list + // + LIST_ENTRY ReadPendingIrpListHead; + + // + // completed irp list + // + LIST_ENTRY IrpCompletedListHead; + +}HIDCLASS_FILEOP_CONTEXT, *PHIDCLASS_FILEOP_CONTEXT; + +typedef struct +{ + // + // original request + // + PIRP OriginalIrp; + + // + // file op + // + PHIDCLASS_FILEOP_CONTEXT FileOp; + + // + // buffer for reading report + // + PVOID InputReportBuffer; + + // + // buffer length + // + ULONG InputReportBufferLength; + + // + // work item + // + PIO_WORKITEM CompletionWorkItem; + +}HIDCLASS_IRP_CONTEXT, *PHIDCLASS_IRP_CONTEXT; + +/* fdo.c */ +NTSTATUS +HidClassFDO_PnP( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +HidClassFDO_DispatchRequestSynchronous( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +/* pdo.c */ +NTSTATUS +HidClassPDO_CreatePDO( + IN PDEVICE_OBJECT DeviceObject, + OUT PDEVICE_RELATIONS *OutDeviceRelations); + +NTSTATUS +HidClassPDO_PnP( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +PHIDP_COLLECTION_DESC +HidClassPDO_GetCollectionDescription( + PHIDP_DEVICE_DESC DeviceDescription, + ULONG CollectionNumber); + +PHIDP_REPORT_IDS +HidClassPDO_GetReportDescription( + PHIDP_DEVICE_DESC DeviceDescription, + ULONG CollectionNumber); + +/* eof */ diff --git a/drivers/usb/hidparse/CMakeLists.txt b/drivers/hid/hidparse/CMakeLists.txt similarity index 67% rename from drivers/usb/hidparse/CMakeLists.txt rename to drivers/hid/hidparse/CMakeLists.txt index a6740cc646f..14a1f87e1b0 100644 --- a/drivers/usb/hidparse/CMakeLists.txt +++ b/drivers/hid/hidparse/CMakeLists.txt @@ -2,7 +2,10 @@ spec2def(hidparse.sys hidparse.spec) add_definitions(-DDEBUG_MODE) -include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include) +include_directories( + ${REACTOS_SOURCE_DIR}/ntoskrnl/include + ${REACTOS_SOURCE_DIR}/lib/drivers/hidparser) + add_library(hidparse SHARED hidparse.c hidparse.rc ${CMAKE_CURRENT_BINARY_DIR}/hidparse.def) @@ -12,3 +15,5 @@ add_cab_target(hidparse 2) add_cab_target(hidparse 2) add_importlib_target(hidparse.spec) + +target_link_libraries(hidparse hidparser) diff --git a/drivers/usb/hidparse/hidparse.c b/drivers/hid/hidparse/hidparse.c similarity index 63% rename from drivers/usb/hidparse/hidparse.c rename to drivers/hid/hidparse/hidparse.c index c3cce18baa1..68db33a4555 100644 --- a/drivers/usb/hidparse/hidparse.c +++ b/drivers/hid/hidparse/hidparse.c @@ -10,30 +10,346 @@ #include "hidparse.h" +PVOID +NTAPI +AllocFunction( + IN ULONG ItemSize) +{ + PVOID Item = ExAllocatePool(NonPagedPool, ItemSize); + if (Item) + { + // + // zero item + // + RtlZeroMemory(Item, ItemSize); + } + + // + // done + // + return Item; +} VOID +NTAPI +FreeFunction( + IN PVOID Item) +{ + // + // free item + // + ExFreePool(Item); +} + +VOID +NTAPI +ZeroFunction( + IN PVOID Item, + IN ULONG ItemSize) +{ + // + // zero item + // + RtlZeroMemory(Item, ItemSize); +} + +VOID +NTAPI +CopyFunction( + IN PVOID Target, + IN PVOID Source, + IN ULONG Length) +{ + // + // copy item + // + RtlCopyMemory(Target, Source, Length); +} + +VOID +NTAPI +DebugFunction( + IN LPCSTR FormatStr, ...) +{ + + va_list args; + unsigned int i; + char printbuffer[1024]; + + va_start(args, FormatStr); + i = vsprintf(printbuffer, FormatStr, args); + va_end(args); + + DbgPrint(printbuffer); +} + +VOID +NTAPI HidP_FreeCollectionDescription ( IN PHIDP_DEVICE_DESC DeviceDescription) { - DPRINT1("HidP_FreeCollectionDescription DeviceDescription %p\n", DeviceDescription); + HID_PARSER Parser; + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, NULL, &Parser); // // free collection // - ExFreePool(DeviceDescription->CollectionDesc); - - // - // free report ids - // - ExFreePool(DeviceDescription->ReportIDs); - - // - // free description itself - // - ExFreePool(DeviceDescription); - + HidParser_FreeCollectionDescription(&Parser, DeviceDescription); } + +HIDAPI +NTSTATUS +NTAPI +HidP_GetCaps( + IN PHIDP_PREPARSED_DATA PreparsedData, + OUT PHIDP_CAPS Capabilities) +{ + HID_PARSER Parser; + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser); + + // + // get caps + // + return HidParser_GetCaps(&Parser, Capabilities); +} + +NTSTATUS +NTAPI +HidP_GetCollectionDescription( + IN PHIDP_REPORT_DESCRIPTOR ReportDesc, + IN ULONG DescLength, + IN POOL_TYPE PoolType, + OUT PHIDP_DEVICE_DESC DeviceDescription) +{ + PHID_PARSER Parser; + HIDPARSER_STATUS Status; + + // + // first allocate the parser + // + Status = HidParser_AllocateParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, &Parser); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // not enough memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get description; + // + Status = HidParser_GetCollectionDescription(Parser, ReportDesc, DescLength, PoolType, DeviceDescription); + + // + // FIXME parser memory leak + // + return Status; +} + +HIDAPI +ULONG +NTAPI +HidP_MaxUsageListLength( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage OPTIONAL, + IN PHIDP_PREPARSED_DATA PreparsedData) +{ + HID_PARSER Parser; + + // + // sanity check + // + ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature); + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser); + + + // + // get usage length + // + return HidParser_MaxUsageListLength(&Parser, ReportType, UsagePage); +} + +HIDAPI +NTSTATUS +NTAPI +HidP_GetSpecificValueCaps( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PHIDP_VALUE_CAPS ValueCaps, + IN OUT PULONG ValueCapsLength, + IN PHIDP_PREPARSED_DATA PreparsedData) +{ + HID_PARSER Parser; + + // + // sanity check + // + ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature); + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser); + + // + // get value caps + // + return HidParser_GetSpecificValueCaps(&Parser, ReportType, UsagePage, LinkCollection, Usage, ValueCaps, ValueCapsLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidP_GetUsages( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + OUT USAGE *UsageList, + IN OUT ULONG *UsageLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength) +{ + HID_PARSER Parser; + + // + // sanity check + // + ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature); + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser); + + // + // get usages + // + return HidParser_GetUsages(&Parser, ReportType, UsagePage, LinkCollection, UsageList, UsageLength, Report, ReportLength); +} + + +#undef HidP_GetButtonCaps + +HIDAPI +NTSTATUS +NTAPI +HidP_UsageListDifference( + IN PUSAGE PreviousUsageList, + IN PUSAGE CurrentUsageList, + OUT PUSAGE BreakUsageList, + OUT PUSAGE MakeUsageList, + IN ULONG UsageListLength) +{ + return HidParser_UsageListDifference(PreviousUsageList, CurrentUsageList, BreakUsageList, MakeUsageList, UsageListLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidP_GetUsagesEx( + IN HIDP_REPORT_TYPE ReportType, + IN USHORT LinkCollection, + OUT PUSAGE_AND_PAGE ButtonList, + IN OUT ULONG *UsageLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength) +{ + return HidP_GetUsages(ReportType, HID_USAGE_PAGE_UNDEFINED, LinkCollection, (PUSAGE)ButtonList, UsageLength, PreparsedData, Report, ReportLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidP_UsageAndPageListDifference( + IN PUSAGE_AND_PAGE PreviousUsageList, + IN PUSAGE_AND_PAGE CurrentUsageList, + OUT PUSAGE_AND_PAGE BreakUsageList, + OUT PUSAGE_AND_PAGE MakeUsageList, + IN ULONG UsageListLength) +{ + return HidParser_UsageAndPageListDifference(PreviousUsageList, CurrentUsageList, BreakUsageList, MakeUsageList, UsageListLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidP_GetScaledUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + OUT PLONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength) +{ + HID_PARSER Parser; + + // + // sanity check + // + ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature); + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, PreparsedData, &Parser); + + // + // get scaled usage value + // + return HidParser_GetScaledUsageValue(&Parser, ReportType, UsagePage, LinkCollection, Usage, UsageValue, Report, ReportLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidP_TranslateUsageAndPagesToI8042ScanCodes( + IN PUSAGE_AND_PAGE ChangedUsageList, + IN ULONG UsageListLength, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext) +{ + HID_PARSER Parser; + + // + // sanity check + // + ASSERT(ReportType == HidP_Input || ReportType == HidP_Output || ReportType == HidP_Feature); + + // + // init parser + // + HidParser_InitParser(AllocFunction, FreeFunction, ZeroFunction, CopyFunction, DebugFunction, NULL, &Parser); + + // + // translate usage pages + // + return HidParser_TranslateUsageAndPagesToI8042ScanCodes(Parser, UsageListLength, KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext); +} + + + HIDAPI NTSTATUS NTAPI @@ -43,7 +359,7 @@ HidP_GetButtonCaps( PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData) { - return HidP_GetSpecificButtonCaps(ReportType, 0, 0, 0, ButtonCaps, (PULONG)ButtonCapsLength, PreparsedData); + return HidP_GetSpecificButtonCaps(ReportType, HID_USAGE_PAGE_UNDEFINED, 0, 0, ButtonCaps, (PULONG)ButtonCapsLength, PreparsedData); } HIDAPI @@ -63,31 +379,6 @@ HidP_GetSpecificButtonCaps( return STATUS_NOT_IMPLEMENTED; } - -HIDAPI -NTSTATUS -NTAPI -HidP_GetCaps( - IN PHIDP_PREPARSED_DATA PreparsedData, - OUT PHIDP_CAPS Capabilities) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS -HidP_GetCollectionDescription( - IN PHIDP_REPORT_DESCRIPTOR ReportDesc, - IN ULONG DescLength, - IN POOL_TYPE PoolType, - OUT PHIDP_DEVICE_DESC DeviceDescription) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - HIDAPI NTSTATUS NTAPI @@ -109,7 +400,7 @@ NTSTATUS NTAPI HidP_GetExtendedAttributes( IN HIDP_REPORT_TYPE ReportType, - IN USHORT DataIndex, + IN USAGE UsagePage, IN PHIDP_PREPARSED_DATA PreparsedData, OUT PHIDP_EXTENDED_ATTRIBUTES Attributes, IN OUT PULONG LengthAttributes) @@ -132,24 +423,6 @@ HidP_GetLinkCollectionNodes( return STATUS_NOT_IMPLEMENTED; } -HIDAPI -NTSTATUS -NTAPI -HidP_GetScaledUsageValue( - IN HIDP_REPORT_TYPE ReportType, - IN USAGE UsagePage, - IN USHORT LinkCollection OPTIONAL, - IN USAGE Usage, - OUT PLONG UsageValue, - IN PHIDP_PREPARSED_DATA PreparsedData, - IN PCHAR Report, - IN ULONG ReportLength) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - HIDAPI NTSTATUS NTAPI @@ -168,72 +441,8 @@ HidP_GetUsageValue( return STATUS_NOT_IMPLEMENTED; } - - -HIDAPI NTSTATUS NTAPI -HidP_UsageListDifference( - IN PUSAGE PreviousUsageList, - IN PUSAGE CurrentUsageList, - OUT PUSAGE BreakUsageList, - OUT PUSAGE MakeUsageList, - IN ULONG UsageListLength) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -HIDAPI -NTSTATUS -NTAPI -HidP_GetSpecificValueCaps( - IN HIDP_REPORT_TYPE ReportType, - IN USAGE UsagePage, - IN USHORT LinkCollection, - IN USAGE Usage, - OUT PHIDP_VALUE_CAPS ValueCaps, - IN OUT PULONG ValueCapsLength, - IN PHIDP_PREPARSED_DATA PreparsedData) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -HIDAPI -ULONG -NTAPI -HidP_MaxUsageListLength( - IN HIDP_REPORT_TYPE ReportType, - IN USAGE UsagePage OPTIONAL, - IN PHIDP_PREPARSED_DATA PreparsedData) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -HIDAPI -NTSTATUS -NTAPI -HidP_GetUsages( - IN HIDP_REPORT_TYPE ReportType, - IN USAGE UsagePage, - IN USHORT LinkCollection OPTIONAL, - OUT USAGE *UsageList, - IN OUT ULONG *UsageLength, - IN PHIDP_PREPARSED_DATA PreparsedData, - IN PCHAR Report, - IN ULONG ReportLength) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS HidP_SysPowerEvent ( IN PCHAR HidPacket, IN USHORT HidPacketLength, @@ -246,6 +455,7 @@ HidP_SysPowerEvent ( } NTSTATUS +NTAPI HidP_SysPowerCaps ( IN PHIDP_PREPARSED_DATA Ppd, OUT PULONG OutputBuffer) @@ -274,38 +484,6 @@ HidP_GetUsageValueArray( return STATUS_NOT_IMPLEMENTED; } -HIDAPI -NTSTATUS -NTAPI -HidP_GetUsagesEx( - IN HIDP_REPORT_TYPE ReportType, - IN USHORT LinkCollection, - OUT PUSAGE_AND_PAGE ButtonList, - IN OUT ULONG *UsageLength, - IN PHIDP_PREPARSED_DATA PreparsedData, - IN PCHAR Report, - IN ULONG ReportLength) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - - -HIDAPI -NTSTATUS -NTAPI -HidP_UsageAndPageListDifference( - IN PUSAGE_AND_PAGE PreviousUsageList, - IN PUSAGE_AND_PAGE CurrentUsageList, - OUT PUSAGE_AND_PAGE BreakUsageList, - OUT PUSAGE_AND_PAGE MakeUsageList, - IN ULONG UsageListLength) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} HIDAPI NTSTATUS @@ -341,22 +519,6 @@ HidP_TranslateUsagesToI8042ScanCodes( return STATUS_NOT_IMPLEMENTED; } -HIDAPI -NTSTATUS -NTAPI -HidP_TranslateUsageAndPagesToI8042ScanCodes( - IN PUSAGE_AND_PAGE ChangedUsageList, - IN ULONG UsageListLength, - IN HIDP_KEYBOARD_DIRECTION KeyAction, - IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, - IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, - IN PVOID InsertCodesContext) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - HIDAPI NTSTATUS NTAPI @@ -473,6 +635,8 @@ HidP_InitializeReportForID( return STATUS_NOT_IMPLEMENTED; } +#undef HidP_GetValueCaps + HIDAPI NTSTATUS NTAPI diff --git a/drivers/usb/hidparse/hidparse.h b/drivers/hid/hidparse/hidparse.h similarity index 79% rename from drivers/usb/hidparse/hidparse.h rename to drivers/hid/hidparse/hidparse.h index f0bc0d2c49b..fa516eb3eff 100644 --- a/drivers/usb/hidparse/hidparse.h +++ b/drivers/hid/hidparse/hidparse.h @@ -5,4 +5,6 @@ #include #include #include +#define NDEBUG #include +#include "hidparser.h" \ No newline at end of file diff --git a/drivers/usb/hidparse/hidparse.rc b/drivers/hid/hidparse/hidparse.rc similarity index 100% rename from drivers/usb/hidparse/hidparse.rc rename to drivers/hid/hidparse/hidparse.rc diff --git a/drivers/usb/hidparse/hidparse.spec b/drivers/hid/hidparse/hidparse.spec similarity index 96% rename from drivers/usb/hidparse/hidparse.spec rename to drivers/hid/hidparse/hidparse.spec index 2a3b1e85fd7..73afdfa3d6c 100644 --- a/drivers/usb/hidparse/hidparse.spec +++ b/drivers/hid/hidparse/hidparse.spec @@ -10,7 +10,7 @@ @ stdcall HidP_GetSpecificValueCaps(long long long long ptr ptr ptr) @ stdcall HidP_GetUsageValue(long long long long ptr ptr ptr long) @ stdcall HidP_GetUsageValueArray(long long long long ptr long ptr ptr long) -@ stdcall HidP_GetUsages(long long ptr ptr ptr ptr long) +@ stdcall HidP_GetUsages(long long long ptr ptr ptr ptr long) @ stdcall HidP_GetUsagesEx(long long ptr ptr ptr ptr long) @ stdcall HidP_GetValueCaps(long ptr ptr ptr) @ stdcall HidP_InitializeReportForID(long long ptr ptr long) diff --git a/drivers/usb/hidusb/CMakeLists.txt b/drivers/hid/hidusb/CMakeLists.txt similarity index 55% rename from drivers/usb/hidusb/CMakeLists.txt rename to drivers/hid/hidusb/CMakeLists.txt index 87de50832bb..52f8a789d0f 100644 --- a/drivers/usb/hidusb/CMakeLists.txt +++ b/drivers/hid/hidusb/CMakeLists.txt @@ -1,11 +1,11 @@ list(APPEND SOURCE hidusb.c - usbhub.rc) + hidusb.rc) add_library(hidusb SHARED ${SOURCE}) set_module_type(hidusb kernelmodedriver) -add_importlibs(hidusb hidclass ntoskrnl usbd) +add_importlibs(hidusb hidclass ntoskrnl usbd hal) -add_cab_target(usbhub 2) +add_cab_target(hidusb 2) diff --git a/drivers/hid/hidusb/hidusb.c b/drivers/hid/hidusb/hidusb.c new file mode 100644 index 00000000000..8addb0e5ad1 --- /dev/null +++ b/drivers/hid/hidusb/hidusb.c @@ -0,0 +1,1643 @@ +/* + * 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 = (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( + 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); + + // + // complete request + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // informal debug print + // + DPRINT1("HIDUSB Request: %x\n", IoStack->MajorFunction); + + // + // 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; + + DPRINT1("[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); + DPRINT1("[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 +HidUsb_ReadReportCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + 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 +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 = (PHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + HidDeviceExtension = (PHID_USB_DEVICE_EXTENSION)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 = (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 +HidUsb_GetReportDescriptor( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; + PHID_DEVICE_EXTENSION DeviceExtension; + PUCHAR 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, 0); + if (!NT_SUCCESS(Status)) + { + // + // failed to get descriptor + // + DPRINT("[HIDUSB] failed to get report descriptor with %x\n", Status); + ASSERT(FALSE); + return Status; + } + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT1("[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 + // + DPRINT1("[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); + DPRINT1("[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); + DPRINT1("[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; + } + + DPRINT1("[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); + + // + // 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_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 Class 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); + ASSERT(Status == STATUS_SUCCESS); + + // + // done + // + DPRINT1("[HIDUSB] SelectConfiguration %x\n", Status); + return Status; + } + + // + // FIXME parse hid descriptor + // + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_SUCCESS; +} + + +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); + DPRINT1("[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->HidDescriptor) + { + ExFreePool(HidDeviceExtension->HidDescriptor); + HidDeviceExtension->HidDescriptor = NULL; + } + + // + // done + // + 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_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)) + { + // + // driver supports D1 & D2 + // + IoStack->Parameters.DeviceCapabilities.Capabilities->DeviceD1 = TRUE; + IoStack->Parameters.DeviceCapabilities.Capabilities->DeviceD2 = 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; + DPRINT1("[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; +} + +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; + + // + // 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 + // + DPRINT1("********* HIDUSB *********\n"); + DPRINT1("HIDUSB Registration Status %x\n", Status); + + return Status; +} diff --git a/drivers/hid/hidusb/hidusb.h b/drivers/hid/hidusb/hidusb.h new file mode 100644 index 00000000000..02eb640cbac --- /dev/null +++ b/drivers/hid/hidusb/hidusb.h @@ -0,0 +1,82 @@ +#pragma once + +#define _HIDPI_ +#define _HIDPI_NO_FUNCTION_MACROS_ +#define NDEBUG +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + // + // event for completion + // + KEVENT Event; + + // + // device descriptor + // + PUSB_DEVICE_DESCRIPTOR DeviceDescriptor; + + // + // configuration descriptor + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // interface information + // + PUSBD_INTERFACE_INFORMATION InterfaceInfo; + + // + // configuration handle + // + USBD_CONFIGURATION_HANDLE ConfigurationHandle; + + // + // hid descriptor + // + PHID_DESCRIPTOR HidDescriptor; +}HID_USB_DEVICE_EXTENSION, *PHID_USB_DEVICE_EXTENSION; + +typedef struct +{ + // + // request irp + // + PIRP Irp; + + // + // work item + // + PIO_WORKITEM WorkItem; + + // + // device object + // + PDEVICE_OBJECT DeviceObject; + +}HID_USB_RESET_CONTEXT, *PHID_USB_RESET_CONTEXT; + + +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); + +NTSTATUS +Hid_DispatchUrb( + IN PDEVICE_OBJECT DeviceObject, + IN PURB Urb); diff --git a/drivers/hid/hidusb/hidusb.rc b/drivers/hid/hidusb/hidusb.rc new file mode 100644 index 00000000000..4ad02a08141 --- /dev/null +++ b/drivers/hid/hidusb/hidusb.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB HID Interface Driver\0" +#define REACTOS_STR_INTERNAL_NAME "hidusb\0" +#define REACTOS_STR_ORIGINAL_FILENAME "hidusb.sys\0" +#include diff --git a/drivers/hid/kbdhid/CMakeLists.txt b/drivers/hid/kbdhid/CMakeLists.txt new file mode 100644 index 00000000000..57d918b53e9 --- /dev/null +++ b/drivers/hid/kbdhid/CMakeLists.txt @@ -0,0 +1,13 @@ + +add_definitions(-DDEBUG_MODE) + +include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include) + +add_library(kbdhid SHARED kbdhid.c kbdhid.rc) + +set_module_type(kbdhid kernelmodedriver) +add_importlibs(kbdhid ntoskrnl hal hidparse) +add_cab_target(kbdhid 2) + +add_cab_target(kbdhid 2) + diff --git a/drivers/hid/kbdhid/kbdhid.c b/drivers/hid/kbdhid/kbdhid.c new file mode 100644 index 00000000000..d2d4866bf6d --- /dev/null +++ b/drivers/hid/kbdhid/kbdhid.c @@ -0,0 +1,855 @@ +/* + * PROJECT: ReactOS HID Stack + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/hid/kbdhid/kbdhid.c + * PURPOSE: Keyboard HID Driver + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "kbdhid.h" + +VOID +KbdHid_DispatchInputData( + IN PKBDHID_DEVICE_EXTENSION DeviceExtension, + IN PKEYBOARD_INPUT_DATA InputData) +{ + KIRQL OldIrql; + ULONG InputDataConsumed; + + if (!DeviceExtension->ClassService) + return; + + /* sanity check */ + ASSERT(DeviceExtension->ClassService); + ASSERT(DeviceExtension->ClassDeviceObject); + + /* raise irql */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + /* dispatch input data */ + (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed); + + /* lower irql to previous level */ + KeLowerIrql(OldIrql); +} + +BOOLEAN +NTAPI +KbdHid_InsertScanCodes( + IN PVOID Context, + IN PCHAR NewScanCodes, + IN ULONG Length) +{ + KEYBOARD_INPUT_DATA InputData; + ULONG Index; + + for(Index = 0; Index < Length; Index++) + { + DPRINT1("[KBDHID] ScanCode Index %lu ScanCode %x\n", Index, NewScanCodes[Index] & 0xFF); + // + // TODO: set up input data + // + //KbdHid_DispatchInputData((PKBDHID_DEVICE_EXTENSION)Context, &InputData); + } + + // + // done + // + return TRUE; +} + + +NTSTATUS +NTAPI +KbdHid_ReadCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PKBDHID_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + ULONG ButtonLength; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)Context; + + if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD || + Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED || + Irp->IoStatus.Status == STATUS_CANCELLED || + DeviceExtension->StopReadReport) + { + /* failed to read or should be stopped*/ + DPRINT1("[KBDHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status); + + /* report no longer active */ + DeviceExtension->ReadReportActive = FALSE; + + /* request stopping of the report cycle */ + DeviceExtension->StopReadReport = FALSE; + + /* signal completion event */ + KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + /* get current usages */ + ButtonLength = DeviceExtension->UsageListLength; + Status = HidP_GetUsagesEx(HidP_Input, HIDP_LINK_COLLECTION_UNSPECIFIED, DeviceExtension->CurrentUsageList, &ButtonLength, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); + ASSERT(Status == HIDP_STATUS_SUCCESS); + + /* FIXME check if needs mapping */ + + /* get usage difference */ + Status = HidP_UsageAndPageListDifference(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, DeviceExtension->BreakUsageList, DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength); + ASSERT(Status == HIDP_STATUS_SUCCESS); + + /* replace previous usage list with current list */ + RtlMoveMemory(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, sizeof(USAGE_AND_PAGE) * DeviceExtension->UsageListLength); + + /* translate break usage list */ + HidP_TranslateUsageAndPagesToI8042ScanCodes(DeviceExtension->BreakUsageList, DeviceExtension->UsageListLength, HidP_Keyboard_Break, &DeviceExtension->ModifierState, KbdHid_InsertScanCodes, DeviceExtension); + ASSERT(Status == HIDP_STATUS_SUCCESS); + + /* translate new usage list */ + HidP_TranslateUsageAndPagesToI8042ScanCodes(DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength, HidP_Keyboard_Make, &DeviceExtension->ModifierState, KbdHid_InsertScanCodes, DeviceExtension); + ASSERT(Status == HIDP_STATUS_SUCCESS); + + /* re-init read */ + KbdHid_InitiateRead(DeviceExtension); + + /* stop completion */ + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +KbdHid_InitiateRead( + IN PKBDHID_DEVICE_EXTENSION DeviceExtension) +{ + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + + /* re-use irp */ + IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS); + + /* init irp */ + DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL; + + /* get next stack location */ + IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp); + + /* init stack location */ + IoStack->Parameters.Read.Length = DeviceExtension->ReportLength; + IoStack->Parameters.Read.Key = 0; + IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL; + IoStack->MajorFunction = IRP_MJ_READ; + IoStack->FileObject = DeviceExtension->FileObject; + + /* set completion routine */ + IoSetCompletionRoutine(DeviceExtension->Irp, KbdHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE); + + /* read is active */ + DeviceExtension->ReadReportActive = TRUE; + + /* start the read */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp); + + /* done */ + return Status; +} + +NTSTATUS +NTAPI +KbdHid_CreateCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + KeSetEvent((PKEVENT)Context, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +NTSTATUS +NTAPI +KbdHid_Create( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + KEVENT Event; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + + DPRINT1("[KBDHID]: IRP_MJ_CREATE\n"); + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* get stack location */ + IoStack = IoGetCurrentIrpStackLocation(Irp); + + /* copy stack location to next */ + IoCopyCurrentIrpStackLocationToNext(Irp); + + /* init event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* prepare irp */ + IoSetCompletionRoutine(Irp, KbdHid_CreateCompletion, &Event, TRUE, TRUE, TRUE); + + /* call lower driver */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + /* request pending */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + } + + /* check for success */ + if (!NT_SUCCESS(Status)) + { + /* failed */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + /* is the driver already in use */ + if (DeviceExtension->FileObject == NULL) + { + /* did the caller specify correct attributes */ + ASSERT(IoStack->Parameters.Create.SecurityContext); + if (IoStack->Parameters.Create.SecurityContext->DesiredAccess) + { + /* store file object */ + DeviceExtension->FileObject = IoStack->FileObject; + + /* reset event */ + KeResetEvent(&DeviceExtension->ReadCompletionEvent); + + /* initiating read */ + Status = KbdHid_InitiateRead(DeviceExtension); + DPRINT1("[KBDHID] KbdHid_InitiateRead: status %x\n", Status); + if (Status == STATUS_PENDING) + { + /* report irp is pending */ + Status = STATUS_SUCCESS; + } + } + } + + /* complete request */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + + +NTSTATUS +NTAPI +KbdHid_Close( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PKBDHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); + + if (DeviceExtension->ReadReportActive) + { + /* request stopping of the report cycle */ + DeviceExtension->StopReadReport = TRUE; + + /* wait until the reports have been read */ + KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); + + /* cancel irp */ + IoCancelIrp(DeviceExtension->Irp); + } + + DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); + + /* remove file object */ + DeviceExtension->FileObject = NULL; + + /* skip location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* pass irp to down the stack */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); +} + +NTSTATUS +NTAPI +KbdHid_InternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + PCONNECT_DATA Data; + PKEYBOARD_ATTRIBUTES Attributes; + + /* get current stack location */ + IoStack = IoGetCurrentIrpStackLocation(Irp); + + DPRINT1("[KBDHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_ATTRIBUTES) + { + /* verify output buffer length */ + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES)) + { + /* invalid request */ + DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n"); + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + /* get output buffer */ + Attributes = (PKEYBOARD_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer; + + /* copy attributes */ + RtlCopyMemory(Attributes, &DeviceExtension->Attributes, sizeof(KEYBOARD_ATTRIBUTES)); + + /* complete request */ + Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_CONNECT) + { + /* verify input buffer length */ + if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) + { + /* invalid request */ + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; + } + + /* is it already connected */ + if (DeviceExtension->ClassService) + { + /* already connected */ + Irp->IoStatus.Status = STATUS_SHARING_VIOLATION; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SHARING_VIOLATION; + } + + /* get connect data */ + Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + /* store connect details */ + DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject; + DeviceExtension->ClassService = Data->ClassService; + + /* completed successfully */ + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_DISCONNECT) + { + /* not implemented */ + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_ENABLE) + { + /* not supported */ + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_SUPPORTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_DISABLE) + { + /* not supported */ + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_SUPPORTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_INDICATORS) + { + /* not implemented */ + DPRINT1("IOCTL_KEYBOARD_QUERY_INDICATORS not implemented\n"); + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_TYPEMATIC) + { + /* not implemented */ + DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n"); + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_SET_INDICATORS) + { + /* not implemented */ + DPRINT1("IOCTL_KEYBOARD_SET_INDICATORS not implemented\n"); + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_SET_TYPEMATIC) + { + /* not implemented */ + DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n"); + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION) + { + /* not implemented */ + DPRINT1("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION not implemented\n"); + ASSERT(FALSE); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + + /* unknown control code */ + DPRINT1("[KBDHID] Unknown DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + /* unknown request not supported */ + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS +NTAPI +KbdHid_DeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PKBDHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* skip stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* pass and forget */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); +} + +NTSTATUS +NTAPI +KbdHid_Power( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +KbdHid_SubmitRequest( + PDEVICE_OBJECT DeviceObject, + ULONG IoControlCode, + ULONG InputBufferSize, + PVOID InputBuffer, + ULONG OutputBufferSize, + PVOID OutputBuffer) +{ + KEVENT Event; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + PIRP Irp; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* init event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* build request */ + Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus); + if (!Irp) + { + /* no memory */ + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* send request */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + /* wait for request to complete */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + /* done */ + return Status; +} + +NTSTATUS +NTAPI +KbdHid_StartDevice( + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + ULONG Buttons; + HID_COLLECTION_INFORMATION Information; + PHIDP_PREPARSED_DATA PreparsedData; + HIDP_CAPS Capabilities; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + PUSAGE_AND_PAGE Buffer; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* query collection information */ + Status = KbdHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information); + if (!NT_SUCCESS(Status)) + { + /* failed to query collection information */ + DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status); + return Status; + } + + /* lets allocate space for preparsed data */ + PreparsedData = (PHIDP_PREPARSED_DATA)ExAllocatePool(NonPagedPool, Information.DescriptorSize); + if (!PreparsedData) + { + /* no memory */ + DPRINT1("[KBDHID] no memory size %u\n", Information.DescriptorSize); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* now obtain the preparsed data */ + Status = KbdHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 0, NULL, Information.DescriptorSize, PreparsedData); + if (!NT_SUCCESS(Status)) + { + /* failed to get preparsed data */ + DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status); + ExFreePool(PreparsedData); + return Status; + } + + /* lets get the caps */ + Status = HidP_GetCaps(PreparsedData, &Capabilities); + if (Status != HIDP_STATUS_SUCCESS) + { + /* failed to get capabilities */ + DPRINT1("[KBDHID] failed to obtain caps with %x\n", Status); + ExFreePool(PreparsedData); + return Status; + } + + DPRINT1("[KBDHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength); + + /* init input report*/ + DeviceExtension->ReportLength = Capabilities.InputReportByteLength; + ASSERT(DeviceExtension->ReportLength); + DeviceExtension->Report = (PUCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength); + ASSERT(DeviceExtension->Report); + RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength); + + /* build mdl */ + DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL); + ASSERT(DeviceExtension->ReportMDL); + + /* init mdl */ + MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL); + + /* get max number of buttons */ + Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData); + DPRINT1("[KBDHID] Buttons %lu\n", Buttons); + ASSERT(Buttons > 0); + + /* now allocate an array for those buttons */ + Buffer = (PUSAGE_AND_PAGE)ExAllocatePool(NonPagedPool, sizeof(USAGE_AND_PAGE) * 4 * Buttons); + if (!Buffer) + { + /* no memory */ + ExFreePool(PreparsedData); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* init usage lists */ + RtlZeroMemory(Buffer, sizeof(USAGE_AND_PAGE) * 4 * Buttons); + DeviceExtension->CurrentUsageList = Buffer; + Buffer += Buttons; + DeviceExtension->PreviousUsageList = Buffer; + Buffer += Buttons; + DeviceExtension->MakeUsageList = Buffer; + Buffer += Buttons; + DeviceExtension->BreakUsageList = Buffer; + + // + // FIMXE: implement device hacks + // + // UsageMappings + // KeyboardTypeOverride + // KeyboardSubTypeOverride + // KeyboardNumberTotalKeysOverride + // KeyboardNumberFunctionKeysOverride + // KeyboardNumberIndicatorsOverride + + /* store number of buttons */ + DeviceExtension->UsageListLength = (USHORT)Buttons; + + /* store preparsed data */ + DeviceExtension->PreparsedData = PreparsedData; + + /* completed successfully */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +KbdHid_StartDeviceCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + KeSetEvent((PKEVENT)Context, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +KbdHid_Flush( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* skip current stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* get next stack location */ + IoStack = IoGetNextIrpStackLocation(Irp); + + /* change request to hid flush queue request */ + IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE; + + /* call device */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); +} + +NTSTATUS +NTAPI +KbdHid_Pnp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + KEVENT Event; + NTSTATUS Status; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* get current irp stack */ + IoStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT1("[KBDHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction); + + if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || IoStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) + { + /* indicate success */ + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* skip irp stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* dispatch to lower device */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + } + else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE) + { + /* FIXME synchronization */ + + /* cancel irp */ + IoCancelIrp(DeviceExtension->Irp); + + /* indicate success */ + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* skip irp stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* dispatch to lower device */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + + IoFreeIrp(DeviceExtension->Irp); + IoDetachDevice(DeviceExtension->NextDeviceObject); + IoDeleteDevice(DeviceObject); + return Status; + } + else if (IoStack->MinorFunction == IRP_MN_START_DEVICE) + { + /* init event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* copy stack location */ + IoCopyCurrentIrpStackLocationToNext (Irp); + + /* set completion routine */ + IoSetCompletionRoutine(Irp, KbdHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE); + Irp->IoStatus.Status = 0; + + /* pass request */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = Irp->IoStatus.Status; + } + + if (!NT_SUCCESS(Status)) + { + /* failed */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + /* lets start the device */ + Status = KbdHid_StartDevice(DeviceObject); + DPRINT1("KbdHid_StartDevice %x\n", Status); + + /* complete request */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + /* done */ + return Status; + } + else + { + /* skip irp stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* dispatch to lower device */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + } +} + +NTSTATUS +NTAPI +KbdHid_AddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + NTSTATUS Status; + PDEVICE_OBJECT DeviceObject, NextDeviceObject; + PKBDHID_DEVICE_EXTENSION DeviceExtension; + POWER_STATE State; + + /* create device object */ + Status = IoCreateDevice(DriverObject, sizeof(KBDHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_KEYBOARD, 0, FALSE, &DeviceObject); + if (!NT_SUCCESS(Status)) + { + /* failed to create device object */ + return Status; + } + + /* now attach it */ + NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); + if (!NextDeviceObject) + { + /* failed to attach */ + IoDeleteDevice(DeviceObject); + return STATUS_DEVICE_NOT_CONNECTED; + } + + /* get device extension */ + DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* zero extension */ + RtlZeroMemory(DeviceExtension, sizeof(KBDHID_DEVICE_EXTENSION)); + + /* init device extension */ + DeviceExtension->NextDeviceObject = NextDeviceObject; + KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE); + + /* init keyboard attributes */ + DeviceExtension->Attributes.KeyboardIdentifier.Type = KEYBOARD_TYPE_UNKNOWN; + DeviceExtension->Attributes.KeyboardIdentifier.Subtype = MICROSOFT_KBD_101_TYPE; + DeviceExtension->Attributes.NumberOfFunctionKeys = MICROSOFT_KBD_FUNC; + DeviceExtension->Attributes.NumberOfIndicators = 3; // caps, num lock, scroll lock + DeviceExtension->Attributes.NumberOfKeysTotal = 101; + DeviceExtension->Attributes.InputDataQueueLength = 1; + DeviceExtension->Attributes.KeyRepeatMinimum.Rate = KEYBOARD_TYPEMATIC_RATE_MINIMUM; + DeviceExtension->Attributes.KeyRepeatMinimum.Delay = KEYBOARD_TYPEMATIC_DELAY_MINIMUM; + DeviceExtension->Attributes.KeyRepeatMaximum.Rate = KEYBOARD_TYPEMATIC_RATE_DEFAULT; + DeviceExtension->Attributes.KeyRepeatMaximum.Delay = KEYBOARD_TYPEMATIC_DELAY_MAXIMUM; + + /* allocate irp */ + DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE); + + /* FIXME handle allocation error */ + ASSERT(DeviceExtension->Irp); + + /* set power state to D0 */ + State.DeviceState = PowerDeviceD0; + PoSetPowerState(DeviceObject, DevicePowerState, State); + + /* init device object */ + DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + /* completed successfully */ + return STATUS_SUCCESS; +} + +VOID +NTAPI +KbdHid_Unload( + IN PDRIVER_OBJECT DriverObject) +{ + UNIMPLEMENTED +} + + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegPath) +{ + /* initialize driver object */ + DriverObject->DriverUnload = KbdHid_Unload; + DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice; + DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdHid_Create; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdHid_Close; + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = KbdHid_Flush; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdHid_DeviceControl; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = KbdHid_InternalDeviceControl; + DriverObject->MajorFunction[IRP_MJ_POWER] = KbdHid_Power; + DriverObject->MajorFunction[IRP_MJ_PNP] = KbdHid_Pnp; + DriverObject->DriverUnload = KbdHid_Unload; + DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice; + + /* done */ + return STATUS_SUCCESS; +} diff --git a/drivers/hid/kbdhid/kbdhid.h b/drivers/hid/kbdhid/kbdhid.h new file mode 100644 index 00000000000..0324ad49d51 --- /dev/null +++ b/drivers/hid/kbdhid/kbdhid.h @@ -0,0 +1,133 @@ +#pragma once + +#define _HIDPI_NO_FUNCTION_MACROS_ +#include +#include +#include +#include +#include +#include +//#include +#include +#include + + +typedef struct +{ + // + // lower device object + // + PDEVICE_OBJECT NextDeviceObject; + + // + // irp which is used for reading input reports + // + PIRP Irp; + + // + // event + // + KEVENT ReadCompletionEvent; + + // + // device object for class callback + // + PDEVICE_OBJECT ClassDeviceObject; + + // + // class callback + // + PVOID ClassService; + + // + // usage list length + // + USHORT UsageListLength; + + // + // current usage list length + // + PUSAGE_AND_PAGE CurrentUsageList; + + // + // previous usage list + // + PUSAGE_AND_PAGE PreviousUsageList; + + // + // removed usage item list + // + PUSAGE_AND_PAGE BreakUsageList; + + // + // new item usage list + // + PUSAGE_AND_PAGE MakeUsageList; + + // + // preparsed data + // + PHIDP_PREPARSED_DATA PreparsedData; + + // + // mdl for reading input report + // + PMDL ReportMDL; + + // + // input report buffer + // + PCHAR Report; + + // + // input report length + // + ULONG ReportLength; + + // + // file object the device is reading reports from + // + PFILE_OBJECT FileObject; + + // + // report read is active + // + UCHAR ReadReportActive; + + // + // stop reading flag + // + UCHAR StopReadReport; + + // + // keyboard attributes + // + KEYBOARD_ATTRIBUTES Attributes; + + // + // keyboard modifier state + // + HIDP_KEYBOARD_MODIFIER_STATE ModifierState; + +}KBDHID_DEVICE_EXTENSION, *PKBDHID_DEVICE_EXTENSION; + +/* defaults from kbfiltr.h */ +#define KEYBOARD_TYPEMATIC_RATE_MINIMUM 2 +#define KEYBOARD_TYPEMATIC_RATE_MAXIMUM 30 +#define KEYBOARD_TYPEMATIC_RATE_DEFAULT 30 +#define KEYBOARD_TYPEMATIC_DELAY_MINIMUM 250 +#define KEYBOARD_TYPEMATIC_DELAY_MAXIMUM 1000 +#define KEYBOARD_TYPEMATIC_DELAY_DEFAULT 250 + +/* FIXME: write kbd.h */ +#define MICROSOFT_KBD_FUNC 12 +#define KEYBOARD_TYPE_UNKNOWN (0x51) +#define MICROSOFT_KBD_101_TYPE 0 + + + + +NTSTATUS +KbdHid_InitiateRead( + IN PKBDHID_DEVICE_EXTENSION DeviceExtension); + diff --git a/drivers/hid/kbdhid/kbdhid.rc b/drivers/hid/kbdhid/kbdhid.rc new file mode 100644 index 00000000000..317d71e2932 --- /dev/null +++ b/drivers/hid/kbdhid/kbdhid.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Keyboard HID Class Driver\0" +#define REACTOS_STR_INTERNAL_NAME "kbdhid\0" +#define REACTOS_STR_ORIGINAL_FILENAME "kbdhid.sys\0" +#include diff --git a/drivers/hid/mouhid/CMakeLists.txt b/drivers/hid/mouhid/CMakeLists.txt new file mode 100644 index 00000000000..a9211715f2c --- /dev/null +++ b/drivers/hid/mouhid/CMakeLists.txt @@ -0,0 +1,13 @@ + +add_definitions(-DDEBUG_MODE) + +include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include) + +add_library(mouhid SHARED mouhid.c mouhid.rc) + +set_module_type(mouhid kernelmodedriver) +add_importlibs(mouhid ntoskrnl hal hidparse) +add_cab_target(mouhid 2) + +add_cab_target(mouhid 2) + diff --git a/drivers/hid/mouhid/mouhid.c b/drivers/hid/mouhid/mouhid.c new file mode 100644 index 00000000000..b61af2feb3a --- /dev/null +++ b/drivers/hid/mouhid/mouhid.c @@ -0,0 +1,962 @@ +/* + * PROJECT: ReactOS HID Stack + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/hid/mouhid/mouhid.c + * PURPOSE: Mouse HID Driver + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "mouhid.h" + +static USHORT MouHid_ButtonUpFlags[] = +{ + 0xFF, /* unused */ + MOUSE_LEFT_BUTTON_DOWN, + MOUSE_RIGHT_BUTTON_DOWN, + MOUSE_MIDDLE_BUTTON_DOWN, + MOUSE_BUTTON_4_DOWN, + MOUSE_BUTTON_5_DOWN +}; + +static USHORT MouHid_ButtonDownFlags[] = +{ + 0xFF, /* unused */ + MOUSE_LEFT_BUTTON_UP, + MOUSE_RIGHT_BUTTON_UP, + MOUSE_MIDDLE_BUTTON_UP, + MOUSE_BUTTON_4_UP, + MOUSE_BUTTON_5_UP +}; + +VOID +MouHid_GetButtonMove( + IN PMOUHID_DEVICE_EXTENSION DeviceExtension, + OUT PLONG LastX, + OUT PLONG LastY) +{ + NTSTATUS Status; + + /* init result */ + *LastX = 0; + *LastY = 0; + + /* get scaled usage value x */ + Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, (PLONG)LastX, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); + /* FIXME handle error */ + ASSERT(Status == HIDP_STATUS_SUCCESS); + + /* get scaled usage value y */ + Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, (PLONG)LastY, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); + /* FIXME handle error */ + ASSERT(Status == HIDP_STATUS_SUCCESS); + +} + + +VOID +MouHid_GetButtonFlags( + IN PMOUHID_DEVICE_EXTENSION DeviceExtension, + OUT PUSHORT ButtonFlags) +{ + NTSTATUS Status; + USAGE Usage; + ULONG Index; + PUSAGE TempList; + ULONG CurrentUsageListLength; + + /* init flags */ + *ButtonFlags = 0; + + /* get usages */ + CurrentUsageListLength = DeviceExtension->UsageListLength; + Status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, HIDP_LINK_COLLECTION_UNSPECIFIED, DeviceExtension->CurrentUsageList, &CurrentUsageListLength, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); + if (Status != HIDP_STATUS_SUCCESS) + { + DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status); + return; + } + + /* extract usage list difference */ + Status = HidP_UsageListDifference(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, DeviceExtension->BreakUsageList, DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength); + if (Status != HIDP_STATUS_SUCCESS) + { + DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status); + return; + } + + if (DeviceExtension->UsageListLength) + { + Index = 0; + do + { + /* get usage */ + Usage = DeviceExtension->BreakUsageList[Index]; + if (!Usage) + break; + + if (Usage <= 5) + { + /* max 5 buttons supported */ + *ButtonFlags |= MouHid_ButtonDownFlags[Usage]; + } + + /* move to next index*/ + Index++; + }while(Index < DeviceExtension->UsageListLength); + } + + if (DeviceExtension->UsageListLength) + { + Index = 0; + do + { + /* get usage */ + Usage = DeviceExtension->MakeUsageList[Index]; + if (!Usage) + break; + + if (Usage <= 5) + { + /* max 5 buttons supported */ + *ButtonFlags |= MouHid_ButtonUpFlags[Usage]; + } + + /* move to next index*/ + Index++; + }while(Index < DeviceExtension->UsageListLength); + } + + /* now switch the previous list with current list */ + TempList = DeviceExtension->CurrentUsageList; + DeviceExtension->CurrentUsageList = DeviceExtension->PreviousUsageList; + DeviceExtension->PreviousUsageList = TempList; +} + +VOID +MouHid_DispatchInputData( + IN PMOUHID_DEVICE_EXTENSION DeviceExtension, + IN PMOUSE_INPUT_DATA InputData) +{ + KIRQL OldIrql; + ULONG InputDataConsumed; + + if (!DeviceExtension->ClassService) + return; + + /* sanity check */ + ASSERT(DeviceExtension->ClassService); + ASSERT(DeviceExtension->ClassDeviceObject); + + /* raise irql */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + /* dispatch input data */ + (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed); + + /* lower irql to previous level */ + KeLowerIrql(OldIrql); +} + +NTSTATUS +NTAPI +MouHid_ReadCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PMOUHID_DEVICE_EXTENSION DeviceExtension; + USHORT ButtonFlags; + LONG UsageValue; + NTSTATUS Status; + LONG LastX, LastY; + MOUSE_INPUT_DATA MouseInputData; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)Context; + + if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD || + Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED || + Irp->IoStatus.Status == STATUS_CANCELLED || + DeviceExtension->StopReadReport) + { + /* failed to read or should be stopped*/ + DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status); + + /* report no longer active */ + DeviceExtension->ReadReportActive = FALSE; + + /* request stopping of the report cycle */ + DeviceExtension->StopReadReport = FALSE; + + /* signal completion event */ + KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + /* get mouse change flags */ + MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags); + + /* get mouse change */ + MouHid_GetButtonMove(DeviceExtension, &LastX, &LastY); + + /* init input data */ + RtlZeroMemory(&MouseInputData, sizeof(MOUSE_INPUT_DATA)); + + /* init input data */ + MouseInputData.ButtonFlags = ButtonFlags; + MouseInputData.LastX = LastX; + MouseInputData.LastY = LastY; + + /* detect mouse wheel change */ + if (DeviceExtension->MouseIdentifier == WHEELMOUSE_HID_HARDWARE) + { + /* get usage */ + UsageValue = 0; + Status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &UsageValue, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength); + if (Status == HIDP_STATUS_SUCCESS) + { + /* store wheel status */ + MouseInputData.ButtonFlags |= MOUSE_WHEEL; + MouseInputData.ButtonData = (USHORT)UsageValue; /* FIXME */ + } + else + { + DPRINT1("[MOUHID] failed to get wheel status with %x\n", Status); + } + } + + DPRINT1("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.ButtonFlags, MouseInputData.ButtonData); + + /* dispatch mouse action */ + MouHid_DispatchInputData(DeviceExtension, &MouseInputData); + + /* re-init read */ + MouHid_InitiateRead(DeviceExtension); + + /* stop completion */ + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +MouHid_InitiateRead( + IN PMOUHID_DEVICE_EXTENSION DeviceExtension) +{ + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + + /* re-use irp */ + IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS); + + /* init irp */ + DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL; + + /* get next stack location */ + IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp); + + /* init stack location */ + IoStack->Parameters.Read.Length = DeviceExtension->ReportLength; + IoStack->Parameters.Read.Key = 0; + IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL; + IoStack->MajorFunction = IRP_MJ_READ; + IoStack->FileObject = DeviceExtension->FileObject; + + /* set completion routine */ + IoSetCompletionRoutine(DeviceExtension->Irp, MouHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE); + + /* read is active */ + DeviceExtension->ReadReportActive = TRUE; + + /* start the read */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp); + + /* done */ + return Status; +} + +NTSTATUS +NTAPI +MouHid_CreateCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + KeSetEvent((PKEVENT)Context, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +NTSTATUS +NTAPI +MouHid_Create( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + KEVENT Event; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + + DPRINT1("MOUHID: IRP_MJ_CREATE\n"); + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* get stack location */ + IoStack = IoGetCurrentIrpStackLocation(Irp); + + /* copy stack location to next */ + IoCopyCurrentIrpStackLocationToNext(Irp); + + /* init event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* prepare irp */ + IoSetCompletionRoutine(Irp, MouHid_CreateCompletion, &Event, TRUE, TRUE, TRUE); + + /* call lower driver */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + /* request pending */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + } + + /* check for success */ + if (!NT_SUCCESS(Status)) + { + /* failed */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + /* is the driver already in use */ + if (DeviceExtension->FileObject == NULL) + { + /* did the caller specify correct attributes */ + ASSERT(IoStack->Parameters.Create.SecurityContext); + if (IoStack->Parameters.Create.SecurityContext->DesiredAccess) + { + /* store file object */ + DeviceExtension->FileObject = IoStack->FileObject; + + /* reset event */ + KeResetEvent(&DeviceExtension->ReadCompletionEvent); + + /* initiating read */ + Status = MouHid_InitiateRead(DeviceExtension); + DPRINT1("[MOUHID] MouHid_InitiateRead: status %x\n", Status); + if (Status == STATUS_PENDING) + { + /* report irp is pending */ + Status = STATUS_SUCCESS; + } + } + } + + /* complete request */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + + +NTSTATUS +NTAPI +MouHid_Close( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PMOUHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); + + if (DeviceExtension->ReadReportActive) + { + /* request stopping of the report cycle */ + DeviceExtension->StopReadReport = TRUE; + + /* wait until the reports have been read */ + KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); + + /* cancel irp */ + IoCancelIrp(DeviceExtension->Irp); + } + + DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); + + /* remove file object */ + DeviceExtension->FileObject = NULL; + + /* skip location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* pass irp to down the stack */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); +} + +NTSTATUS +NTAPI +MouHid_InternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PMOUSE_ATTRIBUTES Attributes; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + PCONNECT_DATA Data; + + /* get current stack location */ + IoStack = IoGetCurrentIrpStackLocation(Irp); + + DPRINT1("[MOUHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* handle requests */ + if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUSE_QUERY_ATTRIBUTES) + { + /* verify output buffer length */ + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES)) + { + /* invalid request */ + DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n"); + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_BUFFER_TOO_SMALL; + } + + /* get output buffer */ + Attributes = (PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer; + + /* type of mouse */ + Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier; + + /* number of buttons */ + Attributes->NumberOfButtons = DeviceExtension->UsageListLength; + + /* sample rate not used for usb */ + Attributes->SampleRate = 0; + + /* queue length */ + Attributes->InputDataQueueLength = 2; + + DPRINT1("[MOUHID] MouseIdentifier %x\n", Attributes->MouseIdentifier); + DPRINT1("[MOUHID] NumberOfButtons %x\n", Attributes->NumberOfButtons); + DPRINT1("[MOUHID] SampleRate %x\n", Attributes->SampleRate); + DPRINT1("[MOUHID] InputDataQueueLength %x\n", Attributes->InputDataQueueLength); + + /* complete request */ + Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_CONNECT) + { + /* verify input buffer length */ + if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) + { + /* invalid request */ + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; + } + + /* is it already connected */ + if (DeviceExtension->ClassService) + { + /* already connected */ + Irp->IoStatus.Status = STATUS_SHARING_VIOLATION; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SHARING_VIOLATION; + } + + /* get connect data */ + Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + /* store connect details */ + DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject; + DeviceExtension->ClassService = Data->ClassService; + + /* completed successfully */ + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT) + { + /* not supported */ + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_ENABLE) + { + /* not supported */ + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_SUPPORTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISABLE) + { + /* not supported */ + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_DEVICE_REQUEST; + } + + DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + /* unknown request not supported */ + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS +NTAPI +MouHid_DeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PMOUHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* skip stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* pass and forget */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); +} + +NTSTATUS +NTAPI +MouHid_Power( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +MouHid_SubmitRequest( + PDEVICE_OBJECT DeviceObject, + ULONG IoControlCode, + ULONG InputBufferSize, + PVOID InputBuffer, + ULONG OutputBufferSize, + PVOID OutputBuffer) +{ + KEVENT Event; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + PIRP Irp; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatus; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* init event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* build request */ + Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus); + if (!Irp) + { + /* no memory */ + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* send request */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + /* wait for request to complete */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + } + + /* done */ + return Status; +} + +NTSTATUS +NTAPI +MouHid_StartDevice( + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + ULONG Buttons; + HID_COLLECTION_INFORMATION Information; + PVOID PreparsedData; + HIDP_CAPS Capabilities; + ULONG ValueCapsLength; + HIDP_VALUE_CAPS ValueCaps; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + PUSHORT Buffer; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* query collection information */ + Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information); + if (!NT_SUCCESS(Status)) + { + /* failed to query collection information */ + DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status); + return Status; + } + + /* lets allocate space for preparsed data */ + PreparsedData = ExAllocatePool(NonPagedPool, Information.DescriptorSize); + if (!PreparsedData) + { + /* no memory */ + DPRINT1("[MOUHID] no memory size %u\n", Information.DescriptorSize); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* now obtain the preparsed data */ + Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 0, NULL, Information.DescriptorSize, PreparsedData); + if (!NT_SUCCESS(Status)) + { + /* failed to get preparsed data */ + DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status); + ExFreePool(PreparsedData); + return Status; + } + + /* lets get the caps */ + Status = HidP_GetCaps(PreparsedData, &Capabilities); + if (Status != HIDP_STATUS_SUCCESS) + { + /* failed to get capabilities */ + DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status); + ExFreePool(PreparsedData); + return Status; + } + + DPRINT1("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength); + + /* verify capabilities */ + if (Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC) + { + /* not supported */ + ExFreePool(PreparsedData); + return STATUS_UNSUCCESSFUL; + } + + /* init input report*/ + DeviceExtension->ReportLength = Capabilities.InputReportByteLength; + ASSERT(DeviceExtension->ReportLength); + DeviceExtension->Report = (PUCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength); + ASSERT(DeviceExtension->Report); + RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength); + + /* build mdl */ + DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL); + ASSERT(DeviceExtension->ReportMDL); + + /* init mdl */ + MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL); + + /* get max number of buttons */ + Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData); + DPRINT1("[MOUHID] Buttons %lu\n", Buttons); + ASSERT(Buttons > 0); + + /* now allocate an array for those buttons */ + Buffer = ExAllocatePool(NonPagedPool, sizeof(USAGE) * 4 * Buttons); + if (!Buffer) + { + /* no memory */ + ExFreePool(PreparsedData); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* init usage lists */ + RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons); + DeviceExtension->CurrentUsageList = Buffer; + Buffer += Buttons; + DeviceExtension->PreviousUsageList = Buffer; + Buffer += Buttons; + DeviceExtension->MakeUsageList = Buffer; + Buffer += Buttons; + DeviceExtension->BreakUsageList = Buffer; + + /* store number of buttons */ + DeviceExtension->UsageListLength = (USHORT)Buttons; + + /* store preparsed data */ + DeviceExtension->PreparsedData = PreparsedData; + + ValueCapsLength = 1; + HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, &ValueCaps, &ValueCapsLength, PreparsedData); + + ValueCapsLength = 1; + HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, &ValueCaps, &ValueCapsLength, PreparsedData); + + /* now check for wheel mouse support */ + ValueCapsLength = 1; + Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &ValueCaps, &ValueCapsLength, PreparsedData); + if (Status == HIDP_STATUS_SUCCESS ) + { + /* mouse has wheel support */ + DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE; + DeviceExtension->WheelUsagePage = ValueCaps.UsagePage; + DPRINT1("[MOUHID] mouse wheel support detected\n", Status); + } + else + { + /* check if the mouse has z-axis */ + ValueCapsLength = 1; + Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Z, &ValueCaps, &ValueCapsLength, PreparsedData); + if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1) + { + /* wheel support */ + DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE; + DeviceExtension->WheelUsagePage = ValueCaps.UsagePage; + DPRINT1("[MOUHID] mouse wheel support detected with z-axis\n", Status); + } + } + + /* completed successfully */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +MouHid_StartDeviceCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + KeSetEvent((PKEVENT)Context, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +MouHid_Flush( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* skip current stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* get next stack location */ + IoStack = IoGetNextIrpStackLocation(Irp); + + /* change request to hid flush queue request */ + IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE; + + /* call device */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); +} + +NTSTATUS +NTAPI +MouHid_Pnp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + KEVENT Event; + NTSTATUS Status; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* get current irp stack */ + IoStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT1("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction); + + if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || IoStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) + { + /* indicate success */ + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* skip irp stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* dispatch to lower device */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + } + else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE) + { + /* FIXME synchronization */ + + /* cancel irp */ + IoCancelIrp(DeviceExtension->Irp); + + /* indicate success */ + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* skip irp stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* dispatch to lower device */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + + IoFreeIrp(DeviceExtension->Irp); + IoDetachDevice(DeviceExtension->NextDeviceObject); + IoDeleteDevice(DeviceObject); + return Status; + } + else if (IoStack->MinorFunction == IRP_MN_START_DEVICE) + { + /* init event */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + /* copy stack location */ + IoCopyCurrentIrpStackLocationToNext (Irp); + + /* set completion routine */ + IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE); + Irp->IoStatus.Status = 0; + + /* pass request */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = Irp->IoStatus.Status; + } + + if (!NT_SUCCESS(Status)) + { + /* failed */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + /* lets start the device */ + Status = MouHid_StartDevice(DeviceObject); + DPRINT1("MouHid_StartDevice %x\n", Status); + + /* complete request */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + /* done */ + return Status; + } + else + { + /* skip irp stack location */ + IoSkipCurrentIrpStackLocation(Irp); + + /* dispatch to lower device */ + return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + } +} + +NTSTATUS +NTAPI +MouHid_AddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + NTSTATUS Status; + PDEVICE_OBJECT DeviceObject, NextDeviceObject; + PMOUHID_DEVICE_EXTENSION DeviceExtension; + POWER_STATE State; + + /* create device object */ + Status = IoCreateDevice(DriverObject, sizeof(MOUHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &DeviceObject); + if (!NT_SUCCESS(Status)) + { + /* failed to create device object */ + return Status; + } + + /* now attach it */ + NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); + if (!NextDeviceObject) + { + /* failed to attach */ + IoDeleteDevice(DeviceObject); + return STATUS_DEVICE_NOT_CONNECTED; + } + + /* get device extension */ + DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + /* zero extension */ + RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION)); + + /* init device extension */ + DeviceExtension->MouseIdentifier = MOUSE_HID_HARDWARE; + DeviceExtension->WheelUsagePage = 0; + DeviceExtension->NextDeviceObject = NextDeviceObject; + KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE); + DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE); + + /* FIXME handle allocation error */ + ASSERT(DeviceExtension->Irp); + + /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */ + + /* set power state to D0 */ + State.DeviceState = PowerDeviceD0; + PoSetPowerState(DeviceObject, DevicePowerState, State); + + /* init device object */ + DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + /* completed successfully */ + return STATUS_SUCCESS; +} + +VOID +NTAPI +MouHid_Unload( + IN PDRIVER_OBJECT DriverObject) +{ + UNIMPLEMENTED +} + + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegPath) +{ + /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */ + + /* initialize driver object */ + DriverObject->DriverUnload = MouHid_Unload; + DriverObject->DriverExtension->AddDevice = MouHid_AddDevice; + DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close; + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MouHid_Flush; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_DeviceControl; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl; + DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power; + DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp; + DriverObject->DriverUnload = MouHid_Unload; + DriverObject->DriverExtension->AddDevice = MouHid_AddDevice; + + /* done */ + return STATUS_SUCCESS; +} diff --git a/drivers/hid/mouhid/mouhid.h b/drivers/hid/mouhid/mouhid.h new file mode 100644 index 00000000000..95461734fc9 --- /dev/null +++ b/drivers/hid/mouhid/mouhid.h @@ -0,0 +1,116 @@ +#pragma once + +#define _HIDPI_NO_FUNCTION_MACROS_ +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct +{ + // + // lower device object + // + PDEVICE_OBJECT NextDeviceObject; + + // + // irp which is used for reading input reports + // + PIRP Irp; + + // + // event + // + KEVENT ReadCompletionEvent; + + // + // device object for class callback + // + PDEVICE_OBJECT ClassDeviceObject; + + // + // class callback + // + PVOID ClassService; + + // + // mouse type + // + USHORT MouseIdentifier; + + // + // wheel usage page + // + USHORT WheelUsagePage; + + // + // usage list length + // + USHORT UsageListLength; + + // + // current usage list length + // + PUSAGE CurrentUsageList; + + // + // previous usage list + // + PUSAGE PreviousUsageList; + + // + // removed usage item list + // + PUSAGE BreakUsageList; + + // + // new item usage list + // + PUSAGE MakeUsageList; + + // + // preparsed data + // + PVOID PreparsedData; + + // + // mdl for reading input report + // + PMDL ReportMDL; + + // + // input report buffer + // + PUCHAR Report; + + // + // input report length + // + ULONG ReportLength; + + // + // file object the device is reading reports from + // + PFILE_OBJECT FileObject; + + // + // report read is active + // + UCHAR ReadReportActive; + + // + // stop reading flag + // + UCHAR StopReadReport; + +}MOUHID_DEVICE_EXTENSION, *PMOUHID_DEVICE_EXTENSION; + + +NTSTATUS +MouHid_InitiateRead( + IN PMOUHID_DEVICE_EXTENSION DeviceExtension); diff --git a/drivers/hid/mouhid/mouhid.rc b/drivers/hid/mouhid/mouhid.rc new file mode 100644 index 00000000000..ae82d18f99b --- /dev/null +++ b/drivers/hid/mouhid/mouhid.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Mouse HID Class Driver\0" +#define REACTOS_STR_INTERNAL_NAME "mouhid\0" +#define REACTOS_STR_ORIGINAL_FILENAME "mouhid.sys\0" +#include diff --git a/drivers/usb/CMakeLists.txt b/drivers/usb/CMakeLists.txt index d208ed23e8b..f0928fa9a0d 100644 --- a/drivers/usb/CMakeLists.txt +++ b/drivers/usb/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory(hidparse) add_subdirectory(nt4compat) add_subdirectory(usbd) add_subdirectory(usbehci_new) diff --git a/drivers/usb/hidusb/hidusb.c b/drivers/usb/hidusb/hidusb.c deleted file mode 100644 index 56af50a6516..00000000000 --- a/drivers/usb/hidusb/hidusb.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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" - -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); - - // - // complete request - // - Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - // - // informal debug print - // - DPRINT1("HIDUSB Request: %x\n", IoStack->MajorFunction); - - // - // done - // - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -HidInternalDeviceControl( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -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); -} - -NTSTATUS -NTAPI -HidPnp( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - UNIMPLEMENTED - ASSERT(FALSE); - return STATUS_NOT_IMPLEMENTED; -} - -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; - - // - // 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 - // - DPRINT1("********* HIDUSB *********\n"); - DPRINT1("HIDUSB Registration Status %x\n", Status); - - return Status; -} diff --git a/drivers/usb/hidusb/hidusb.h b/drivers/usb/hidusb/hidusb.h deleted file mode 100644 index e991861d25a..00000000000 --- a/drivers/usb/hidusb/hidusb.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#define _HIDPI_ -#define _HIDPI_NO_FUNCTION_MACROS_ -#include -#include -#include - -typedef struct -{ - // - // event for completion - // - KEVENT Event; - - // - // list for pending requests - // - LIST_ENTRY PendingRequests; - -}HID_USB_DEVICE_EXTENSION, *PHID_USB_DEVICE_EXTENSION; - diff --git a/drivers/usb/usbehci_new/hub_controller.cpp b/drivers/usb/usbehci_new/hub_controller.cpp index b76a00fb4df..4c50e20ed77 100644 --- a/drivers/usb/usbehci_new/hub_controller.cpp +++ b/drivers/usb/usbehci_new/hub_controller.cpp @@ -60,13 +60,16 @@ public: VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine); // internal ioctl routines NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleGetDescriptorFromInterface(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleSelectInterface(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassInterface(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb); friend VOID StatusChangeEndpointCallBack(PVOID Context); @@ -756,6 +759,47 @@ CHubController::HandlePower( IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleIsochronousTransfer( + IN OUT PIRP Irp, + PURB Urb) +{ + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndPointDesc = NULL; + + // + // Check PipeHandle to determine if this is a Bulk or Interrupt Transfer Request + // + EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle; + + if (!EndPointDesc) + { + DPRINT1("No EndpointDesc\n"); + Urb->UrbIsochronousTransfer.Hdr.Status = USBD_STATUS_INVALID_PIPE_HANDLE; + return STATUS_INVALID_PARAMETER; + } + + // + // sanity checks + // + ASSERT(EndPointDesc); + ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS); + + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + return UsbDevice->SubmitIrp(Irp); +} + //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleBulkOrInterruptTransfer( @@ -794,22 +838,11 @@ CHubController::HandleBulkOrInterruptTransfer( // EndPointDesc = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle; - switch(EndPointDesc->bmAttributes & 0x0F) - { - case USB_ENDPOINT_TYPE_CONTROL: - DPRINT1("Control Transfer is not expected!!!\n"); - return STATUS_INVALID_DEVICE_REQUEST; - case USB_ENDPOINT_TYPE_BULK: - DPRINT("Initiating Bulk Transfer\n"); - break; - case USB_ENDPOINT_TYPE_ISOCHRONOUS: - case USB_ENDPOINT_TYPE_INTERRUPT: - DPRINT1("Not Supported\n"); - break; - default: - DPRINT1("Unknown EndPoint Type!\n"); - break; - } + // + // sanity checks + // + ASSERT(EndPointDesc); + ASSERT((EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK || (EndPointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT); // // check if this is a valid usb device handle @@ -1086,7 +1119,10 @@ CHubController::HandleGetStatusFromDevice( IN OUT PIRP Irp, PURB Urb) { - PUSHORT Status; + PUSHORT DeviceStatus; + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PUSBDEVICE UsbDevice; // // sanity checks @@ -1094,22 +1130,54 @@ CHubController::HandleGetStatusFromDevice( PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT)); PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer); - PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL); // // get status buffer // - Status = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer; + DeviceStatus = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer; + + + if (Urb->UrbHeader.UsbdDeviceHandle == NULL) + { + // + // FIXME need more flags ? + // + *DeviceStatus = USB_PORT_STATUS_CONNECT; + return STATUS_SUCCESS; + } // - // FIXME need more flags ? + // check if this is a valid usb device handle // - *Status = USB_PORT_STATUS_CONNECT; + ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + + // + // generate setup packet + // + CtrlSetup.bRequest = USB_REQUEST_GET_STATUS; + CtrlSetup.wValue.LowByte = 0; + CtrlSetup.wValue.HiByte = 0; + CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength; + CtrlSetup.bmRequestType.B = 0x80; + + // + // submit setup packet + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer); + ASSERT(Status == STATUS_SUCCESS); + DPRINT1("CHubController::HandleGetStatusFromDevice Status %x Length %lu DeviceStatus %x\n", Status, Urb->UrbControlDescriptorRequest.TransferBufferLength, *DeviceStatus); // // done // - return STATUS_SUCCESS; + return Status; } //----------------------------------------------------------------------------------------- @@ -1122,6 +1190,8 @@ CHubController::HandleClassDevice( PUSB_HUB_DESCRIPTOR UsbHubDescriptor; ULONG PortCount, Dummy2; USHORT Dummy1; + PUSBDEVICE UsbDevice; + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; DPRINT("CHubController::HandleClassDevice Request %x Class %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value >> 8); @@ -1130,6 +1200,36 @@ CHubController::HandleClassDevice( // switch(Urb->UrbControlVendorClassRequest.Request) { + case USB_REQUEST_GET_STATUS: + { + // + // check if this is a valid usb device handle + // + ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + + // + // generate setup packet + // + CtrlSetup.bRequest = USB_REQUEST_GET_STATUS; + CtrlSetup.wValue.LowByte = Urb->UrbControlVendorClassRequest.Index; + CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; + CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; + CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength; + CtrlSetup.bmRequestType.B = 0xA0; + + // + // submit setup packet + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer); + ASSERT(Status == STATUS_SUCCESS); + break; + } case USB_REQUEST_GET_DESCRIPTOR: { switch (Urb->UrbControlVendorClassRequest.Value >> 8) @@ -1191,6 +1291,55 @@ CHubController::HandleClassDevice( return Status; } + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleGetDescriptorFromInterface( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + PUSBDEVICE UsbDevice; + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + + // + // sanity check + // + ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength); + ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer); + + // + // check if this is a valid usb device handle + // + ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + // + // generate setup packet + // + CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR; + CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index; + CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType; + CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId; + CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength; + CtrlSetup.bmRequestType.B = 0x81; + + // + // submit setup packet + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer); + ASSERT(Status == STATUS_SUCCESS); + + // + // done + // + return Status; +} + //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleGetDescriptor( @@ -1300,8 +1449,6 @@ CHubController::HandleGetDescriptor( } else { - DPRINT1("Length %u\n", Urb->UrbControlDescriptorRequest.TransferBufferLength); - // // check if this is a valid usb device handle // @@ -1392,7 +1539,7 @@ CHubController::HandleGetDescriptor( //----------------------------------------------------------------------------------------- NTSTATUS -CHubController::HandleClassInterface( +CHubController::HandleClassEndpoint( IN OUT PIRP Irp, IN OUT PURB Urb) { @@ -1418,6 +1565,70 @@ CHubController::HandleClassInterface( UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + DPRINT1("URB_FUNCTION_CLASS_ENDPOINT\n"); + DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags); + DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength); + DPRINT1("TransferBuffer %x\n", Urb->UrbControlVendorClassRequest.TransferBuffer); + DPRINT1("TransferBufferMDL %x\n", Urb->UrbControlVendorClassRequest.TransferBufferMDL); + DPRINT1("RequestTypeReservedBits %x\n", Urb->UrbControlVendorClassRequest.RequestTypeReservedBits); + DPRINT1("Request %x\n", Urb->UrbControlVendorClassRequest.Request); + DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value); + DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index); + + // + // initialize setup packet + // + CtrlSetup.bmRequestType.B = 0xa2; //FIXME: Const. + CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; + CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; + CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; + CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength; + + // + // issue request + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlVendorClassRequest.TransferBufferLength, Urb->UrbControlVendorClassRequest.TransferBuffer); + + // + // assert on failure + // + PC_ASSERT(NT_SUCCESS(Status)); + + + // + // done + // + return Status; +} + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleClassInterface( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PUSBDEVICE UsbDevice; + + // + // sanity check + // + //ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer || Urb->UrbControlVendorClassRequest.TransferBufferMDL); + //ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength); + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + + // + // check if this is a valid usb device handle + // + PC_ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))); + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + DPRINT1("URB_FUNCTION_CLASS_INTERFACE\n"); DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags); DPRINT1("TransferBufferLength %x\n", Urb->UrbControlVendorClassRequest.TransferBufferLength); @@ -1490,6 +1701,9 @@ CHubController::HandleDeviceControl( switch (Urb->UrbHeader.Function) { + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + Status = HandleGetDescriptorFromInterface(Irp, Urb); + break; case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: Status = HandleGetDescriptor(Irp, Urb); break; @@ -1511,9 +1725,15 @@ CHubController::HandleDeviceControl( case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: Status = HandleBulkOrInterruptTransfer(Irp, Urb); break; + case URB_FUNCTION_ISOCH_TRANSFER: + Status = HandleIsochronousTransfer(Irp, Urb); + break; case URB_FUNCTION_CLASS_INTERFACE: Status = HandleClassInterface(Irp, Urb); break; + case URB_FUNCTION_CLASS_ENDPOINT: + Status = HandleClassEndpoint(Irp, Urb); + break; default: DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function); break; @@ -2301,12 +2521,8 @@ USBHI_RestoreUsbDevice( PC_ASSERT(Controller->ValidateUsbDevice(OldUsbDevice)); DPRINT1("NewUsbDevice: DeviceAddress %x\n", NewUsbDevice->GetDeviceAddress()); - - DPRINT1("OldUsbDevice: DeviceAddress %x\n", OldUsbDevice->GetDeviceAddress()); - PC_ASSERT(FALSE); - // // remove old device handle // diff --git a/drivers/usb/usbhub_new/fdo.c b/drivers/usb/usbhub_new/fdo.c index 06114094d58..89eb1665959 100644 --- a/drivers/usb/usbhub_new/fdo.c +++ b/drivers/usb/usbhub_new/fdo.c @@ -803,6 +803,7 @@ CreateDeviceIds( NTSTATUS Status; ULONG Index; PWCHAR BufferPtr; + WCHAR Buffer[100]; PHUB_CHILDDEVICE_EXTENSION UsbChildExtension; UsbChildExtension = (PHUB_CHILDDEVICE_EXTENSION)UsbChildDeviceObject->DeviceExtension; @@ -954,6 +955,28 @@ CreateDeviceIds( UsbChildExtension->usInstanceId.MaximumLength = UsbChildExtension->usInstanceId.Length; DPRINT1("Usb InstanceId %wZ\n", &UsbChildExtension->usInstanceId); } + else + { + // + // the device did not provide a serial number, lets create a pseudo instance id + // + Index = swprintf(Buffer, L"0&%04d", UsbChildExtension->PortNumber) + 1; + UsbChildExtension->usInstanceId.Buffer = (LPWSTR)ExAllocatePool(NonPagedPool, Index * sizeof(WCHAR)); + if (UsbChildExtension->usInstanceId.Buffer == NULL) + { + DPRINT1("Error: failed to allocate %lu bytes\n", Index * sizeof(WCHAR)); + goto Cleanup; + } + + // + // copy instance id + // + RtlCopyMemory(UsbChildExtension->usInstanceId.Buffer, Buffer, Index * sizeof(WCHAR)); + UsbChildExtension->usInstanceId.Length = UsbChildExtension->usDeviceId.MaximumLength = Index * sizeof(WCHAR); + + DPRINT1("usDeviceId %wZ\n", &UsbChildExtension->usInstanceId); + } + return Status; diff --git a/drivers/usb/usbohci/hardware.cpp b/drivers/usb/usbohci/hardware.cpp index c21e4c95154..4e68d666997 100644 --- a/drivers/usb/usbohci/hardware.cpp +++ b/drivers/usb/usbohci/hardware.cpp @@ -1364,7 +1364,7 @@ InterruptServiceRoutine( // // defer processing // - DPRINT1("Status %x Acknowledge %x FrameNumber %x\n", Status, Acknowledge, This->m_HCCA->CurrentFrameNumber); + DPRINT("Status %x Acknowledge %x FrameNumber %x\n", Status, Acknowledge, This->m_HCCA->CurrentFrameNumber); KeInsertQueueDpc(&This->m_IntDpcObject, (PVOID)Status, (PVOID)(DoneHead & ~1)); // diff --git a/drivers/usb/usbohci/hub_controller.cpp b/drivers/usb/usbohci/hub_controller.cpp index 24e08a82c75..67761753312 100644 --- a/drivers/usb/usbohci/hub_controller.cpp +++ b/drivers/usb/usbohci/hub_controller.cpp @@ -1634,6 +1634,12 @@ CHubController::HandleClassInterface( DPRINT1("Value %x\n", Urb->UrbControlVendorClassRequest.Value); DPRINT1("Index %x\n", Urb->UrbControlVendorClassRequest.Index); + if (Urb->UrbControlVendorClassRequest.TransferBufferLength == 0) + { + DPRINT1("Invalid request length\n"); + return STATUS_SUCCESS; + } + // // initialize setup packet // diff --git a/drivers/usb/usbohci/usb_queue.cpp b/drivers/usb/usbohci/usb_queue.cpp index a2853fe072f..f3f993e7bee 100644 --- a/drivers/usb/usbohci/usb_queue.cpp +++ b/drivers/usb/usbohci/usb_queue.cpp @@ -620,7 +620,7 @@ CUSBQueue::TransferDescriptorCompletionCallback( POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, PreviousEndpointDescriptor; NTSTATUS Status; - DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback transfer descriptor %x\n", TransferDescriptorLogicalAddress); + DPRINT("CUSBQueue::TransferDescriptorCompletionCallback transfer descriptor %x\n", TransferDescriptorLogicalAddress); // // find transfer descriptor in control list diff --git a/drivers/usb/usbohci/usb_request.cpp b/drivers/usb/usbohci/usb_request.cpp index f6762c079c1..8fe03208248 100644 --- a/drivers/usb/usbohci/usb_request.cpp +++ b/drivers/usb/usbohci/usb_request.cpp @@ -941,7 +941,7 @@ CUSBRequest::AllocateEndpointDescriptor( Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress()); Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize()); - DPRINT1("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize()); + DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize()); // // is there an endpoint descriptor diff --git a/include/ddk/hidclass.h b/include/ddk/hidclass.h index c93bfb4a525..a523f882991 100644 --- a/include/ddk/hidclass.h +++ b/include/ddk/hidclass.h @@ -73,16 +73,9 @@ DEFINE_GUID (GUID_HID_INTERFACE_HIDPARSE, \ #define IOCTL_HID_GET_DRIVER_CONFIG HID_BUFFER_CTL_CODE(100) #define IOCTL_HID_SET_DRIVER_CONFIG HID_BUFFER_CTL_CODE(101) +#define IOCTL_HID_GET_INDEXED_STRING HID_OUT_CTL_CODE(120) #define IOCTL_HID_GET_MS_GENRE_DESCRIPTOR HID_OUT_CTL_CODE(121) -/* FIXME: these values are wrong! */ -#define IOCTL_HID_GET_STRING 0 -#define IOCTL_HID_GET_DEVICE_ATTRIBUTES 1 -#define IOCTL_HID_GET_DEVICE_DESCRIPTOR 2 -#define IOCTL_HID_READ_REPORT 3 -#define IOCTL_HID_WRITE_REPORT 4 -#define IOCTL_HID_GET_REPORT_DESCRIPTOR 5 - typedef enum _HID_STRING_TYPE { HID_STRING_INDEXED = 0, diff --git a/include/ddk/hidpddi.h b/include/ddk/hidpddi.h index 165b402a4a7..3f142308530 100644 --- a/include/ddk/hidpddi.h +++ b/include/ddk/hidpddi.h @@ -43,6 +43,7 @@ typedef struct _HIDP_DEVICE_DESC }HIDP_DEVICE_DESC, *PHIDP_DEVICE_DESC; NTSTATUS +NTAPI HidP_GetCollectionDescription( IN PHIDP_REPORT_DESCRIPTOR ReportDesc, IN ULONG DescLength, @@ -51,11 +52,13 @@ HidP_GetCollectionDescription( ); VOID +NTAPI HidP_FreeCollectionDescription ( IN PHIDP_DEVICE_DESC DeviceDescription ); NTSTATUS +NTAPI HidP_SysPowerEvent ( IN PCHAR HidPacket, IN USHORT HidPacketLength, @@ -64,6 +67,7 @@ HidP_SysPowerEvent ( ); NTSTATUS +NTAPI HidP_SysPowerCaps ( IN PHIDP_PREPARSED_DATA Ppd, OUT PULONG OutputBuffer diff --git a/include/ddk/hidport.h b/include/ddk/hidport.h index 413f9ee1147..078f58ea9b5 100644 --- a/include/ddk/hidport.h +++ b/include/ddk/hidport.h @@ -50,8 +50,8 @@ typedef struct _HID_DESCRIPTOR typedef VOID -(*HID_SEND_IDLE_CALLBACK)( - __in PVOID Context +(NTAPI *HID_SEND_IDLE_CALLBACK)( + IN PVOID Context ); typedef struct _HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO diff --git a/include/psdk/hidusage.h b/include/psdk/hidusage.h index 1827c19dcec..af3386ec8bc 100644 --- a/include/psdk/hidusage.h +++ b/include/psdk/hidusage.h @@ -199,6 +199,14 @@ typedef USHORT USAGE, *PUSAGE; #define HID_USAGE_SIMULATION_RUDDER ((USAGE) 0xBA) #define HID_USAGE_SIMULATION_THROTTLE ((USAGE) 0xBB) + +#define HID_USAGE_CONSUMERCTRL ((USAGE)0x01) +#define HID_USAGE_DIGITIZER_PEN ((USAGE)0x02) +#define HID_USAGE_DIGITIZER_IN_RANGE ((USAGE)0x32) +#define HID_USAGE_DIGITIZER_TIP_SWITCH ((USAGE)0x42) +#define HID_USAGE_DIGITIZER_BARREL_SWITCH ((USAGE)0x44) + + #ifdef __cplusplus } #endif diff --git a/lib/drivers/CMakeLists.txt b/lib/drivers/CMakeLists.txt index 1d1e3812b84..c23d0636528 100644 --- a/lib/drivers/CMakeLists.txt +++ b/lib/drivers/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(chew) add_subdirectory(csq) +add_subdirectory(hidparser) add_subdirectory(ip) add_subdirectory(lwip) add_subdirectory(sound) diff --git a/lib/drivers/hidparser/CMakeLists.txt b/lib/drivers/hidparser/CMakeLists.txt new file mode 100644 index 00000000000..5d16301ce1e --- /dev/null +++ b/lib/drivers/hidparser/CMakeLists.txt @@ -0,0 +1,13 @@ + +add_definitions( + -DUNICODE -D_UNICODE + -DNDEBUG=1) + +list(APPEND SOURCE + hidparser.c + parser.c + api.c) + +add_library(hidparser ${SOURCE}) +add_dependencies(hidparser bugcodes) + diff --git a/lib/drivers/hidparser/api.c b/lib/drivers/hidparser/api.c new file mode 100644 index 00000000000..6c39d10ce2c --- /dev/null +++ b/lib/drivers/hidparser/api.c @@ -0,0 +1,1077 @@ +/* + * PROJECT: ReactOS HID Parser Library + * LICENSE: GPL - See COPYING in the top level directory + * FILE: lib/drivers/hidparser/api.c + * PURPOSE: HID Parser + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + + +#include "parser.h" + +static ULONG KeyboardScanCodes[256] = +{ + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, + 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, + 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140 +}; + + + +ULONG +HidParser_NumberOfTopCollections( + IN PHID_PARSER Parser) +{ + PHID_PARSER_CONTEXT ParserContext; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + ASSERT(ParserContext->RootCollection); + ASSERT(ParserContext->RootCollection->NodeCount); + + // + // number of top collections + // + return ParserContext->RootCollection->NodeCount; +} + +PHID_COLLECTION +HidParser_GetCollection( + IN PHID_PARSER Parser, + IN ULONG CollectionNumber) +{ + PHID_PARSER_CONTEXT ParserContext; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + ASSERT(ParserContext->RootCollection); + ASSERT(ParserContext->RootCollection->NodeCount); + + // + // is collection index out of bounds + // + if (CollectionNumber < ParserContext->RootCollection->NodeCount) + { + // + // valid collection + // + return ParserContext->RootCollection->Nodes[CollectionNumber]; + } + + // + // no such collection + // + Parser->Debug("HIDPARSE] No such collection %lu\n", CollectionNumber); + return NULL; +} + +PHID_REPORT +HidParser_GetReportByType( + IN PHID_PARSER Parser, + IN ULONG ReportType) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + ULONG ReportCount = 0; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + for(Index = 0; Index < ParserContext->ReportCount; Index++) + { + // + // check if the report type match + // + if (ParserContext->Reports[Index]->Type == ReportType) + { + // + // found report + // + return ParserContext->Reports[Index]; + } + } + + // + // report not found + // + return NULL; +} + + +ULONG +HidParser_NumberOfReports( + IN PHID_PARSER Parser, + IN ULONG ReportType) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + ULONG ReportCount = 0; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + for(Index = 0; Index < ParserContext->ReportCount; Index++) + { + // + // check if the report type match + // + if (ParserContext->Reports[Index]->Type == ReportType) + { + // + // found report + // + ReportCount++; + } + } + + // + // done + // + return ReportCount; +} + +HIDPARSER_STATUS +HidParser_GetCollectionUsagePage( + IN PHID_PARSER Parser, + IN ULONG CollectionIndex, + OUT PUSHORT Usage, + OUT PUSHORT UsagePage) +{ + PHID_COLLECTION Collection; + + // + // find collection + // + Collection = HidParser_GetCollection(Parser, CollectionIndex); + if (!Collection) + { + // + // collection not found + // + return HIDPARSER_STATUS_COLLECTION_NOT_FOUND; + } + + // + // store result + // + *UsagePage = (Collection->Usage >> 16); + *Usage = (Collection->Usage & 0xFFFF); + return HIDPARSER_STATUS_SUCCESS; +} + +ULONG +HidParser_GetReportLength( + IN PHID_PARSER Parser, + IN ULONG ReportType) +{ + PHID_PARSER_CONTEXT ParserContext; + PHID_REPORT Report; + ULONG ReportLength; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get first report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no report found + // + return 0; + } + + // + // get report length + // + ReportLength = Report->ReportSize; + + // + // done + // + if (ReportLength) + { + // + // byte aligned length + // + ASSERT(ReportLength % 8 == 0); + return ReportLength / 8; + } + return ReportLength; +} + +UCHAR +HidParser_IsReportIDUsed( + IN PHID_PARSER Parser) +{ + PHID_PARSER_CONTEXT ParserContext; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // return flag + // + return ParserContext->UseReportIDs; +} + +ULONG +HidParser_GetReportItemCountFromReportType( + IN PHID_PARSER Parser, + IN ULONG ReportType) +{ + PHID_PARSER_CONTEXT ParserContext; + PHID_REPORT Report; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no such report + // + return 0; + } + + // + // return report item count + // + return Report->ItemCount; +} + + +ULONG +HidParser_GetReportItemTypeCountFromReportType( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN ULONG bData) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + PHID_REPORT Report; + ULONG ItemCount = 0; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no such report + // + return 0; + } + + // + // enumerate all items + // + for(Index = 0; Index < Report->ItemCount; Index++) + { + // + // check item type + // + if (Report->Items[Index]->HasData && bData == TRUE) + { + // + // found data item + // + ItemCount++; + } + else if (Report->Items[Index]->HasData == FALSE && bData == FALSE) + { + // + // found value item + // + ItemCount++; + } + } + + // + // no report items + // + return ItemCount; +} + +ULONG +HidParser_GetContextSize( + IN PHID_PARSER Parser) +{ + // + // FIXME the context must contain all parsed info + // + return sizeof(HID_PARSER_CONTEXT); +} + +VOID +HidParser_FreeContext( + IN PHID_PARSER Parser, + IN PUCHAR Context, + IN ULONG ContextLength) +{ + // + // FIXME implement freeing of parsed info + // +} + +HIDPARSER_STATUS +HidParser_AllocateParser( + IN PHIDPARSER_ALLOC_FUNCTION AllocFunction, + IN PHIDPARSER_FREE_FUNCTION FreeFunction, + IN PHIDPARSER_ZERO_FUNCTION ZeroFunction, + IN PHIDPARSER_COPY_FUNCTION CopyFunction, + IN PHIDPARSER_DEBUG_FUNCTION DebugFunction, + OUT PHID_PARSER *OutParser) +{ + PHID_PARSER Parser; + PHID_PARSER_CONTEXT ParserContext; + + // + // allocate + // + Parser = (PHID_PARSER)AllocFunction(sizeof(HID_PARSER)); + if (!Parser) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // allocate parser context + // + ParserContext = (PHID_PARSER_CONTEXT)AllocFunction(sizeof(HID_PARSER_CONTEXT)); + if (!ParserContext) + { + // + // no memory + // + FreeFunction(Parser); + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + + // + // init parser + // + Parser->Alloc = AllocFunction; + Parser->Free = FreeFunction; + Parser->Zero = ZeroFunction; + Parser->Copy = CopyFunction; + Parser->Debug = DebugFunction; + Parser->ParserContext = ParserContext; + + // + // store result + // + *OutParser = Parser; + // + // success + // + return HIDPARSER_STATUS_SUCCESS; +} + +VOID +HidParser_InitParser( + IN PHIDPARSER_ALLOC_FUNCTION AllocFunction, + IN PHIDPARSER_FREE_FUNCTION FreeFunction, + IN PHIDPARSER_ZERO_FUNCTION ZeroFunction, + IN PHIDPARSER_COPY_FUNCTION CopyFunction, + IN PHIDPARSER_DEBUG_FUNCTION DebugFunction, + IN PVOID ParserContext, + OUT PHID_PARSER Parser) +{ + Parser->Alloc = AllocFunction; + Parser->Free = FreeFunction; + Parser->Zero = ZeroFunction; + Parser->Copy = CopyFunction; + Parser->Debug = DebugFunction; + Parser->ParserContext = ParserContext; +} + +ULONG +HidParser_GetCollectionCount( + IN PHID_COLLECTION Collection) +{ + ULONG Index; + ULONG Count = Collection->NodeCount; + + for(Index = 0; Index < Collection->NodeCount; Index++) + { + // + // count collection for sub nodes + // + Count += HidParser_GetCollectionCount(Collection->Nodes[Index]); + } + + // + // done + // + return Count; +} + +ULONG +HidParser_GetTotalCollectionCount( + IN PHID_PARSER Parser) +{ + PHID_PARSER_CONTEXT ParserContext; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity check + // + ASSERT(ParserContext); + ASSERT(ParserContext->RootCollection); + + // + // count collections + // + return HidParser_GetCollectionCount(ParserContext->RootCollection); +} + +ULONG +HidParser_GetMaxUsageListLengthWithReportAndPage( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USAGE UsagePage OPTIONAL) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + PHID_REPORT Report; + ULONG ItemCount = 0; + USHORT CurrentUsagePage; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no such report + // + return 0; + } + + for(Index = 0; Index < Report->ItemCount; Index++) + { + // + // check usage page + // + CurrentUsagePage = (Report->Items[Index]->UsageMinimum >> 16); + if (CurrentUsagePage == UsagePage && Report->Items[Index]->HasData) + { + // + // found item + // + ItemCount++; + } + } + + // + // done + // + return ItemCount; +} + +HIDPARSER_STATUS +HidParser_GetSpecificValueCapsWithReport( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USHORT UsagePage, + IN USHORT Usage, + OUT PHIDP_VALUE_CAPS ValueCaps, + IN OUT PULONG ValueCapsLength) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + PHID_REPORT Report; + ULONG ItemCount = 0; + USHORT CurrentUsagePage; + USHORT CurrentUsage; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no such report + // + return HIDPARSER_STATUS_REPORT_NOT_FOUND; + } + + for(Index = 0; Index < Report->ItemCount; Index++) + { + // + // check usage page + // + CurrentUsagePage = (Report->Items[Index]->UsageMinimum >> 16); + CurrentUsage = (Report->Items[Index]->UsageMinimum & 0xFFFF); + + if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0)) + { + // + // check if there is enough place for the caps + // + if (ItemCount < *ValueCapsLength) + { + // + // zero caps + // + Parser->Zero(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS)); + + // + // init caps + // + ValueCaps[ItemCount].UsagePage = CurrentUsagePage; + ValueCaps[ItemCount].ReportID = Report->ReportID; + ValueCaps[ItemCount].LogicalMin = Report->Items[Index]->Minimum; + ValueCaps[ItemCount].LogicalMax = Report->Items[Index]->Maximum; + ValueCaps[ItemCount].IsAbsolute = !Report->Items[Index]->Relative; + ValueCaps[ItemCount].BitSize = Report->Items[Index]->BitCount; + + // + // FIXME: FILLMEIN + // + } + + + // + // found item + // + ItemCount++; + } + } + + // + // store result + // + *ValueCapsLength = ItemCount; + + if (ItemCount) + { + // + // success + // + return HIDPARSER_STATUS_SUCCESS; + } + + // + // item not found + // + return HIDPARSER_STATUS_USAGE_NOT_FOUND; +} + +HIDPARSER_STATUS +HidParser_GetUsagesWithReport( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USAGE UsagePage, + OUT USAGE *UsageList, + IN OUT PULONG UsageLength, + IN PCHAR ReportDescriptor, + IN ULONG ReportDescriptorLength) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + PHID_REPORT Report; + ULONG ItemCount = 0; + USHORT CurrentUsagePage; + PHID_REPORT_ITEM ReportItem; + UCHAR Activated; + ULONG Data; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no such report + // + return HIDPARSER_STATUS_REPORT_NOT_FOUND; + } + + if (Report->ReportSize / 8 != (ReportDescriptorLength - 1)) + { + // + // invalid report descriptor length + // + return HIDPARSER_STATUS_INVALID_REPORT_LENGTH; + } + + for(Index = 0; Index < Report->ItemCount; Index++) + { + // + // get report item + // + ReportItem = Report->Items[Index]; + + // + // does it have data + // + if (!ReportItem->HasData) + continue; + + // + // check usage page + // + CurrentUsagePage = (ReportItem->UsageMinimum >> 16); + + // + // does usage match + // + if (UsagePage != CurrentUsagePage) + continue; + + // + // check if the specified usage is activated + // + ASSERT(ReportItem->ByteOffset < ReportDescriptorLength); + ASSERT(ReportItem->BitCount < 8); + + // + // one extra shift for skipping the prepended report id + // + Data = ReportDescriptor[ReportItem->ByteOffset + 1]; + + // + // shift data + // + Data >>= ReportItem->Shift; + + // + // clear unwanted bits + // + Data &= ReportItem->Mask; + + // + // is it activated + // + Activated = (Data != 0); + + if (!Activated) + continue; + + // + // is there enough space for the usage + // + if (ItemCount >= *UsageLength) + { + ItemCount++; + continue; + } + + // + // store item + // + UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF); + ItemCount++; + } + + if (ItemCount > *UsageLength) + { + // + // list too small + // + return HIDPARSER_STATUS_BUFFER_TOO_SMALL; + } + + // + // success, clear rest of array + // + Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE)); + + // + // store result size + // + *UsageLength = ItemCount; + + // + // done + // + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_GetScaledUsageValueWithReport( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USAGE UsagePage, + IN USAGE Usage, + OUT PLONG UsageValue, + IN PCHAR ReportDescriptor, + IN ULONG ReportDescriptorLength) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + PHID_REPORT Report; + ULONG ItemCount = 0; + USHORT CurrentUsagePage; + PHID_REPORT_ITEM ReportItem; + ULONG Data; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + // + // sanity checks + // + ASSERT(ParserContext); + + // + // FIXME support multiple top collecions + // + ASSERT(ParserContext->RootCollection->NodeCount == 1); + + // + // get report + // + Report = HidParser_GetReportByType(Parser, ReportType); + if (!Report) + { + // + // no such report + // + return HIDPARSER_STATUS_REPORT_NOT_FOUND; + } + + if (Report->ReportSize / 8 != (ReportDescriptorLength - 1)) + { + // + // invalid report descriptor length + // + return HIDPARSER_STATUS_INVALID_REPORT_LENGTH; + } + + for(Index = 0; Index < Report->ItemCount; Index++) + { + // + // get report item + // + ReportItem = Report->Items[Index]; + + // + // check usage page + // + CurrentUsagePage = (ReportItem->UsageMinimum >> 16); + + // + // does usage page match + // + if (UsagePage != CurrentUsagePage) + continue; + + // + // does the usage match + // + if (Usage != (ReportItem->UsageMinimum & 0xFFFF)) + continue; + + // + // check if the specified usage is activated + // + ASSERT(ReportItem->ByteOffset < ReportDescriptorLength); + + // + // one extra shift for skipping the prepended report id + // + Data = 0; + Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1))); + Data = ReportDescriptor[ReportItem->ByteOffset + 1]; + + // + // shift data + // + Data >>= ReportItem->Shift; + + // + // clear unwanted bits + // + Data &= ReportItem->Mask; + + if (ReportItem->Minimum > ReportItem->Maximum) + { + // + // logical boundaries are signed values + // + if ((Data & ~(ReportItem->Mask >> 1)) != 0) + { + Data |= ~ReportItem->Mask; + } + } + + // + // store result + // + *UsageValue = Data; + return HIDPARSER_STATUS_SUCCESS; + } + + // + // usage not found + // + return HIDPARSER_STATUS_USAGE_NOT_FOUND; +} + +ULONG +HidParser_GetScanCode( + IN USAGE Usage) +{ + if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0])) + { + // + // valid usage + // + return KeyboardScanCodes[Usage]; + } + + // + // invalid usage + // + return 0; +} + +VOID +HidParser_DispatchKey( + IN PCHAR ScanCodes, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext) +{ + ULONG Index; + ULONG Length = 0; + + // + // count code length + // + for(Index = 0; Index < sizeof(ULONG); Index++) + { + if (ScanCodes[Index] == 0) + { + // + // last scan code + // + break; + } + + // + // is this a key break + // + if (KeyAction == HidP_KeyboardBreak) + { + // + // add break + // + ScanCodes[Index] |= KEY_BREAK; + } + + // + // more scan counts + // + Length++; + } + + if (Length > 0) + { + // + // dispatch scan codes + // + InsertCodesProcedure(InsertCodesContext, ScanCodes, Length); + } +} + + +HIDPARSER_STATUS +HidParser_TranslateUsage( + IN PHID_PARSER Parser, + IN USAGE Usage, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext) +{ + ULONG ScanCode; + + // + // get scan code + // + ScanCode = HidParser_GetScanCode(Usage); + if (!ScanCode) + { + // + // invalid lookup or no scan code available + // + return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN; + } + + // + // FIXME: translate modifier states + // + + HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext); + + // + // done + // + return HIDPARSER_STATUS_SUCCESS; +} \ No newline at end of file diff --git a/lib/drivers/hidparser/hidparser.c b/lib/drivers/hidparser/hidparser.c new file mode 100644 index 00000000000..1a1fce50f6b --- /dev/null +++ b/lib/drivers/hidparser/hidparser.c @@ -0,0 +1,1159 @@ +/* + * PROJECT: ReactOS HID Parser Library + * LICENSE: GPL - See COPYING in the top level directory + * FILE: lib/drivers/hidparser/hidparser.c + * PURPOSE: HID Parser + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "parser.h" + +NTSTATUS +TranslateHidParserStatus( + IN HIDPARSER_STATUS Status) +{ + switch(Status) + { + case HIDPARSER_STATUS_INSUFFICIENT_RESOURCES: + return HIDP_STATUS_INTERNAL_ERROR; + case HIDPARSER_STATUS_NOT_IMPLEMENTED: + return HIDP_STATUS_NOT_IMPLEMENTED; + case HIDPARSER_STATUS_REPORT_NOT_FOUND: + return HIDP_STATUS_REPORT_DOES_NOT_EXIST; + case HIDPARSER_STATUS_INVALID_REPORT_LENGTH: + return HIDP_STATUS_INVALID_REPORT_LENGTH; + case HIDPARSER_STATUS_INVALID_REPORT_TYPE: + return HIDP_STATUS_INVALID_REPORT_TYPE; + case HIDPARSER_STATUS_BUFFER_TOO_SMALL: + return HIDP_STATUS_BUFFER_TOO_SMALL; + case HIDPARSER_STATUS_USAGE_NOT_FOUND: + return HIDP_STATUS_USAGE_NOT_FOUND; + case HIDPARSER_STATUS_I8042_TRANS_UNKNOWN: + return HIDP_STATUS_I8042_TRANS_UNKNOWN; + case HIDPARSER_STATUS_COLLECTION_NOT_FOUND: + return HIDP_STATUS_NOT_IMPLEMENTED; //FIXME + } + DPRINT1("TranslateHidParserStatus Status %ld not implemented\n", Status); + return HIDP_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HidParser_GetCollectionDescription( + IN PHID_PARSER Parser, + IN PHIDP_REPORT_DESCRIPTOR ReportDesc, + IN ULONG DescLength, + IN POOL_TYPE PoolType, + OUT PHIDP_DEVICE_DESC DeviceDescription) +{ + HIDPARSER_STATUS ParserStatus; + ULONG CollectionCount, ReportCount; + ULONG Index; + + // + // first parse the report descriptor + // + ParserStatus = HidParser_ParseReportDescriptor(Parser, ReportDesc, DescLength); + if (ParserStatus != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to parse report descriptor + // + Parser->Debug("[HIDPARSER] Failed to parse report descriptor with %x\n", ParserStatus); + return TranslateHidParserStatus(ParserStatus); + } + + // + // get collection count + // + CollectionCount = HidParser_NumberOfTopCollections(Parser); + + // + // FIXME: only one top level collection is supported + // + ASSERT(CollectionCount <= 1); + if (CollectionCount == 0) + { + // + // no top level collections found + // + return STATUS_NO_DATA_DETECTED; + } + + // + // zero description + // + Parser->Zero(DeviceDescription, sizeof(HIDP_DEVICE_DESC)); + + // + // allocate collection + // + DeviceDescription->CollectionDesc = (PHIDP_COLLECTION_DESC)Parser->Alloc(sizeof(HIDP_COLLECTION_DESC) * CollectionCount); + if (!DeviceDescription->CollectionDesc) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // allocate report description + // + DeviceDescription->ReportIDs = (PHIDP_REPORT_IDS)Parser->Alloc(sizeof(HIDP_REPORT_IDS) * CollectionCount); + if (!DeviceDescription->ReportIDs) + { + // + // no memory + // + Parser->Free(DeviceDescription->CollectionDesc); + return STATUS_INSUFFICIENT_RESOURCES; + } + + for(Index = 0; Index < CollectionCount; Index++) + { + // + // init report description + // + DeviceDescription->ReportIDs[Index].CollectionNumber = Index + 1; + DeviceDescription->ReportIDs[Index].ReportID = Index; //FIXME + DeviceDescription->ReportIDs[Index].InputLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_INPUT); + DeviceDescription->ReportIDs[Index].OutputLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_OUTPUT); + DeviceDescription->ReportIDs[Index].FeatureLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_FEATURE); + + // + // init collection description + // + DeviceDescription->CollectionDesc[Index].CollectionNumber = Index + 1; + + // + // get collection usage page + // + ParserStatus = HidParser_GetCollectionUsagePage(Parser, Index, &DeviceDescription->CollectionDesc[Index].Usage, &DeviceDescription->CollectionDesc[Index].UsagePage); + + // + // windows seems to prepend the report id, regardless if it is required + // + DeviceDescription->CollectionDesc[Index].InputLength = (DeviceDescription->ReportIDs[Index].InputLength > 0 ? DeviceDescription->ReportIDs[Index].InputLength + 1 : 0); + DeviceDescription->CollectionDesc[Index].OutputLength = (DeviceDescription->ReportIDs[Index].OutputLength > 0 ? DeviceDescription->ReportIDs[Index].OutputLength + 1 : 0); + DeviceDescription->CollectionDesc[Index].FeatureLength = (DeviceDescription->ReportIDs[Index].FeatureLength > 0 ? DeviceDescription->ReportIDs[Index].FeatureLength + 1 : 0); + + // + // set preparsed data length + // + DeviceDescription->CollectionDesc[Index].PreparsedDataLength = HidParser_GetContextSize(Parser); + DeviceDescription->CollectionDesc[Index].PreparsedData = Parser->Alloc(DeviceDescription->CollectionDesc[Index].PreparsedDataLength); + if (!DeviceDescription->CollectionDesc[Index].PreparsedData) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // copy context + // + Parser->Copy(DeviceDescription->CollectionDesc[Index].PreparsedData, Parser->ParserContext, DeviceDescription->CollectionDesc[Index].PreparsedDataLength); + } + + // + // store collection & report count + // + DeviceDescription->CollectionDescLength = CollectionCount; + DeviceDescription->ReportIDsLength = CollectionCount; + + // + // done + // + return STATUS_SUCCESS; +} + +VOID +NTAPI +HidParser_FreeCollectionDescription( + IN PHID_PARSER Parser, + IN PHIDP_DEVICE_DESC DeviceDescription) +{ + ULONG Index; + + // + // first free all context + // + for(Index = 0; Index < DeviceDescription->CollectionDescLength; Index++) + { + // + // free parser context + // + HidParser_FreeContext(Parser, (PUCHAR)DeviceDescription->CollectionDesc[Index].PreparsedData, DeviceDescription->CollectionDesc[Index].PreparsedDataLength); + } + + // + // now free collection description + // + Parser->Free(DeviceDescription->CollectionDesc); + + // + // free report description + // + ExFreePool(DeviceDescription->ReportIDs); +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetCaps( + IN PHID_PARSER Parser, + OUT PHIDP_CAPS Capabilities) +{ + ULONG CollectionNumber; + // + // zero capabilities + // + Parser->Zero(Capabilities, sizeof(HIDP_CAPS)); + + // + // FIXME support multiple top level collections + // + CollectionNumber = 0; + + // + // init capabilities + // + HidParser_GetCollectionUsagePage(Parser, CollectionNumber, &Capabilities->Usage, &Capabilities->UsagePage); + Capabilities->InputReportByteLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_INPUT); + Capabilities->OutputReportByteLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_OUTPUT); + Capabilities->FeatureReportByteLength = HidParser_GetReportLength(Parser, HID_REPORT_TYPE_FEATURE); + + // + // always pre-prend report id + // + Capabilities->InputReportByteLength = (Capabilities->InputReportByteLength > 0 ? Capabilities->InputReportByteLength + 1 : 0); + Capabilities->OutputReportByteLength = (Capabilities->OutputReportByteLength > 0 ? Capabilities->OutputReportByteLength + 1 : 0); + Capabilities->FeatureReportByteLength = (Capabilities->FeatureReportByteLength > 0 ? Capabilities->FeatureReportByteLength + 1 : 0); + + // + // get number of link collection nodes + // + Capabilities->NumberLinkCollectionNodes = HidParser_GetTotalCollectionCount(Parser); + + // + // get data indices + // + Capabilities->NumberInputDataIndices = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_INPUT, TRUE); + Capabilities->NumberOutputDataIndices = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_OUTPUT, TRUE); + Capabilities->NumberFeatureDataIndices = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_FEATURE, TRUE); + + // + // get value caps + // + Capabilities->NumberInputValueCaps = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_INPUT, FALSE); + Capabilities->NumberOutputValueCaps = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_OUTPUT, FALSE); + Capabilities->NumberFeatureValueCaps = HidParser_GetReportItemTypeCountFromReportType(Parser, HID_REPORT_TYPE_FEATURE, FALSE); + + + // + // get button caps + // + Capabilities->NumberInputButtonCaps = HidParser_GetReportItemCountFromReportType(Parser, HID_REPORT_TYPE_INPUT); + Capabilities->NumberOutputButtonCaps = HidParser_GetReportItemCountFromReportType(Parser, HID_REPORT_TYPE_OUTPUT); + Capabilities->NumberFeatureButtonCaps = HidParser_GetReportItemCountFromReportType(Parser, HID_REPORT_TYPE_FEATURE); + + // + // done + // + return HIDP_STATUS_SUCCESS; +} + +HIDAPI +ULONG +NTAPI +HidParser_MaxUsageListLength( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage OPTIONAL) +{ + // + // FIXME test what should be returned when usage page is not defined + // + if (UsagePage == HID_USAGE_PAGE_UNDEFINED) + { + // + // implement me + // + UNIMPLEMENTED + + // + // invalid report + // + return 0; + } + + if (ReportType == HidP_Input) + { + // + // input report + // + return HidParser_GetMaxUsageListLengthWithReportAndPage(Parser, HID_REPORT_TYPE_INPUT, UsagePage); + } + else if (ReportType == HidP_Output) + { + // + // input report + // + return HidParser_GetMaxUsageListLengthWithReportAndPage(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage); + } + else if (ReportType == HidP_Feature) + { + // + // input report + // + return HidParser_GetMaxUsageListLengthWithReportAndPage(Parser, HID_REPORT_TYPE_FEATURE, UsagePage); + } + else + { + // + // invalid report type + // + return 0; + } +} + +#undef HidParser_GetButtonCaps + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetButtonCaps( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN PHIDP_BUTTON_CAPS ButtonCaps, + IN PUSHORT ButtonCapsLength) +{ + return HidParser_GetSpecificButtonCaps(Parser, ReportType, HID_USAGE_PAGE_UNDEFINED, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_PAGE_UNDEFINED, ButtonCaps, (PULONG)ButtonCapsLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetSpecificValueCaps( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PHIDP_VALUE_CAPS ValueCaps, + IN OUT PULONG ValueCapsLength) +{ + HIDPARSER_STATUS ParserStatus; + + // + // FIXME: implement searching in specific collection + // + ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED); + + if (ReportType == HidP_Input) + { + // + // input report + // + ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, HID_REPORT_TYPE_INPUT, UsagePage, Usage, ValueCaps, ValueCapsLength); + } + else if (ReportType == HidP_Output) + { + // + // input report + // + ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, ValueCaps, ValueCapsLength); + } + else if (ReportType == HidP_Feature) + { + // + // input report + // + ParserStatus = HidParser_GetSpecificValueCapsWithReport(Parser, HID_REPORT_TYPE_FEATURE, UsagePage, Usage, ValueCaps, ValueCapsLength); + } + else + { + // + // invalid report type + // + return HIDP_STATUS_INVALID_REPORT_TYPE; + } + + + if (ParserStatus == HIDPARSER_STATUS_SUCCESS) + { + // + // success + // + return HIDP_STATUS_SUCCESS; + } + + // + // translate error + // + return TranslateHidParserStatus(ParserStatus); +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_UsageListDifference( + IN PUSAGE PreviousUsageList, + IN PUSAGE CurrentUsageList, + OUT PUSAGE BreakUsageList, + OUT PUSAGE MakeUsageList, + IN ULONG UsageListLength) +{ + ULONG Index, SubIndex, bFound, BreakUsageIndex = 0, MakeUsageIndex = 0; + USAGE CurrentUsage, Usage; + + if (UsageListLength) + { + Index = 0; + do + { + /* get current usage */ + CurrentUsage = PreviousUsageList[Index]; + + /* is the end of list reached? */ + if (!CurrentUsage) + break; + + /* start searching in current usage list */ + SubIndex = 0; + bFound = FALSE; + do + { + /* get usage of current list */ + Usage = CurrentUsageList[SubIndex]; + + /* end of list reached? */ + if (!Usage) + break; + + /* check if it matches the current one */ + if (CurrentUsage == Usage) + { + /* it does */ + bFound = TRUE; + break; + } + + /* move to next usage */ + SubIndex++; + }while(SubIndex < UsageListLength); + + /* was the usage found ?*/ + if (!bFound) + { + /* store it in the break usage list */ + BreakUsageList[BreakUsageIndex] = CurrentUsage; + BreakUsageIndex++; + } + + /* move to next usage */ + Index++; + + }while(Index < UsageListLength); + + /* now process the new items */ + Index = 0; + do + { + /* get current usage */ + CurrentUsage = CurrentUsageList[Index]; + + /* is the end of list reached? */ + if (!CurrentUsage) + break; + + /* start searching in current usage list */ + SubIndex = 0; + bFound = FALSE; + do + { + /* get usage of previous list */ + Usage = PreviousUsageList[SubIndex]; + + /* end of list reached? */ + if (!Usage) + break; + + /* check if it matches the current one */ + if (CurrentUsage == Usage) + { + /* it does */ + bFound = TRUE; + break; + } + + /* move to next usage */ + SubIndex++; + }while(SubIndex < UsageListLength); + + /* was the usage found ?*/ + if (!bFound) + { + /* store it in the make usage list */ + MakeUsageList[MakeUsageIndex] = CurrentUsage; + MakeUsageIndex++; + } + + /* move to next usage */ + Index++; + + }while(Index < UsageListLength); + } + + /* does the break list contain empty entries */ + if (BreakUsageIndex < UsageListLength) + { + /* zeroize entries */ + RtlZeroMemory(&BreakUsageList[BreakUsageIndex], sizeof(USAGE) * (UsageListLength - BreakUsageIndex)); + } + + /* does the make usage list contain empty entries */ + if (MakeUsageIndex < UsageListLength) + { + /* zeroize entries */ + RtlZeroMemory(&MakeUsageList[MakeUsageIndex], sizeof(USAGE) * (UsageListLength - MakeUsageIndex)); + } + + /* done */ + return HIDP_STATUS_SUCCESS; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsages( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + OUT USAGE *UsageList, + IN OUT PULONG UsageLength, + IN PCHAR Report, + IN ULONG ReportLength) +{ + HIDPARSER_STATUS ParserStatus; + + // + // FIXME: implement searching in specific collection + // + ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED); + + if (ReportType == HidP_Input) + { + // + // input report + // + ParserStatus = HidParser_GetUsagesWithReport(Parser, HID_REPORT_TYPE_INPUT, UsagePage, UsageList, UsageLength, Report, ReportLength); + } + else if (ReportType == HidP_Output) + { + // + // input report + // + ParserStatus = HidParser_GetUsagesWithReport(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage, UsageList, UsageLength, Report, ReportLength); + } + else if (ReportType == HidP_Feature) + { + // + // input report + // + ParserStatus = HidParser_GetUsagesWithReport(Parser, HID_REPORT_TYPE_FEATURE, UsagePage, UsageList, UsageLength, Report, ReportLength); + } + else + { + // + // invalid report type + // + return HIDP_STATUS_INVALID_REPORT_TYPE; + } + + if (ParserStatus == HIDPARSER_STATUS_SUCCESS) + { + // + // success + // + return HIDP_STATUS_SUCCESS; + } + + // + // translate error + // + return TranslateHidParserStatus(ParserStatus); +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetScaledUsageValue( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + OUT PLONG UsageValue, + IN PCHAR Report, + IN ULONG ReportLength) +{ + HIDPARSER_STATUS ParserStatus; + + // + // FIXME: implement searching in specific collection + // + ASSERT(LinkCollection == HIDP_LINK_COLLECTION_UNSPECIFIED); + + if (ReportType == HidP_Input) + { + // + // input report + // + ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, HID_REPORT_TYPE_INPUT, UsagePage, Usage, UsageValue, Report, ReportLength); + } + else if (ReportType == HidP_Output) + { + // + // input report + // + ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, HID_REPORT_TYPE_OUTPUT, UsagePage, Usage, UsageValue, Report, ReportLength); + } + else if (ReportType == HidP_Feature) + { + // + // input report + // + ParserStatus = HidParser_GetScaledUsageValueWithReport(Parser, HID_REPORT_TYPE_FEATURE, UsagePage, Usage, UsageValue, Report, ReportLength); + } + else + { + // + // invalid report type + // + return HIDP_STATUS_INVALID_REPORT_TYPE; + } + + if (ParserStatus == HIDPARSER_STATUS_SUCCESS) + { + // + // success + // + return HIDP_STATUS_SUCCESS; + } + + // + // translate error + // + return TranslateHidParserStatus(ParserStatus); +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_TranslateUsageAndPagesToI8042ScanCodes( + IN PHID_PARSER Parser, + IN PUSAGE_AND_PAGE ChangedUsageList, + IN ULONG UsageListLength, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext) +{ + ULONG Index; + HIDPARSER_STATUS Status = HIDPARSER_STATUS_SUCCESS; + + for(Index = 0; Index < UsageListLength; Index++) + { + // + // check current usage + // + if (ChangedUsageList[Index].UsagePage == HID_USAGE_PAGE_KEYBOARD) + { + // + // process usage + // + Status = HidParser_TranslateUsage(Parser, ChangedUsageList[Index].Usage, KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext); + } + else if (ChangedUsageList[Index].UsagePage == HID_USAGE_PAGE_CONSUMER) + { + // + // FIXME: implement me + // + UNIMPLEMENTED + Status = HIDPARSER_STATUS_NOT_IMPLEMENTED; + } + else + { + // + // invalid page + // + DPRINT1("[HIDPARSE] Error unexpected usage page %x\n", ChangedUsageList[Index].UsagePage); + return HIDP_STATUS_I8042_TRANS_UNKNOWN; + } + + // + // check status + // + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed + // + return TranslateHidParserStatus(Status); + } + } + + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed + // + return TranslateHidParserStatus(Status); + } + + // + // done + // + return HIDP_STATUS_SUCCESS; +} + + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsagesEx( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USHORT LinkCollection, + OUT PUSAGE_AND_PAGE ButtonList, + IN OUT ULONG *UsageLength, + IN PCHAR Report, + IN ULONG ReportLength) +{ + return HidParser_GetUsages(Parser, ReportType, HID_USAGE_PAGE_UNDEFINED, LinkCollection, (PUSAGE)ButtonList, UsageLength, Report, ReportLength); +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_UsageAndPageListDifference( + IN PUSAGE_AND_PAGE PreviousUsageList, + IN PUSAGE_AND_PAGE CurrentUsageList, + OUT PUSAGE_AND_PAGE BreakUsageList, + OUT PUSAGE_AND_PAGE MakeUsageList, + IN ULONG UsageListLength) +{ + ULONG Index, SubIndex, BreakUsageListIndex = 0, MakeUsageListIndex = 0, bFound; + PUSAGE_AND_PAGE CurrentUsage, Usage; + + if (UsageListLength) + { + /* process removed usages */ + Index = 0; + do + { + /* get usage from current index */ + CurrentUsage = &PreviousUsageList[Index]; + + /* end of list reached? */ + if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0) + break; + + /* search in current list */ + SubIndex = 0; + bFound = FALSE; + do + { + /* get usage */ + Usage = &CurrentUsageList[SubIndex]; + + /* end of list reached? */ + if (Usage->Usage == 0 && Usage->UsagePage == 0) + break; + + /* does it match */ + if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage) + { + /* found match */ + bFound = TRUE; + } + + /* move to next index */ + SubIndex++; + + }while(SubIndex < UsageListLength); + + if (!bFound) + { + /* store it in break usage list */ + BreakUsageList[BreakUsageListIndex].Usage = CurrentUsage->Usage; + BreakUsageList[BreakUsageListIndex].UsagePage = CurrentUsage->UsagePage; + BreakUsageListIndex++; + } + + /* move to next index */ + Index++; + + }while(Index < UsageListLength); + + /* process new usages */ + Index = 0; + do + { + /* get usage from current index */ + CurrentUsage = &CurrentUsageList[Index]; + + /* end of list reached? */ + if (CurrentUsage->Usage == 0 && CurrentUsage->UsagePage == 0) + break; + + /* search in current list */ + SubIndex = 0; + bFound = FALSE; + do + { + /* get usage */ + Usage = &PreviousUsageList[SubIndex]; + + /* end of list reached? */ + if (Usage->Usage == 0 && Usage->UsagePage == 0) + break; + + /* does it match */ + if (Usage->Usage == CurrentUsage->Usage && Usage->UsagePage == CurrentUsage->UsagePage) + { + /* found match */ + bFound = TRUE; + } + + /* move to next index */ + SubIndex++; + + }while(SubIndex < UsageListLength); + + if (!bFound) + { + /* store it in break usage list */ + MakeUsageList[MakeUsageListIndex].Usage = CurrentUsage->Usage; + MakeUsageList[MakeUsageListIndex].UsagePage = CurrentUsage->UsagePage; + MakeUsageListIndex++; + } + + /* move to next index */ + Index++; + }while(Index < UsageListLength); + } + + /* are there remaining free list entries */ + if (BreakUsageListIndex < UsageListLength) + { + /* zero them */ + RtlZeroMemory(&BreakUsageList[BreakUsageListIndex], (UsageListLength - BreakUsageListIndex) * sizeof(USAGE_AND_PAGE)); + } + + /* are there remaining free list entries */ + if (MakeUsageListIndex < UsageListLength) + { + /* zero them */ + RtlZeroMemory(&MakeUsageList[MakeUsageListIndex], (UsageListLength - MakeUsageListIndex) * sizeof(USAGE_AND_PAGE)); + } + + /* done */ + return HIDP_STATUS_SUCCESS; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetSpecificButtonCaps( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PHIDP_BUTTON_CAPS ButtonCaps, + IN OUT PULONG ButtonCapsLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetData( + IN HIDP_REPORT_TYPE ReportType, + OUT PHIDP_DATA DataList, + IN OUT PULONG DataLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetExtendedAttributes( + IN HIDP_REPORT_TYPE ReportType, + IN USHORT DataIndex, + IN PHIDP_PREPARSED_DATA PreparsedData, + OUT PHIDP_EXTENDED_ATTRIBUTES Attributes, + IN OUT PULONG LengthAttributes) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetLinkCollectionNodes( + OUT PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes, + IN OUT PULONG LinkCollectionNodesLength, + IN PHIDP_PREPARSED_DATA PreparsedData) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PULONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS +NTAPI +HidParser_SysPowerEvent ( + IN PCHAR HidPacket, + IN USHORT HidPacketLength, + IN PHIDP_PREPARSED_DATA Ppd, + OUT PULONG OutputBuffer) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HidParser_SysPowerCaps ( + IN PHIDP_PREPARSED_DATA Ppd, + OUT PULONG OutputBuffer) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsageValueArray( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + OUT PCHAR UsageValue, + IN USHORT UsageValueByteLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_UnsetUsages( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN PUSAGE UsageList, + IN OUT PULONG UsageLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_TranslateUsagesToI8042ScanCodes( + IN PUSAGE ChangedUsageList, + IN ULONG UsageListLength, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetUsages( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN PUSAGE UsageList, + IN OUT PULONG UsageLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetUsageValueArray( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + IN PCHAR UsageValue, + IN USHORT UsageValueByteLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + IN ULONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetScaledUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + IN LONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetData( + IN HIDP_REPORT_TYPE ReportType, + IN PHIDP_DATA DataList, + IN OUT PULONG DataLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +ULONG +NTAPI +HidParser_MaxDataListLength( + IN HIDP_REPORT_TYPE ReportType, + IN PHIDP_PREPARSED_DATA PreparsedData) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +HIDAPI +NTSTATUS +NTAPI +HidParser_InitializeReportForID( + IN HIDP_REPORT_TYPE ReportType, + IN UCHAR ReportID, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +#undef HidParser_GetValueCaps + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetValueCaps( + HIDP_REPORT_TYPE ReportType, + PHIDP_VALUE_CAPS ValueCaps, + PULONG ValueCapsLength, + PHIDP_PREPARSED_DATA PreparsedData) +{ + UNIMPLEMENTED + ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} diff --git a/lib/drivers/hidparser/hidparser.h b/lib/drivers/hidparser/hidparser.h new file mode 100644 index 00000000000..104ceeeb3b6 --- /dev/null +++ b/lib/drivers/hidparser/hidparser.h @@ -0,0 +1,428 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface + * LICENSE: GPL - See COPYING in the top level directory + * FILE: lib/drivers/hidparser/hidparser.c + * PURPOSE: HID Parser + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#pragma once + +#define _HIDPI_ +#define _HIDPI_NO_FUNCTION_MACROS_ +#include +#include +#include +#include + +// +// function prototypes +// +typedef PVOID (NTAPI *PHIDPARSER_ALLOC_FUNCTION)(ULONG Size); +typedef VOID (NTAPI *PHIDPARSER_FREE_FUNCTION)(PVOID Item); +typedef VOID (NTAPI *PHIDPARSER_ZERO_FUNCTION)(PVOID Item, ULONG Size); +typedef VOID (NTAPI *PHIDPARSER_COPY_FUNCTION)(PVOID Target, PVOID Source, ULONG Size); +typedef VOID (NTAPI *PHIDPARSER_DEBUG_FUNCTION)(LPCSTR Src, ...); + +// +// status code +// +typedef long HIDPARSER_STATUS; + +// +// result codes +// +typedef enum +{ + HIDPARSER_STATUS_SUCCESS = 0, + HIDPARSER_STATUS_INSUFFICIENT_RESOURCES = -1, + HIDPARSER_STATUS_NOT_IMPLEMENTED = -2, + HIDPARSER_STATUS_REPORT_NOT_FOUND = -3, + HIDPARSER_STATUS_COLLECTION_NOT_FOUND = -4, + HIDPARSER_STATUS_INVALID_REPORT_LENGTH = -5, + HIDPARSER_STATUS_INVALID_REPORT_TYPE = -6, + HIDPARSER_STATUS_BUFFER_TOO_SMALL = -7, + HIDPARSER_STATUS_USAGE_NOT_FOUND = -8, + HIDPARSER_STATUS_I8042_TRANS_UNKNOWN = -9 +}HIDPARSER_STATUS_CODES; + +typedef struct +{ + // + // size of struct + // + unsigned long Size; + + // + // allocation function + // + PHIDPARSER_ALLOC_FUNCTION Alloc; + + // + // free function + // + PFREE_FUNCTION Free; + + // + // zero function + // + PHIDPARSER_ZERO_FUNCTION Zero; + + // + // copy function + // + PHIDPARSER_COPY_FUNCTION Copy; + + // + // debug function + // + PHIDPARSER_DEBUG_FUNCTION Debug; + + // + // parser context + // + void * ParserContext; + +}HID_PARSER, *PHID_PARSER; + +HIDPARSER_STATUS +HidParser_AllocateParser( + IN PHIDPARSER_ALLOC_FUNCTION AllocFunction, + IN PHIDPARSER_FREE_FUNCTION FreeFunction, + IN PHIDPARSER_ZERO_FUNCTION ZeroFunction, + IN PHIDPARSER_COPY_FUNCTION CopyFunction, + IN PHIDPARSER_DEBUG_FUNCTION DebugFunction, + OUT PHID_PARSER *OutParser); + +VOID +HidParser_InitParser( + IN PHIDPARSER_ALLOC_FUNCTION AllocFunction, + IN PHIDPARSER_FREE_FUNCTION FreeFunction, + IN PHIDPARSER_ZERO_FUNCTION ZeroFunction, + IN PHIDPARSER_COPY_FUNCTION CopyFunction, + IN PHIDPARSER_DEBUG_FUNCTION DebugFunction, + IN PVOID ParserContext, + OUT PHID_PARSER Parser); + +NTSTATUS +NTAPI +HidParser_GetCollectionDescription( + IN PHID_PARSER Parser, + IN PHIDP_REPORT_DESCRIPTOR ReportDesc, + IN ULONG DescLength, + IN POOL_TYPE PoolType, + OUT PHIDP_DEVICE_DESC DeviceDescription); + +VOID +NTAPI +HidParser_FreeCollectionDescription( + IN PHID_PARSER Parser, + IN PHIDP_DEVICE_DESC DeviceDescription); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetCaps( + IN PHID_PARSER Parser, + OUT PHIDP_CAPS Capabilities); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetSpecificValueCaps( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PHIDP_VALUE_CAPS ValueCaps, + IN OUT PULONG ValueCapsLength); + + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetButtonCaps( + IN PHID_PARSER Parser, + HIDP_REPORT_TYPE ReportType, + PHIDP_BUTTON_CAPS ButtonCaps, + PUSHORT ButtonCapsLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetSpecificButtonCaps( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PHIDP_BUTTON_CAPS ButtonCaps, + IN OUT PULONG ButtonCapsLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetScaledUsageValue( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + OUT PLONG UsageValue, + IN PCHAR Report, + IN ULONG ReportLength); + + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetData( + IN HIDP_REPORT_TYPE ReportType, + OUT PHIDP_DATA DataList, + IN OUT PULONG DataLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetExtendedAttributes( + IN HIDP_REPORT_TYPE ReportType, + IN USHORT DataIndex, + IN PHIDP_PREPARSED_DATA PreparsedData, + OUT PHIDP_EXTENDED_ATTRIBUTES Attributes, + IN OUT PULONG LengthAttributes); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetLinkCollectionNodes( + OUT PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes, + IN OUT PULONG LinkCollectionNodesLength, + IN PHIDP_PREPARSED_DATA PreparsedData); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + OUT PULONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_UsageListDifference( + IN PUSAGE PreviousUsageList, + IN PUSAGE CurrentUsageList, + OUT PUSAGE BreakUsageList, + OUT PUSAGE MakeUsageList, + IN ULONG UsageListLength); + + +HIDAPI +ULONG +NTAPI +HidParser_MaxUsageListLength( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage OPTIONAL); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsages( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + OUT USAGE *UsageList, + IN OUT ULONG *UsageLength, + IN PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsagesEx( + IN PHID_PARSER Parser, + IN HIDP_REPORT_TYPE ReportType, + IN USHORT LinkCollection, + OUT PUSAGE_AND_PAGE ButtonList, + IN OUT ULONG *UsageLength, + IN PCHAR Report, + IN ULONG ReportLength); + + +NTSTATUS +NTAPI +HidParser_SysPowerEvent ( + IN PCHAR HidPacket, + IN USHORT HidPacketLength, + IN PHIDP_PREPARSED_DATA Ppd, + OUT PULONG OutputBuffer); + +NTSTATUS +NTAPI +HidParser_SysPowerCaps ( + IN PHIDP_PREPARSED_DATA Ppd, + OUT PULONG OutputBuffer); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetUsageValueArray( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + OUT PCHAR UsageValue, + IN USHORT UsageValueByteLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN PCHAR Report, + IN ULONG ReportLength); + + +HIDAPI +NTSTATUS +NTAPI +HidParser_UsageAndPageListDifference( + IN PUSAGE_AND_PAGE PreviousUsageList, + IN PUSAGE_AND_PAGE CurrentUsageList, + OUT PUSAGE_AND_PAGE BreakUsageList, + OUT PUSAGE_AND_PAGE MakeUsageList, + IN ULONG UsageListLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_UnsetUsages( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN PUSAGE UsageList, + IN OUT PULONG UsageLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_TranslateUsagesToI8042ScanCodes( + IN PUSAGE ChangedUsageList, + IN ULONG UsageListLength, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext); + +HIDAPI +NTSTATUS +NTAPI +HidParser_TranslateUsageAndPagesToI8042ScanCodes( + IN PUSAGE_AND_PAGE ChangedUsageList, + IN ULONG UsageListLength, + IN HIDP_KEYBOARD_DIRECTION KeyAction, + IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, + IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, + IN PVOID InsertCodesContext); + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetUsages( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN PUSAGE UsageList, + IN OUT PULONG UsageLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetUsageValueArray( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + IN PCHAR UsageValue, + IN USHORT UsageValueByteLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection, + IN USAGE Usage, + IN ULONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetScaledUsageValue( + IN HIDP_REPORT_TYPE ReportType, + IN USAGE UsagePage, + IN USHORT LinkCollection OPTIONAL, + IN USAGE Usage, + IN LONG UsageValue, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_SetData( + IN HIDP_REPORT_TYPE ReportType, + IN PHIDP_DATA DataList, + IN OUT PULONG DataLength, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +ULONG +NTAPI +HidParser_MaxDataListLength( + IN HIDP_REPORT_TYPE ReportType, + IN PHIDP_PREPARSED_DATA PreparsedData); + +HIDAPI +NTSTATUS +NTAPI +HidParser_InitializeReportForID( + IN HIDP_REPORT_TYPE ReportType, + IN UCHAR ReportID, + IN PHIDP_PREPARSED_DATA PreparsedData, + IN OUT PCHAR Report, + IN ULONG ReportLength); + +HIDAPI +NTSTATUS +NTAPI +HidParser_GetValueCaps( + HIDP_REPORT_TYPE ReportType, + PHIDP_VALUE_CAPS ValueCaps, + PULONG ValueCapsLength, + PHIDP_PREPARSED_DATA PreparsedData); diff --git a/lib/drivers/hidparser/parser.c b/lib/drivers/hidparser/parser.c new file mode 100644 index 00000000000..d86b6df9bd0 --- /dev/null +++ b/lib/drivers/hidparser/parser.c @@ -0,0 +1,1347 @@ +/* + * PROJECT: ReactOS HID Parser Library + * LICENSE: GPL - See COPYING in the top level directory + * FILE: lib/drivers/hidparser/parser.c + * PURPOSE: HID Parser + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + + +#include "parser.h" + +static UCHAR ItemSize[4] = { 0, 1, 2, 4 }; + +VOID +HidParser_DeleteReport( + IN PHID_PARSER Parser, + IN PHID_REPORT Report) +{ + // + // not implemented + // +} + +VOID +HidParser_FreeCollection( + IN PHID_PARSER Parser, + IN PHID_COLLECTION Collection) +{ + // + // not implemented + // +} + +HIDPARSER_STATUS +HidParser_AllocateCollection( + IN PHID_PARSER Parser, + IN PHID_COLLECTION ParentCollection, + IN UCHAR Type, + IN PLOCAL_ITEM_STATE LocalItemState, + OUT PHID_COLLECTION * OutCollection) +{ + PHID_COLLECTION Collection; + USAGE_VALUE UsageValue; + + // + // first allocate the collection + // + Collection = (PHID_COLLECTION)Parser->Alloc(sizeof(HID_COLLECTION)); + if (!Collection) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // init collection + // + Collection->Root = ParentCollection; + Collection->Type = Type; + Collection->StringID = LocalItemState->StringIndex; + Collection->PhysicalID = LocalItemState->DesignatorIndex; + + // + // set Usage + // + ASSERT(LocalItemState); + ASSERT(LocalItemState->UsageStack); + + if (LocalItemState->UsageStackUsed > 0) + { + // + // usage value from first local stack item + // + UsageValue.u.Extended = LocalItemState->UsageStack[0].u.Extended; + } + else if (LocalItemState->UsageMinimumSet) + { + // + // use value from minimum + // + UsageValue.u.Extended = LocalItemState->UsageMinimum.u.Extended; + } + else if (LocalItemState->UsageMaximumSet) + { + // + // use value from maximum + // + UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended; + } + else if (Type == COLLECTION_LOGICAL) + { + // + // root collection + // + UsageValue.u.Extended = 0; + } + else + { + // + // no usage set + // + Parser->Debug("HIDPARSE] No usage set\n"); + UsageValue.u.Extended = 0; + } + + // + // store usage + // + Collection->Usage = UsageValue.u.Extended; + + // + // store result + // + *OutCollection = Collection; + + // + // done + // + return HIDPARSER_STATUS_SUCCESS; +} + + +VOID +HidParser_ResetParser( + OUT PHID_PARSER Parser) +{ + ULONG Index; + PHID_PARSER_CONTEXT ParserContext; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + + + // + // delete all reports + // + for(Index = 0; Index < ParserContext->ReportCount; Index++) + { + // + // delete report + // + HidParser_DeleteReport(Parser, ParserContext->Reports[Index]); + } + + if (ParserContext->ReportCount && ParserContext->Reports) + { + // + // free report array + // + Parser->Free(ParserContext->Reports); + } + + if (ParserContext->RootCollection) + { + // + // delete root collection + // + HidParser_FreeCollection(Parser, ParserContext->RootCollection); + } + + // + // reinit parser + // + ParserContext->ReportCount = 0; + ParserContext->Reports = NULL; + ParserContext->RootCollection = NULL; + ParserContext->UseReportIDs = FALSE; + + // + // zero item states + // + Parser->Zero(&ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE)); + Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE)); +} + +HIDPARSER_STATUS +HidParser_AddCollection( + IN PHID_PARSER Parser, + IN PHID_COLLECTION CurrentCollection, + IN PHID_COLLECTION NewCollection) +{ + PHID_COLLECTION * NewAllocCollection; + ULONG CollectionCount; + + // + // increment collection array + // + CollectionCount = CurrentCollection->NodeCount + 1; + + // + // allocate new collection + // + NewAllocCollection = (PHID_COLLECTION*)Parser->Alloc(sizeof(PHID_COLLECTION) * CollectionCount); + if (!NewAllocCollection) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + if (CurrentCollection->NodeCount) + { + // + // copy old array + // + Parser->Copy(NewAllocCollection, CurrentCollection->Nodes, CurrentCollection->NodeCount * sizeof(PHID_COLLECTION)); + + // + // delete old array + // + Parser->Free(CurrentCollection->Nodes); + } + + // + // insert new item + // + NewAllocCollection[CurrentCollection->NodeCount] = (struct __HID_COLLECTION__*)NewCollection; + + + // + // store new array + // + CurrentCollection->Nodes = NewAllocCollection; + CurrentCollection->NodeCount++; + + // + // done + // + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_FindReport( + IN PHID_PARSER Parser, + IN UCHAR ReportType, + IN UCHAR ReportID, + OUT PHID_REPORT *OutReport) +{ + PHID_PARSER_CONTEXT ParserContext; + ULONG Index; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + ASSERT(ParserContext); + + for(Index = 0; Index < ParserContext->ReportCount; Index++) + { + if (ParserContext->Reports[Index]->Type == ReportType && ParserContext->Reports[Index]->ReportID == ReportID) + { + // + // found report + // + *OutReport = ParserContext->Reports[Index]; + return HIDPARSER_STATUS_SUCCESS; + } + } + + // + // no such report found + // + *OutReport = NULL; + return HIDPARSER_STATUS_REPORT_NOT_FOUND; +} + +HIDPARSER_STATUS +HidParser_AllocateReport( + IN PHID_PARSER Parser, + IN UCHAR ReportType, + IN UCHAR ReportID, + OUT PHID_REPORT *OutReport) +{ + PHID_REPORT Report; + + // + // allocate report + // + Report = (PHID_REPORT)Parser->Alloc(sizeof(HID_REPORT)); + if (!Report) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // init report + // + Report->ReportID = ReportID; + Report->Type = ReportType; + + // + // done + // + *OutReport = Report; + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_AddReport( + IN PHID_PARSER Parser, + IN PHID_REPORT NewReport) +{ + PHID_REPORT * NewReportArray; + PHID_PARSER_CONTEXT ParserContext; + + // + // get parser context + // + ParserContext = (PHID_PARSER_CONTEXT)Parser->ParserContext; + ASSERT(ParserContext); + + // + // allocate new report array + // + NewReportArray = (PHID_REPORT*)Parser->Alloc(sizeof(PHID_REPORT) * (ParserContext->ReportCount + 1)); + if (!NewReportArray) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + if (ParserContext->ReportCount) + { + // + // copy old array contents + // + Parser->Copy(NewReportArray, ParserContext->Reports, sizeof(PHID_REPORT) * ParserContext->ReportCount); + + // + // free old array + // + Parser->Free(ParserContext->Reports); + } + + // + // store result + // + NewReportArray[ParserContext->ReportCount] = NewReport; + ParserContext->Reports = NewReportArray; + ParserContext->ReportCount++; + + // + // completed successfully + // + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_GetReport( + IN PHID_PARSER Parser, + IN UCHAR ReportType, + IN UCHAR ReportID, + IN UCHAR CreateIfNotExists, + OUT PHID_REPORT *OutReport) +{ + HIDPARSER_STATUS Status; + + // + // try finding existing report + // + Status = HidParser_FindReport(Parser, ReportType, ReportID, OutReport); + if (Status == HIDPARSER_STATUS_SUCCESS || CreateIfNotExists == FALSE) + { + // + // founed report + // + return Status; + } + + // + // allocate new report + // + Status = HidParser_AllocateReport(Parser, ReportType, ReportID, OutReport); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to allocate report + // + return Status; + } + + // + // add report + // + Status = HidParser_AddReport(Parser, *OutReport); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to allocate report + // + Parser->Free(*OutReport); + } + + // + // done + // + return Status; +} + + +HIDPARSER_STATUS +HidParser_ReserveCollectionItems( + IN PHID_PARSER Parser, + IN PHID_COLLECTION Collection, + IN ULONG ReportCount) +{ + PHID_REPORT_ITEM * NewReportArray; + + if (Collection->ItemCount + ReportCount <= Collection->ItemCountAllocated) + { + // + // enough space for the next items + // + return HIDPARSER_STATUS_SUCCESS; + } + + // + // allocate report array + // + NewReportArray = (PHID_REPORT_ITEM*)Parser->Alloc(sizeof(PHID_REPORT) * (Collection->ItemCountAllocated + ReportCount)); + if (!NewReportArray) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // are there any items + // + if (Collection->ItemCount) + { + // + // copy old items + // + Parser->Copy(NewReportArray, Collection->Items, sizeof(PHID_REPORT_ITEM) * Collection->ItemCount); + + // + // free old item + // + Parser->Free(Collection->Items); + } + + // + // replace array + // + Collection->Items = NewReportArray; + Collection->ItemCountAllocated += ReportCount; + + // + // completed sucessfully + // + return HIDPARSER_STATUS_SUCCESS; +} + + +HIDPARSER_STATUS +HidParser_ReserveReportItems( + IN PHID_PARSER Parser, + IN PHID_REPORT Report, + IN ULONG ReportCount) +{ + PHID_REPORT_ITEM * NewReportArray; + + if (Report->ItemCount + ReportCount <= Report->ItemAllocated) + { + // + // enough space for the next items + // + return HIDPARSER_STATUS_SUCCESS; + } + + // + // allocate report array + // + NewReportArray = (PHID_REPORT_ITEM*)Parser->Alloc(sizeof(PHID_REPORT_ITEM) * (Report->ItemAllocated + ReportCount)); + if (!NewReportArray) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // are there any items + // + if (Report->ItemCount) + { + // + // copy old items + // + Parser->Copy(NewReportArray, Report->Items, sizeof(PHID_REPORT_ITEM) * Report->ItemCount); + + // + // free old item + // + Parser->Free(Report->Items); + } + + // + // replace array + // + Report->Items = NewReportArray; + Report->ItemAllocated += ReportCount; + + // + // completed sucessfully + // + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_AllocateReportItem( + IN PHID_PARSER Parser, + OUT PHID_REPORT_ITEM * OutReportItem) +{ + PHID_REPORT_ITEM ReportItem; + + // + // allocate report item + // + ReportItem = (PHID_REPORT_ITEM)Parser->Alloc(sizeof(HID_REPORT_ITEM)); + if (!ReportItem) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // store result + // + *OutReportItem = ReportItem; + return HIDPARSER_STATUS_SUCCESS; +} + +VOID +HidParser_AddReportItemToReport( + IN OUT PHID_REPORT Report, + IN PHID_REPORT_ITEM ReportItem) +{ + // + // there should be space in item array + // + ASSERT(Report->ItemCount + 1 <= Report->ItemAllocated); + + // + // store item + // + Report->Items[Report->ItemCount] = ReportItem; + Report->ItemCount++; +} + +VOID +HidParser_AddReportItemToCollection( + IN OUT PHID_COLLECTION Collection, + IN PHID_REPORT_ITEM ReportItem) +{ + // + // there should be space in item array + // + ASSERT(Collection->ItemCount + 1 <= Collection->ItemCountAllocated); + + // + // store item + // + Collection->Items[Collection->ItemCount] = ReportItem; + Collection->ItemCount++; +} + +VOID +HidParser_SignRange( + IN ULONG Minimum, + IN ULONG Maximum, + OUT PULONG NewMinimum, + OUT PULONG NewMaximum) +{ + ULONG Mask = 0x80000000; + ULONG Index; + + for (Index = 0; Index < 4; Index++) + { + if (Minimum & Mask) + { + Minimum |= Mask; + if (Maximum & Mask) + Maximum |= Mask; + return; + } + + Mask >>= 8; + Mask |= 0xff000000; + } + + *NewMinimum = Minimum; + *NewMaximum = Maximum; +} + +HIDPARSER_STATUS +HidParser_InitReportItem( + IN PHID_REPORT Report, + IN PHID_REPORT_ITEM ReportItem, + IN PGLOBAL_ITEM_STATE GlobalItemState, + IN PLOCAL_ITEM_STATE LocalItemState, + IN PMAIN_ITEM_DATA ItemData, + IN ULONG ReportItemIndex) +{ + ULONG LogicalMinimum; + ULONG LogicalMaximum; + ULONG PhysicalMinimum; + ULONG PhysicalMaximum; + ULONG UsageMinimum; + ULONG UsageMaximum; + USAGE_VALUE UsageValue; + + // + // get logical bounds + // + LogicalMinimum = GlobalItemState->LogicalMinimum; + LogicalMaximum = GlobalItemState->LogicialMaximum; + if (LogicalMinimum > LogicalMaximum) + { + // + // make them signed + // + HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum); + } + //ASSERT(LogicalMinimum <= LogicalMaximum); + + // + // get physical bounds + // + PhysicalMinimum = GlobalItemState->PhysicalMinimum; + PhysicalMaximum = GlobalItemState->PhysicalMaximum; + if (PhysicalMinimum > PhysicalMaximum) + { + // + // make them signed + // + HidParser_SignRange(PhysicalMinimum, PhysicalMaximum, &PhysicalMinimum, &PhysicalMaximum); + } + //ASSERT(PhysicalMinimum <= PhysicalMaximum); + + // + // get usage bounds + // + UsageMinimum = 0; + UsageMaximum = 0; + if (ItemData->ArrayVariable == FALSE) + { + // + // get usage bounds + // + UsageMinimum = LocalItemState->UsageMinimum.u.Extended; + UsageMaximum = LocalItemState->UsageMaximum.u.Extended; + } + else + { + // + // get usage value from stack + // + if (ReportItemIndex < LocalItemState->UsageStackUsed) + { + // + // use stack item + // + UsageValue = LocalItemState->UsageStack[ReportItemIndex]; + } + else + { + // + // get usage minimum from local state + // + UsageValue = LocalItemState->UsageMinimum; + ASSERT(LocalItemState->UsageMinimumSet); + ASSERT(LocalItemState->UsageMaximumSet); + + // + // append item index + // + UsageValue.u.Extended += ReportItemIndex; + + if (UsageValue.u.Extended > LocalItemState->UsageMaximum.u.Extended) + { + // + // maximum reached + // + UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended; + } + } + + // + // usage usage bounds + // + UsageMinimum = UsageMaximum = UsageValue.u.Extended; + } + + // + // now store all values + // + ReportItem->ByteOffset = (Report->ReportSize / 8); + ReportItem->Shift = (Report->ReportSize % 8); + ReportItem->Mask = ~(0xFFFFFFFF << GlobalItemState->ReportSize); + ReportItem->BitCount = GlobalItemState->ReportSize; + ReportItem->HasData = (ItemData->DataConstant == FALSE); + ReportItem->Array = (ItemData->ArrayVariable == 0); + ReportItem->Relative = (ItemData->Relative == TRUE); + ReportItem->Minimum = LogicalMinimum; + ReportItem->Maximum = LogicalMaximum; + ReportItem->UsageMinimum = UsageMinimum; + ReportItem->UsageMaximum = UsageMaximum; + + // + // increment report size + // + Report->ReportSize += GlobalItemState->ReportSize; + + // + // completed successfully + // + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_AddMainItem( + IN PHID_PARSER Parser, + IN PHID_REPORT Report, + IN PGLOBAL_ITEM_STATE GlobalItemState, + IN PLOCAL_ITEM_STATE LocalItemState, + IN PMAIN_ITEM_DATA ItemData, + IN PHID_COLLECTION Collection) +{ + PHID_REPORT_ITEM ReportItem; + HIDPARSER_STATUS Status; + ULONG Index; + + // + // first grow report item array + // + Status = HidParser_ReserveReportItems(Parser, Report, GlobalItemState->ReportCount); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to allocate memory + // + return Status; + } + + // + // grow collection item array + // + Status = HidParser_ReserveCollectionItems(Parser, Collection, GlobalItemState->ReportCount); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to allocate memory + // + return Status; + } + + + + for(Index = 0; Index < GlobalItemState->ReportCount; Index++) + { + // + // create report item + // + Status = HidParser_AllocateReportItem(Parser, &ReportItem); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to allocate memory + // + return Status; + } + + Status = HidParser_InitReportItem(Report, ReportItem, GlobalItemState, LocalItemState, ItemData, Index); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // failed to init report item + // + return Status; + } + + // + // add report item + // + HidParser_AddReportItemToReport(Report, ReportItem); + HidParser_AddReportItemToCollection(Collection, ReportItem); + } + + // + // done + // + return HIDPARSER_STATUS_SUCCESS; +} + +HIDPARSER_STATUS +HidParser_ParseReportDescriptor( + IN PHID_PARSER Parser, + IN PUCHAR ReportDescriptor, + IN ULONG ReportLength) +{ + PGLOBAL_ITEM_STATE LinkedGlobalItemState, NextLinkedGlobalItemState; + ULONG Index; + PUSAGE_VALUE NewUsageStack, UsageValue; + HIDPARSER_STATUS Status; + PHID_COLLECTION CurrentCollection, NewCollection; + PUCHAR CurrentOffset, ReportEnd; + PITEM_PREFIX CurrentItem; + ULONG CurrentItemSize; + PLONG_ITEM CurrentLongItem; + PSHORT_ITEM CurrentShortItem; + ULONG Data; + UCHAR ReportType; + PHID_REPORT Report; + PMAIN_ITEM_DATA MainItemData; + PHID_PARSER_CONTEXT ParserContext; + + // + // reset parser + // + HidParser_ResetParser(Parser); + + // + // get parser context + // + ParserContext =(PHID_PARSER_CONTEXT)Parser->ParserContext; + ASSERT(ParserContext); + + // + // allocate usage stack + // + ParserContext->LocalItemState.UsageStackAllocated = 10; + ParserContext->LocalItemState.UsageStack = (PUSAGE_VALUE)Parser->Alloc(ParserContext->LocalItemState.UsageStackAllocated * sizeof(USAGE_VALUE)); + if (!ParserContext->LocalItemState.UsageStack) + { + // + // no memory + // + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // now allocate root collection + // + Status = HidParser_AllocateCollection(Parser, NULL, COLLECTION_LOGICAL, &ParserContext->LocalItemState, &ParserContext->RootCollection); + if (Status != HIDPARSER_STATUS_SUCCESS) + { + // + // no memory + // + Parser->Free(ParserContext->LocalItemState.UsageStack); + ParserContext->LocalItemState.UsageStack = NULL; + return HIDPARSER_STATUS_INSUFFICIENT_RESOURCES; + } + + // + // start parsing + // + CurrentCollection = ParserContext->RootCollection; + CurrentOffset = ReportDescriptor; + ReportEnd = ReportDescriptor + ReportLength; + + do + { + // + // get current item + // + CurrentItem = (PITEM_PREFIX)CurrentOffset; + + // + // get item size + // + CurrentItemSize = ItemSize[CurrentItem->Size]; + Data = 0; + + if (CurrentItem->Type == ITEM_TYPE_LONG) + { + // + // increment item size with size of data item + // + CurrentLongItem = (PLONG_ITEM)CurrentItem; + CurrentItemSize += CurrentLongItem->DataSize; + } + else + { + // + // get short item + // + CurrentShortItem = (PSHORT_ITEM)CurrentItem; + + // + // get associated data + // + //ASSERT(CurrentItemSize == 1 || CurrentItemSize == 2 || CurrentItemSize == 4); + if (CurrentItemSize == 1) + Data = CurrentShortItem->Data.UData8[0]; + else if (CurrentItemSize == 2) + Data = CurrentShortItem->Data.UData16[0]; + else if (CurrentItemSize == 4) + Data = CurrentShortItem->Data.UData32; + else + { + // + // invalid item size + // + //Parser->Debug("CurrentItem invalid item size %lu\n", CurrentItemSize); + } + + } + + // + // handle items + // + ASSERT(CurrentItem->Type >= ITEM_TYPE_MAIN && CurrentItem->Type <= ITEM_TYPE_LONG); + switch(CurrentItem->Type) + { + case ITEM_TYPE_MAIN: + { + // preprocess the local state if relevant (usages for + // collections and report items) + if (CurrentItem->Tag != ITEM_TAG_MAIN_END_COLLECTION) + { + // make all usages extended for easier later processing + for (Index = 0; Index < ParserContext->LocalItemState.UsageStackUsed; Index++) + { + // + // is it already extended + // + if (ParserContext->LocalItemState.UsageStack[Index].IsExtended) + continue; + + // + // extend usage item + // + ParserContext->LocalItemState.UsageStack[Index].u.s.UsagePage = ParserContext->GlobalItemState.UsagePage; + ParserContext->LocalItemState.UsageStack[Index].IsExtended = TRUE; + } + + if (!ParserContext->LocalItemState.UsageMinimum.IsExtended) { + // the specs say if one of them is extended they must + // both be extended, so if the minimum isn't, the + // maximum mustn't either. + ParserContext->LocalItemState.UsageMinimum.u.s.UsagePage + = ParserContext->LocalItemState.UsageMaximum.u.s.UsagePage + = ParserContext->GlobalItemState.UsagePage; + ParserContext->LocalItemState.UsageMinimum.IsExtended + = ParserContext->LocalItemState.UsageMaximum.IsExtended = TRUE; + } + + //LocalItemState.usage_stack = usageStack; + //ParserContext->LocalItemState.UsageStackUsed = UsageStackUsed; + } + + if (CurrentItem->Tag == ITEM_TAG_MAIN_COLLECTION) { + + // + // allocate new collection + // + Status = HidParser_AllocateCollection(Parser, CurrentCollection, (UCHAR)Data, &ParserContext->LocalItemState, &NewCollection); + ASSERT(Status == HIDPARSER_STATUS_SUCCESS); + + // + // add new collection to current collection + // + Status = HidParser_AddCollection(Parser, CurrentCollection, NewCollection); + ASSERT(Status == HIDPARSER_STATUS_SUCCESS); + + // + // make new collection current + // + CurrentCollection = NewCollection; + } + else if (CurrentItem->Tag == ITEM_TAG_MAIN_END_COLLECTION) + { + // + // assert on ending the root collection + // + ASSERT(CurrentCollection != ParserContext->RootCollection); + + // + // use parent of current collection + // + CurrentCollection = CurrentCollection->Root; + ASSERT(CurrentCollection); + } + else + { + ReportType = HID_REPORT_TYPE_ANY; + + switch (CurrentItem->Tag) { + case ITEM_TAG_MAIN_INPUT: + ReportType = HID_REPORT_TYPE_INPUT; + break; + + case ITEM_TAG_MAIN_OUTPUT: + ReportType = HID_REPORT_TYPE_OUTPUT; + break; + + case ITEM_TAG_MAIN_FEATURE: + ReportType = HID_REPORT_TYPE_FEATURE; + break; + + default: + Parser->Debug("[HIDPARSE] Unknown ReportType %x\n", CurrentItem->Tag); + ASSERT(FALSE); + break; + } + + if (ReportType == HID_REPORT_TYPE_ANY) + break; + + // + // get report + // + Status = HidParser_GetReport(Parser, ReportType, ParserContext->GlobalItemState.ReportId, TRUE, &Report); + ASSERT(Status == HIDPARSER_STATUS_SUCCESS); + + // fill in a sensible default if the index isn't set + if (!ParserContext->LocalItemState.DesignatorIndexSet) { + ParserContext->LocalItemState.DesignatorIndex + = ParserContext->LocalItemState.DesignatorMinimum; + } + + if (!ParserContext->LocalItemState.StringIndexSet) + ParserContext->LocalItemState.StringIndex = ParserContext->LocalItemState.StringMinimum; + + // + // get main item data + // + MainItemData = (PMAIN_ITEM_DATA)&Data; + + // + // add states & data to the report + // + Status = HidParser_AddMainItem(Parser, Report, &ParserContext->GlobalItemState, &ParserContext->LocalItemState, MainItemData, CurrentCollection); + ASSERT(Status == HIDPARSER_STATUS_SUCCESS); + } + + // + // backup stack + // + Index = ParserContext->LocalItemState.UsageStackAllocated; + NewUsageStack = ParserContext->LocalItemState.UsageStack; + + // + // reset the local item state and clear the usage stack + // + Parser->Zero(&ParserContext->LocalItemState, sizeof(LOCAL_ITEM_STATE)); + + // + // restore stack + // + ParserContext->LocalItemState.UsageStack = NewUsageStack; + ParserContext->LocalItemState.UsageStackAllocated = Index; + break; + } + case ITEM_TYPE_GLOBAL: + { + switch (CurrentItem->Tag) { + case ITEM_TAG_GLOBAL_USAGE_PAGE: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_USAGE_PAGE %x\n", Data); + ParserContext->GlobalItemState.UsagePage = Data; + break; + case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOGICAL_MINIMUM %x\n", Data); + ParserContext->GlobalItemState.LogicalMinimum = Data; + break; + + case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_LOCAL_MAXIMUM %x\n", Data); + ParserContext->GlobalItemState.LogicialMaximum = Data; + break; + + case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM %x\n", Data); + ParserContext->GlobalItemState.PhysicalMinimum = Data; + break; + + case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM %x\n", Data); + ParserContext->GlobalItemState.PhysicalMaximum = Data; + break; + + case ITEM_TAG_GLOBAL_UNIT_EXPONENT: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT_EXPONENT %x\n", Data); + ParserContext->GlobalItemState.UnitExponent = Data; + break; + + case ITEM_TAG_GLOBAL_UNIT: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_UNIT %x\n", Data); + ParserContext->GlobalItemState.Unit = Data; + break; + + case ITEM_TAG_GLOBAL_REPORT_SIZE: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_SIZE %x\n", Data); + ParserContext->GlobalItemState.ReportSize = Data; + break; + + case ITEM_TAG_GLOBAL_REPORT_ID: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_ID %x\n", Data); + ParserContext->GlobalItemState.ReportId = Data; + ParserContext->UseReportIDs = TRUE; + break; + + case ITEM_TAG_GLOBAL_REPORT_COUNT: + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_REPORT_COUNT %x\n", Data); + ParserContext->GlobalItemState.ReportCount = Data; + break; + + case ITEM_TAG_GLOBAL_PUSH: + { + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_PUSH\n"); + // + // allocate global item state + // + LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)Parser->Alloc(sizeof(GLOBAL_ITEM_STATE)); + ASSERT(LinkedGlobalItemState); + + // + // copy global item state + // + Parser->Copy(LinkedGlobalItemState, &ParserContext->GlobalItemState, sizeof(GLOBAL_ITEM_STATE)); + + // + // store pushed item in link member + // + ParserContext->GlobalItemState.Next = (struct __GLOBAL_ITEM_STATE__*)LinkedGlobalItemState; + break; + } + case ITEM_TAG_GLOBAL_POP: + { + Parser->Debug("[HIDPARSE] ITEM_TAG_GLOBAL_POP\n"); + if (ParserContext->GlobalItemState.Next == NULL) + { + // + // pop without push + // + ASSERT(FALSE); + break; + } + + // + // get link + // + LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next; + + // + // replace current item with linked one + // + Parser->Copy(&ParserContext->GlobalItemState, LinkedGlobalItemState, sizeof(GLOBAL_ITEM_STATE)); + + // + // free item + // + Parser->Free(LinkedGlobalItemState); + break; + } + + default: + // + // unknown / unsupported tag + // + ASSERT(FALSE); + break; + } + + break; + } + case ITEM_TYPE_LOCAL: + { + switch (CurrentItem->Tag) + { + case ITEM_TAG_LOCAL_USAGE: + { + if (ParserContext->LocalItemState.UsageStackUsed >= ParserContext->LocalItemState.UsageStackAllocated) + { + // + // increment stack size + // + ParserContext->LocalItemState.UsageStackAllocated += 10; + + // + // build new usage stack + // + NewUsageStack = (PUSAGE_VALUE)Parser->Alloc(sizeof(USAGE_VALUE) * ParserContext->LocalItemState.UsageStackAllocated); + ASSERT(NewUsageStack); + + // + // copy old usage stack + // + Parser->Copy(NewUsageStack, ParserContext->LocalItemState.UsageStack, sizeof(USAGE_VALUE) * (ParserContext->LocalItemState.UsageStackAllocated - 10)); + + // + // free old usage stack + // + Parser->Free(ParserContext->LocalItemState.UsageStack); + + // + // replace with new usage stack + // + ParserContext->LocalItemState.UsageStack = NewUsageStack; + } + + // + // get fresh usage value + // + UsageValue = &ParserContext->LocalItemState.UsageStack[ParserContext->LocalItemState.UsageStackUsed]; + + // + // init usage stack + // + UsageValue->IsExtended = CurrentItemSize == sizeof(ULONG); + UsageValue->u.Extended = Data; + + // + // increment usage stack usage count + // + ParserContext->LocalItemState.UsageStackUsed++; + break; + } + + case ITEM_TAG_LOCAL_USAGE_MINIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MINIMUM Data %x\n", Data); + ParserContext->LocalItemState.UsageMinimum.u.Extended = Data; + ParserContext->LocalItemState.UsageMinimum.IsExtended + = CurrentItemSize == sizeof(ULONG); + ParserContext->LocalItemState.UsageMinimumSet = TRUE; + break; + + case ITEM_TAG_LOCAL_USAGE_MAXIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_USAGE_MAXIMUM Data %x\n", Data); + ParserContext->LocalItemState.UsageMaximum.u.Extended = Data; + ParserContext->LocalItemState.UsageMaximum.IsExtended + = CurrentItemSize == sizeof(ULONG); + ParserContext->LocalItemState.UsageMaximumSet = TRUE; + break; + + case ITEM_TAG_LOCAL_DESIGNATOR_INDEX: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_INDEX Data %x\n", Data); + ParserContext->LocalItemState.DesignatorIndex = Data; + ParserContext->LocalItemState.DesignatorIndexSet = TRUE; + break; + + case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM Data %x\n", Data); + ParserContext->LocalItemState.DesignatorMinimum = Data; + break; + + case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM Data %x\n", Data); + ParserContext->LocalItemState.DesignatorMaximum = Data; + break; + + case ITEM_TAG_LOCAL_STRING_INDEX: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_INDEX Data %x\n", Data); + ParserContext->LocalItemState.StringIndex = Data; + ParserContext->LocalItemState.StringIndexSet = TRUE; + break; + + case ITEM_TAG_LOCAL_STRING_MINIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MINIMUM Data %x\n", Data); + ParserContext->LocalItemState.StringMinimum = Data; + break; + + case ITEM_TAG_LOCAL_STRING_MAXIMUM: + Parser->Debug("[HIDPARSE] ITEM_TAG_LOCAL_STRING_MAXIMUM Data %x\n", Data); + ParserContext->LocalItemState.StringMaximum = Data; + break; + + default: + Parser->Debug("Unknown Local Item Tag %x\n", CurrentItem->Tag); + ASSERT(FALSE); + break; + } + break; + } + + case ITEM_TYPE_LONG: + { + CurrentLongItem = (PLONG_ITEM)CurrentItem; + Parser->Debug("Unsupported ITEM_TYPE_LONG Tag %x\n", CurrentLongItem->LongItemTag); + break; + } + } + + // + // move to next item + // + CurrentOffset += CurrentItemSize + sizeof(ITEM_PREFIX); + + + }while(CurrentOffset < ReportEnd); + + + // + // cleanup global stack + // + LinkedGlobalItemState = (PGLOBAL_ITEM_STATE)ParserContext->GlobalItemState.Next; + while(LinkedGlobalItemState != NULL) + { + Parser->Debug("[HIDPARSE] Freeing GlobalState %p\n", LinkedGlobalItemState); + // + // free global item state + // + NextLinkedGlobalItemState = (PGLOBAL_ITEM_STATE)LinkedGlobalItemState->Next; + + // + // free state + // + Parser->Free(LinkedGlobalItemState); + + // + // move to next global state + // + LinkedGlobalItemState = NextLinkedGlobalItemState; + } + + // + // free usage stack + // + Parser->Free(ParserContext->LocalItemState.UsageStack); + ParserContext->LocalItemState.UsageStack = NULL; + + // + // done + // + return HIDPARSER_STATUS_SUCCESS; +} + diff --git a/lib/drivers/hidparser/parser.h b/lib/drivers/hidparser/parser.h new file mode 100644 index 00000000000..3519530033b --- /dev/null +++ b/lib/drivers/hidparser/parser.h @@ -0,0 +1,362 @@ + +#pragma once +#include +#include +#include +#include "hidparser.h" + + /* + * Copyright 2007, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + +#define HID_REPORT_TYPE_ANY 0x07 + + +#define ITEM_TYPE_MAIN 0x0 +#define ITEM_TYPE_GLOBAL 0x1 +#define ITEM_TYPE_LOCAL 0x2 +#define ITEM_TYPE_LONG 0x3 + +#define ITEM_TAG_MAIN_INPUT 0x8 +#define ITEM_TAG_MAIN_OUTPUT 0x9 +#define ITEM_TAG_MAIN_FEATURE 0xb +#define ITEM_TAG_MAIN_COLLECTION 0xa +#define ITEM_TAG_MAIN_END_COLLECTION 0xc + +#define ITEM_TAG_GLOBAL_USAGE_PAGE 0x0 +#define ITEM_TAG_GLOBAL_LOGICAL_MINIMUM 0x1 +#define ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM 0x2 +#define ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM 0x3 +#define ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM 0x4 +#define ITEM_TAG_GLOBAL_UNIT_EXPONENT 0x5 +#define ITEM_TAG_GLOBAL_UNIT 0x6 +#define ITEM_TAG_GLOBAL_REPORT_SIZE 0x7 +#define ITEM_TAG_GLOBAL_REPORT_ID 0x8 +#define ITEM_TAG_GLOBAL_REPORT_COUNT 0x9 +#define ITEM_TAG_GLOBAL_PUSH 0xa +#define ITEM_TAG_GLOBAL_POP 0xb + +#define ITEM_TAG_LOCAL_USAGE 0x0 +#define ITEM_TAG_LOCAL_USAGE_MINIMUM 0x1 +#define ITEM_TAG_LOCAL_USAGE_MAXIMUM 0x2 +#define ITEM_TAG_LOCAL_DESIGNATOR_INDEX 0x3 +#define ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM 0x4 +#define ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM 0x5 +#define ITEM_TAG_LOCAL_STRING_INDEX 0x7 +#define ITEM_TAG_LOCAL_STRING_MINIMUM 0x8 +#define ITEM_TAG_LOCAL_STRING_MAXIMUM 0x9 +#define ITEM_TAG_LOCAL_DELIMITER 0xa + +#define ITEM_TAG_LONG 0xf + +#define COLLECTION_PHYSICAL 0x00 +#define COLLECTION_APPLICATION 0x01 +#define COLLECTION_LOGICAL 0x02 +#define COLLECTION_REPORT 0x03 +#define COLLECTION_NAMED_ARRAY 0x04 +#define COLLECTION_USAGE_SWITCH 0x05 +#define COLLECTION_USAGE_MODIFIER 0x06 +#define COLLECTION_ALL 0xff + +#define UNIT_SYSTEM 0x0 +#define UNIT_LENGTH 0x1 +#define UNIT_MASS 0x2 +#define UNIT_TIME 0x3 +#define UNIT_TEMPERATURE 0x4 +#define UNIT_CURRENT 0x5 +#define UNIT_LUMINOUS_INTENSITY 0x6 + +#define USAGE_PAGE_SHIFT 16 +#define USAGE_PAGE_MASK 0xffff +#define USAGE_ID_SHIFT 0 +#define USAGE_ID_MASK 0xffff + +typedef struct +{ + UCHAR Size:2; + UCHAR Type:2; + UCHAR Tag:4; +}ITEM_PREFIX, *PITEM_PREFIX; + +typedef struct +{ + ITEM_PREFIX Prefix; + + union + { + UCHAR UData8[4]; + CHAR SData8[4]; + USHORT UData16[2]; + SHORT SData16[2]; + ULONG UData32; + LONG SData32; + }Data; + +}SHORT_ITEM, *PSHORT_ITEM; + +typedef struct +{ + ITEM_PREFIX Prefix; + UCHAR DataSize; + UCHAR LongItemTag; + UCHAR Data[0]; + +}LONG_ITEM,*PLONG_ITEM; + + +#define LBITFIELD9(b1,b2,b3,b4,b5,b6,b7,b8,b9) USHORT b9,b8,b7,b6,b5,b4,b3,b2,b1 +typedef struct +{ + USHORT DataConstant:1; + USHORT ArrayVariable:1; + USHORT Relative:1; + USHORT Wrap:1; + USHORT NonLinear:1; + USHORT NoPreferred:1; + USHORT NullState:1; + USHORT IsVolatile:1; + USHORT BitsBytes:1; + UCHAR reserved[2]; + +}MAIN_ITEM_DATA, *PMAIN_ITEM_DATA; + +typedef struct __GLOBAL_ITEM_STATE_ +{ + USHORT UsagePage; + ULONG LogicalMinimum; + ULONG LogicialMaximum; + ULONG PhysicalMinimum; + ULONG PhysicalMaximum; + UCHAR UnitExponent; + UCHAR Unit; + ULONG ReportSize; + ULONG ReportCount; + UCHAR ReportId; + struct __GLOBAL_ITEM_STATE__ * Next; +}GLOBAL_ITEM_STATE, *PGLOBAL_ITEM_STATE; + + +typedef struct usage_value +{ + union + { + struct { + USHORT UsageId; + USHORT UsagePage; + }s; + ULONG Extended; + }u; + + UCHAR IsExtended; +}USAGE_VALUE, *PUSAGE_VALUE; + + +typedef struct +{ + PUSAGE_VALUE UsageStack; + ULONG UsageStackUsed; + ULONG UsageStackAllocated; + + USAGE_VALUE UsageMinimum; + USAGE_VALUE UsageMaximum; + + UCHAR UsageMinimumSet; + UCHAR UsageMaximumSet; + + ULONG DesignatorIndex; + UCHAR DesignatorIndexSet; + + ULONG DesignatorMinimum; + ULONG DesignatorMaximum; + + UCHAR StringIndex; + UCHAR StringIndexSet; + UCHAR StringMinimum; + UCHAR StringMaximum; + +}LOCAL_ITEM_STATE, *PLOCAL_ITEM_STATE; + +typedef struct +{ + ULONG ByteOffset; + UCHAR Shift; + ULONG Mask; + UCHAR BitCount; + UCHAR HasData; + UCHAR Array; + UCHAR Relative; + ULONG Minimum; + ULONG Maximum; + ULONG UsageMinimum; + ULONG UsageMaximum; + ULONG Data; + UCHAR Valid; +}HID_REPORT_ITEM, *PHID_REPORT_ITEM; + +struct HID_REPORT; + +typedef struct __HID_COLLECTION__ +{ + struct __HID_COLLECTION__ * Root; + + UCHAR Type; + ULONG Usage; + UCHAR StringID; + UCHAR PhysicalID; + ULONG NodeCount; + struct __HID_COLLECTION__ ** Nodes; + + ULONG ItemCount; + ULONG ItemCountAllocated; + PHID_REPORT_ITEM * Items; + + //ULONG ReportCount; + //struct HID_REPORT ** Reports; + +}HID_COLLECTION, *PHID_COLLECTION; + +typedef struct +{ + UCHAR Type; + UCHAR ReportID; + ULONG ReportSize; + + ULONG ItemCount; + ULONG ItemAllocated; + PHID_REPORT_ITEM *Items; + + ULONG ReportStatus; + UCHAR * CurrentReport; + ULONG BusyCount; +}HID_REPORT, *PHID_REPORT; + +typedef struct +{ + // + // global item state + // + GLOBAL_ITEM_STATE GlobalItemState; + + // + // local item state + // + LOCAL_ITEM_STATE LocalItemState; + + // + // root collection + // + PHID_COLLECTION RootCollection; + + // + // report count + // + ULONG ReportCount; + + // + // reports + // + PHID_REPORT * Reports; + + // + // uses report ids + // + UCHAR UseReportIDs; + +}HID_PARSER_CONTEXT, *PHID_PARSER_CONTEXT; + +HIDPARSER_STATUS +HidParser_ParseReportDescriptor( + PHID_PARSER Parser, + PUCHAR Report, + ULONG ReportSize); + +ULONG +HidParser_NumberOfTopCollections( + IN PHID_PARSER Parser); + +#define HID_REPORT_TYPE_INPUT 0x01 +#define HID_REPORT_TYPE_OUTPUT 0x02 +#define HID_REPORT_TYPE_FEATURE 0x04 + +ULONG +HidParser_NumberOfReports( + IN PHID_PARSER Parser, + IN ULONG ReportType); + +HIDPARSER_STATUS +HidParser_GetCollectionUsagePage( + IN PHID_PARSER Parser, + IN ULONG CollectionNumber, + OUT PUSHORT Usage, + OUT PUSHORT UsagePage); + +ULONG +HidParser_GetReportLength( + IN PHID_PARSER Parser, + IN ULONG ReportType); + +UCHAR +HidParser_IsReportIDUsed( + IN PHID_PARSER Parser); + +ULONG +HidParser_GetReportItemCountFromReportType( + IN PHID_PARSER Parser, + IN ULONG ReportType); + +ULONG +HidParser_GetReportItemTypeCountFromReportType( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN ULONG bData); + +ULONG +HidParser_GetContextSize( + IN PHID_PARSER Parser); + +VOID +HidParser_FreeContext( + IN PHID_PARSER Parser, + IN PUCHAR Context, + IN ULONG ContextLength); + +ULONG +HidParser_GetTotalCollectionCount( + IN PHID_PARSER Parser); + +ULONG +HidParser_GetMaxUsageListLengthWithReportAndPage( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USAGE UsagePage OPTIONAL); + +HIDPARSER_STATUS +HidParser_GetSpecificValueCapsWithReport( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USHORT UsagePage, + IN USHORT Usage, + OUT PHIDP_VALUE_CAPS ValueCaps, + IN OUT PULONG ValueCapsLength); + + +HIDPARSER_STATUS +HidParser_GetUsagesWithReport( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USAGE UsagePage, + OUT USAGE *UsageList, + IN OUT PULONG UsageLength, + IN PCHAR ReportDescriptor, + IN ULONG ReportDescriptorLength); + +HIDPARSER_STATUS +HidParser_GetScaledUsageValueWithReport( + IN PHID_PARSER Parser, + IN ULONG ReportType, + IN USAGE UsagePage, + IN USAGE Usage, + OUT PLONG UsageValue, + IN PCHAR ReportDescriptor, + IN ULONG ReportDescriptorLength); diff --git a/media/inf/CMakeLists.txt b/media/inf/CMakeLists.txt index 716ed694c93..15b5331cd60 100644 --- a/media/inf/CMakeLists.txt +++ b/media/inf/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND INF_FILES font.inf hal.inf hdc.inf + input.inf intl.inf keyboard.inf ks.inf diff --git a/media/inf/input.inf b/media/inf/input.inf new file mode 100644 index 00000000000..810eafc1655 --- /dev/null +++ b/media/inf/input.inf @@ -0,0 +1,73 @@ +[Version] +Signature="$WINDOWS NT$" +Class=HIDClass +ClassGuid={745a17a0-74d3-11d0-b6fe-00a0c90f57da} +Provider=%MSFT% +LayoutFile=layout.inf +DriverVer=07/01/2001,5.1.2600.5512 + +[DestinationDirs] +DefaultDestDir = 12 +HID_Inst.CopyFilesDLL.NT = 11 +SPI_Files_DLL = 11 + +[ClassInstall] +Addreg=HIDClassReg + +[HIDClassReg] +HKR,,,,%HID.ClassName% +HKR,,Icon,,-24 +HKR,,NoInstallClass,,1 + +[ClassInstall32] +Addreg=HIDClassReg + +[MSMice] +%USB\VID_045E&PID_0009.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0009 +%USB\VID_045E&PID_001E.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_001E +%USB\VID_045E&PID_0023.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0023 +%USB\VID_045E&PID_0024.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0024 +%USB\VID_045E&PID_0025.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0025 +%USB\VID_045E&PID_0029.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0029 +%USB\VID_045E&PID_0039.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0039 +%USB\VID_045E&PID_0040.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0040 +%USB\VID_045E&PID_0047.DeviceDesc%=HID_Inst,, USB\VID_045E&PID_0047 + + +[Standard] +%HID_DEVICE_SYSTEM_GAME%=HID_Raw_Inst,, HID_DEVICE_SYSTEM_GAME +%HID_DEVICE%=HID_Raw_Inst,, HID_DEVICE +%HID.DeviceDesc% = HID_Inst,,GENERIC_HID_DEVICE,USB\Class_03&SubClass_01,USB\Class_03 + + +[HID_Inst.NT] +Copyfiles = HID_Inst.CopyFiles.NT, HID_Inst.CopyFilesDLL.NT + +[HID_Inst.CopyFiles.NT] +hidusb.sys +hidclass.sys +hidparse.sys + +[HID_INST.CopyFilesDLL.NT] +hid.dll + +[HID_Inst.NT.Services] +AddService = hidusb, 0x00000002, HID_Service_Inst + +[HID_Service_Inst] +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\hidusb.sys +LoadOrderGroup = extended base + +[strings] +MSFT = "ReactOS" +HID.DeviceDesc = "USB-HID (Human Interface Device)" +HID.DefaultDevice = "HID-Standardgerät" +HID.ClassName = "Eingabegeräte (Human Interface Devices)" +HID.SvcDesc = "ReactOS HID Class-Treiber" + + + + diff --git a/media/inf/msmouse.inf b/media/inf/msmouse.inf index 2d5e6fed22c..dae16ed4c77 100644 Binary files a/media/inf/msmouse.inf and b/media/inf/msmouse.inf differ diff --git a/media/inf/syssetup.inf.tpl b/media/inf/syssetup.inf.tpl index 5ae24870a65..4b2968a9dbb 100644 --- a/media/inf/syssetup.inf.tpl +++ b/media/inf/syssetup.inf.tpl @@ -22,6 +22,7 @@ display.inf fdc.inf hal.inf hdc.inf +input.inf keyboard.inf machine.inf msmouse.inf diff --git a/ntoskrnl/ob/obname.c b/ntoskrnl/ob/obname.c index b0d4ca59f2c..8d601eed77b 100644 --- a/ntoskrnl/ob/obname.c +++ b/ntoskrnl/ob/obname.c @@ -1208,4 +1208,30 @@ ObQueryDeviceMapInformation(IN PEPROCESS Process, KeReleaseGuardedMutex(&ObpDeviceMapLock); } +NTSTATUS +NTAPI +ObIsDosDeviceLocallyMapped( + IN ULONG Index, + OUT PUCHAR DosDeviceState) +{ + /* check parameters */ + if (Index < 1 || Index > 26) + { + /* invalid index */ + return STATUS_INVALID_PARAMETER; + } + + /* acquire lock */ + KeAcquireGuardedMutex(&ObpDeviceMapLock); + + /* get drive mapping status */ + *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0; + + /* release lock */ + KeReleaseGuardedMutex(&ObpDeviceMapLock); + + /* done */ + return STATUS_SUCCESS; +} + /* EOF */