reactos/drivers/hid/hidclass/hidclass.c

463 lines
14 KiB
C
Raw Normal View History

/*
* 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)
{
UNIMPLEMENTED
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
HidClass_Close(
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_Read(
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_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;
PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
//
// get device extension
//
CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(CommonDeviceExtension->IsFDO == FALSE);
PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)CommonDeviceExtension;
//
// 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);
//
// init result buffer
//
CollectionInformation->DescriptorSize = PDODeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedDataLength; //FIXME which collection is to be retrieved for composite devices / multi collection devices?
CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
CollectionInformation->VendorID = PDODeviceExtension->Attributes.VendorID;
CollectionInformation->ProductID = PDODeviceExtension->Attributes.ProductID;
CollectionInformation->VersionNumber = PDODeviceExtension->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:
{
//
// FIXME: which collection to use for composite / multi collection devices...
//
//
// check if output buffer is big enough
//
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < PDODeviceExtension->DeviceDescription.CollectionDesc[0].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, PDODeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedData, PDODeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedDataLength);
//
// complete request
//
Irp->IoStatus.Information = PDODeviceExtension->DeviceDescription.CollectionDesc[0].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);
ASSERT(FALSE);
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);
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);
DPRINT1("[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;
}