Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303/* * 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"
#define NDEBUG#include <debug.h>
static LPWSTR ClientIdentificationAddress = L"HIDCLASS";static ULONG HidClassDeviceNumber = 0;
NTSTATUSNTAPIDllInitialize( IN PUNICODE_STRING RegistryPath){ return STATUS_SUCCESS;}
NTSTATUSNTAPIDllUnload(VOID){ return STATUS_SUCCESS;}
NTSTATUSNTAPIHidClassAddDevice( 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 = 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 = NewDeviceObject->DeviceExtension;
/* zero device extension */ RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION));
/* initialize device extension */ 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(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;}
VOIDNTAPIHidClassDriverUnload( IN PDRIVER_OBJECT DriverObject){ UNIMPLEMENTED;}
NTSTATUSNTAPIHidClass_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) { // // only supported for PDO // Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; }
// // 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;}
NTSTATUSNTAPIHidClass_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;}
NTSTATUSNTAPIHidClass_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;}
PIRPHidClass_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;}
NTSTATUSHidClass_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;}
NTSTATUSNTAPIHidClass_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;}
NTSTATUSNTAPIHidClass_Write( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PIO_STACK_LOCATION IoStack; PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; PIRP SubIrp; KEVENT Event; IO_STATUS_BLOCK IoStatusBlock; HID_XFER_PACKET XferPacket; NTSTATUS Status; ULONG Length;
IoStack = IoGetCurrentIrpStackLocation(Irp); Length = IoStack->Parameters.Write.Length; if (Length < 1) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; }
RtlZeroMemory(&XferPacket, sizeof(XferPacket)); XferPacket.reportBufferLen = Length; XferPacket.reportBuffer = Irp->UserBuffer; XferPacket.reportId = XferPacket.reportBuffer[0];
CommonDeviceExtension = DeviceObject->DeviceExtension; SubIrp = IoBuildDeviceIoControlRequest( IOCTL_HID_WRITE_REPORT, CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatusBlock); if (!SubIrp) { Irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } SubIrp->UserBuffer = &XferPacket; KeInitializeEvent(&Event, SynchronizationEvent, FALSE); Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status;}
NTSTATUSNTAPIHidClass_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; } case IOCTL_HID_GET_FEATURE: { PIRP SubIrp; KEVENT Event; IO_STATUS_BLOCK IoStatusBlock; HID_XFER_PACKET XferPacket; NTSTATUS Status; PHIDP_REPORT_IDS ReportDescription;
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]); if (!ReportDescription || IoStack->Parameters.DeviceIoControl.OutputBufferLength < ReportDescription->FeatureLength) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; }
RtlZeroMemory(&XferPacket, sizeof(XferPacket)); XferPacket.reportBufferLen = ReportDescription->FeatureLength; XferPacket.reportBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); XferPacket.reportId = ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]; if (!XferPacket.reportBuffer) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; }
SubIrp = IoBuildDeviceIoControlRequest( IOCTL_HID_GET_FEATURE, CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatusBlock); if (!SubIrp) { Irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } SubIrp->UserBuffer = &XferPacket; KeInitializeEvent(&Event, SynchronizationEvent, FALSE); Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } case IOCTL_HID_SET_FEATURE: { PIRP SubIrp; KEVENT Event; IO_STATUS_BLOCK IoStatusBlock; HID_XFER_PACKET XferPacket; NTSTATUS Status; PHIDP_REPORT_IDS ReportDescription;
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]); if (!ReportDescription || IoStack->Parameters.DeviceIoControl.InputBufferLength < ReportDescription->FeatureLength) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; }
RtlZeroMemory(&XferPacket, sizeof(XferPacket)); XferPacket.reportBufferLen = ReportDescription->FeatureLength; XferPacket.reportBuffer = Irp->AssociatedIrp.SystemBuffer; XferPacket.reportId = XferPacket.reportBuffer[0];
SubIrp = IoBuildDeviceIoControlRequest( IOCTL_HID_SET_FEATURE, CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &IoStatusBlock); if (!SubIrp) { Irp->IoStatus.Status = STATUS_NO_MEMORY; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } SubIrp->UserBuffer = &XferPacket; KeInitializeEvent(&Event, SynchronizationEvent, FALSE); Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } 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; } }}
NTSTATUSNTAPIHidClass_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;}
NTSTATUSNTAPIHidClass_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; }}
NTSTATUSNTAPIHidClass_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); }}
NTSTATUSNTAPIHidClass_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);}
NTSTATUSNTAPIHidClassDispatch( 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); }}
NTSTATUSNTAPIHidRegisterMinidriver( 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, 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;}