#include "precomp.h"
+#define NDEBUG
+#include <debug.h>
+
static LPWSTR ClientIdentificationAddress = L"HIDCLASS";
static ULONG HidClassDeviceNumber = 0;
-ULONG
+NTSTATUS
NTAPI
-DllInitialize(ULONG Unknown)
+DllInitialize(
+ IN PUNICODE_STRING RegistryPath)
{
- return 0;
+ return STATUS_SUCCESS;
}
-ULONG
+NTSTATUS
NTAPI
-DllUnload()
+DllUnload(VOID)
{
- return 0;
+ return STATUS_SUCCESS;
}
NTSTATUS
NTSTATUS Status;
UNICODE_STRING DeviceName;
PDEVICE_OBJECT NewDeviceObject;
- PHIDCLASS_DEVICE_EXTENSION DeviceExtension;
+ PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
ULONG DeviceExtensionSize;
PHIDCLASS_DRIVER_EXTENSION DriverExtension;
-
/* increment device number */
InterlockedIncrement((PLONG)&HidClassDeviceNumber);
RtlInitUnicodeString(&DeviceName, CharDeviceName);
/* get driver object extension */
- DriverExtension = (PHIDCLASS_DRIVER_EXTENSION) IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress);
+ DriverExtension = IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress);
if (!DriverExtension)
{
/* device removed */
}
/* calculate device extension size */
- DeviceExtensionSize = sizeof(HIDCLASS_DEVICE_EXTENSION) + DriverExtension->DeviceExtensionSize;
+ DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + DriverExtension->DeviceExtensionSize;
/* now create the device */
Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &NewDeviceObject);
}
/* get device extension */
- DeviceExtension = (PHIDCLASS_DEVICE_EXTENSION)NewDeviceObject->DeviceExtension;
+ FDODeviceExtension = NewDeviceObject->DeviceExtension;
/* zero device extension */
- RtlZeroMemory(DeviceExtension, sizeof(HIDCLASS_DEVICE_EXTENSION));
+ RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION));
/* initialize device extension */
- DeviceExtension->HidDeviceExtension.PhysicalDeviceObject = PhysicalDeviceObject;
- DeviceExtension->HidDeviceExtension.MiniDeviceExtension = (PVOID)((ULONG_PTR)DeviceExtension + sizeof(HIDCLASS_DEVICE_EXTENSION));
- DeviceExtension->HidDeviceExtension.NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, PhysicalDeviceObject);
- DeviceExtension->IsFDO = TRUE;
- DeviceExtension->DriverExtension = DriverExtension;
+ FDODeviceExtension->Common.IsFDO = TRUE;
+ FDODeviceExtension->Common.DriverExtension = DriverExtension;
+ FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = PhysicalDeviceObject;
+ FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = (PVOID)((ULONG_PTR)FDODeviceExtension + sizeof(HIDCLASS_FDO_EXTENSION));
+ FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, PhysicalDeviceObject);
+ if (FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject == NULL)
+ {
+ /* no PDO */
+ IoDeleteDevice(NewDeviceObject);
+ DPRINT1("[HIDCLASS] failed to attach to device stack\n");
+ return STATUS_DEVICE_REMOVED;
+ }
/* sanity check */
- ASSERT(DeviceExtension->HidDeviceExtension.NextDeviceObject);
+ ASSERT(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
/* increment stack size */
NewDeviceObject->StackSize++;
{
/* failed */
DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status);
- IoDetachDevice(DeviceExtension->HidDeviceExtension.NextDeviceObject);
+ IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
IoDeleteDevice(NewDeviceObject);
return Status;
}
NTAPI
HidClassDriverUnload(
IN PDRIVER_OBJECT DriverObject)
+{
+ UNIMPLEMENTED
+}
+
+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 = 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 = DeviceObject->DeviceExtension;
+
+ //
+ // get stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ DPRINT("ShareAccess %x\n", IoStack->Parameters.Create.ShareAccess);
+ DPRINT("Options %x\n", IoStack->Parameters.Create.Options);
+ DPRINT("DesiredAccess %x\n", IoStack->Parameters.Create.SecurityContext->DesiredAccess);
+
+ //
+ // allocate context
+ //
+ Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG);
+ 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);
+ KeInitializeEvent(&Context->IrpReadComplete, NotificationEvent, FALSE);
+
+ //
+ // store context
+ //
+ ASSERT(IoStack->FileObject);
+ IoStack->FileObject->FsContext = 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_FILEOP_CONTEXT IrpContext;
+ BOOLEAN IsRequestPending = FALSE;
+ KIRQL OldLevel;
+ PLIST_ENTRY Entry;
+ PIRP ListIrp;
+
+ //
+ // get device extension
+ //
+ CommonDeviceExtension = 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 = IoStack->FileObject->FsContext;
+ ASSERT(IrpContext);
+
+ //
+ // acquire lock
+ //
+ KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
+
+ if (!IsListEmpty(&IrpContext->ReadPendingIrpListHead))
+ {
+ //
+ // FIXME cancel irp
+ //
+ IsRequestPending = TRUE;
+ }
+
+ //
+ // signal stop
+ //
+ IrpContext->StopInProgress = TRUE;
+
+ //
+ // release lock
+ //
+ KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
+
+ if (IsRequestPending)
+ {
+ //
+ // wait for request to complete
+ //
+ DPRINT1("[HIDCLASS] Waiting for read irp completion...\n");
+ KeWaitForSingleObject(&IrpContext->IrpReadComplete, Executive, KernelMode, FALSE, NULL);
+ }
+
+ //
+ // acquire lock
+ //
+ KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
+
+ //
+ // sanity check
+ //
+ ASSERT(IsListEmpty(&IrpContext->ReadPendingIrpListHead));
+
+ //
+ // now free all irps
+ //
+ while (!IsListEmpty(&IrpContext->IrpCompletedListHead))
+ {
+ //
+ // remove head irp
+ //
+ Entry = RemoveHeadList(&IrpContext->IrpCompletedListHead);
+
+ //
+ // get irp
+ //
+ ListIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // free the irp
+ //
+ IoFreeIrp(ListIrp);
+ }
+
+ //
+ // release lock
+ //
+ KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
+
+ //
+ // remove context
+ //
+ IoStack->FileObject->FsContext = NULL;
+
+ //
+ // free context
+ //
+ ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
+
+ //
+ // complete request
+ //
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
+
+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;
+ BOOLEAN IsEmpty;
+
+ //
+ // get irp context
+ //
+ IrpContext = 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 = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority);
+ 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;
+ IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information;
+
+ //
+ // free input report buffer
+ //
+ ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG);
+
+ //
+ // remove us from pending list
+ //
+ KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel);
+
+ //
+ // remove from pending list
+ //
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
+ //
+ // is list empty
+ //
+ IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead);
+
+ //
+ // 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);
+
+
+ DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty);
+ if (IrpContext->FileOp->StopInProgress && IsEmpty)
+ {
+ //
+ // last pending irp
+ //
+ DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
+ KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
+ }
+
+ if (IrpContext->FileOp->StopInProgress && IsEmpty)
+ {
+ //
+ // last pending irp
+ //
+ DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
+ KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
+ }
+
+ //
+ // free irp context
+ //
+ ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
+
+ //
+ // 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 = 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 = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT), HIDCLASS_TAG);
+ if (!IrpContext)
+ {
+ //
+ // no memory
+ //
+ IoFreeIrp(Irp);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get device extension
+ //
+ PDODeviceExtension = 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);
+
+ if (Context->StopInProgress)
+ {
+ //
+ // stop in progress
+ //
+ DPRINT1("[HIDCLASS] Stop In Progress\n");
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_CANCELLED;
+
+ }
+
+ //
+ // store report length
+ //
+ IrpContext->InputReportBufferLength = ReportDescription->InputLength;
+
+ //
+ // allocate buffer
+ //
+ IrpContext->InputReportBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpContext->InputReportBufferLength, HIDCLASS_TAG);
+ if (!IrpContext->InputReportBuffer)
+ {
+ //
+ // no memory
+ //
+ IoFreeIrp(Irp);
+ ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
+ 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 = DeviceObject->DeviceExtension;
+ ASSERT(CommonDeviceExtension->IsFDO == FALSE);
+
+ //
+ // sanity check
+ //
+ ASSERT(IoStack->FileObject);
+ ASSERT(IoStack->FileObject->FsContext);
+
+ //
+ // get context
+ //
+ Context = IoStack->FileObject->FsContext;
+ ASSERT(Context);
+
+ //
+ // FIXME support polled devices
+ //
+ ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
+
+ if (Context->StopInProgress)
+ {
+ //
+ // stop in progress
+ //
+ DPRINT1("[HIDCLASS] Stop In Progress\n");
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_CANCELLED;
+ }
+
+ //
+ // 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);
+
+ //
+ // let's 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
-HidClassDispatch(
+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 = DeviceObject->DeviceExtension;
+
+ //
+ // only PDO are supported
+ //
+ if (CommonDeviceExtension->IsFDO)
+ {
+ //
+ // invalid request
+ //
+ DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n");
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_INVALID_PARAMETER_1;
+ }
+
+ ASSERT(CommonDeviceExtension->IsFDO == FALSE);
+
+ //
+ // get pdo device extension
+ //
+ PDODeviceExtension = 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 = 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)
+{
+ PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
+ CommonDeviceExtension = DeviceObject->DeviceExtension;
+
+ if (CommonDeviceExtension->IsFDO)
+ {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ return HidClassFDO_DispatchRequest(DeviceObject, Irp);
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ PoStartNextPowerIrp(Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+}
+
+NTSTATUS
+NTAPI
+HidClass_PnP(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
+
+ //
+ // get common device extension
+ //
+ CommonDeviceExtension = 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 = 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(
}
/* now allocate the driver object extension */
- Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject, (PVOID)ClientIdentificationAddress, sizeof(HIDCLASS_DRIVER_EXTENSION), (PVOID*)&DriverExtension);
+ Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject,
+ ClientIdentificationAddress,
+ sizeof(HIDCLASS_DRIVER_EXTENSION),
+ (PVOID *)&DriverExtension);
if (!NT_SUCCESS(Status))
{
/* failed to allocate driver extension */
DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload;
/* copy driver dispatch routines */
- RtlCopyMemory(DriverExtension->MajorFunction, MinidriverRegistration->DriverObject->MajorFunction, sizeof(PDRIVER_DISPATCH) * IRP_MJ_MAXIMUM_FUNCTION);
+ RtlCopyMemory(DriverExtension->MajorFunction,
+ MinidriverRegistration->DriverObject->MajorFunction,
+ sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1));
/* initialize lock */
KeInitializeSpinLock(&DriverExtension->Lock);