Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Keyboard class driver * FILE: drivers/kbdclass/kbdclass.c * PURPOSE: Keyboard class driver * * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) */
#include "kbdclass.h"
#include <stdio.h>#include <pseh/pseh2.h>#include <kbdmou.h>#include <debug.h>
static DRIVER_UNLOAD DriverUnload;static DRIVER_DISPATCH ClassCreate;static DRIVER_DISPATCH ClassClose;static DRIVER_DISPATCH ClassCleanup;static DRIVER_DISPATCH ClassRead;static DRIVER_DISPATCH ClassDeviceControl;static DRIVER_DISPATCH ClassPower;static DRIVER_ADD_DEVICE ClassAddDevice;static DRIVER_STARTIO ClassStartIo;static DRIVER_CANCEL ClassCancelRoutine;static NTSTATUSHandleReadIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN IsInStartIo);
static VOID NTAPIDriverUnload(IN PDRIVER_OBJECT DriverObject){ // nothing to do here yet}
static NTSTATUS NTAPIClassCreate( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ TRACE_(CLASS_NAME, "IRP_MJ_CREATE\n");
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) return ForwardIrpAndForget(DeviceObject, Irp);
/* FIXME: open all associated Port devices */ Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;}
static NTSTATUS NTAPIClassClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ TRACE_(CLASS_NAME, "IRP_MJ_CLOSE\n");
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) return ForwardIrpAndForget(DeviceObject, Irp);
/* FIXME: close all associated Port devices */ Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;}
static NTSTATUS NTAPIClassCleanup( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ TRACE_(CLASS_NAME, "IRP_MJ_CLEANUP\n");
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) return ForwardIrpAndForget(DeviceObject, Irp);
/* FIXME: cleanup all associated Port devices */ Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;}
static NTSTATUS NTAPIClassRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; KIRQL OldIrql; NTSTATUS Status;
TRACE_(CLASS_NAME, "IRP_MJ_READ\n");
ASSERT(DeviceExtension->Common.IsClassDO);
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) return ForwardIrpAndForget(DeviceObject, Irp);
if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA)) { Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_BUFFER_TOO_SMALL; }
KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql); Status = HandleReadIrp(DeviceObject, Irp, FALSE); KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql); return Status;}
static NTSTATUS NTAPIClassDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ //PCLASS_DEVICE_EXTENSION DeviceExtension; NTSTATUS Status = STATUS_NOT_SUPPORTED;
TRACE_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL\n");
if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO) return ForwardIrpAndForget(DeviceObject, Irp);
//DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_KEYBOARD_QUERY_ATTRIBUTES: case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: case IOCTL_KEYBOARD_QUERY_INDICATORS: case IOCTL_KEYBOARD_QUERY_TYPEMATIC: { /* FIXME: We hope that all devices will return the same result. * Ask only the first one */ PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead; if (Head->Flink != Head) { /* We have at least one device */ PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, PORT_DEVICE_EXTENSION, ListEntry); IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(DevExt->DeviceObject, Irp); } break; } case IOCTL_KEYBOARD_SET_INDICATORS: case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */ { /* Send it to all associated Port devices */ PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead; PLIST_ENTRY Entry = Head->Flink; Status = STATUS_SUCCESS; while (Entry != Head) { PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Entry, PORT_DEVICE_EXTENSION, ListEntry);
IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
if (IoForwardIrpSynchronously(DevExt->LowerDevice, Irp)) { if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; } } else { Status = STATUS_UNSUCCESSFUL; } Entry = Entry->Flink; } break; } default: WARN_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n", IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode); ASSERT(FALSE); break; }
Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;}
static NTSTATUS NTAPIClassPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ NTSTATUS Status; PPORT_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = DeviceObject->DeviceExtension; if (!DeviceExtension->Common.IsClassDO) { /* Forward port DO IRPs to lower device */ PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(DeviceExtension->LowerDevice, Irp); }
switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction) { case IRP_MN_SET_POWER: case IRP_MN_QUERY_POWER: Irp->IoStatus.Status = STATUS_SUCCESS; break; } Status = Irp->IoStatus.Status; PoStartNextPowerIrp(Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status;}
static NTSTATUSReadRegistryEntries( IN PUNICODE_STRING RegistryPath, IN PCLASS_DRIVER_EXTENSION DriverExtension){ UNICODE_STRING ParametersRegistryKey; RTL_QUERY_REGISTRY_TABLE Parameters[4]; NTSTATUS Status;
/* HACK: We don't support multiple devices with this disabled */ ULONG DefaultConnectMultiplePorts = 1; ULONG DefaultDataQueueSize = 0x64; PCWSTR DefaultDeviceBaseName = L"KeyboardClass";
ParametersRegistryKey.Length = 0; ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL); ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, CLASS_TAG); if (!ParametersRegistryKey.Buffer) { WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n"); return STATUS_NO_MEMORY; } RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath); RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters"); ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
RtlZeroMemory(Parameters, sizeof(Parameters));
Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[0].Name = L"ConnectMultiplePorts"; Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts; Parameters[0].DefaultType = REG_DWORD; Parameters[0].DefaultData = &DefaultConnectMultiplePorts; Parameters[0].DefaultLength = sizeof(ULONG);
Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[1].Name = L"KeyboardDataQueueSize"; Parameters[1].EntryContext = &DriverExtension->DataQueueSize; Parameters[1].DefaultType = REG_DWORD; Parameters[1].DefaultData = &DefaultDataQueueSize; Parameters[1].DefaultLength = sizeof(ULONG);
Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[2].Name = L"KeyboardDeviceBaseName"; Parameters[2].EntryContext = &DriverExtension->DeviceBaseName; Parameters[2].DefaultType = REG_SZ; Parameters[2].DefaultData = (PVOID)DefaultDeviceBaseName; Parameters[2].DefaultLength = 0;
Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, ParametersRegistryKey.Buffer, Parameters, NULL, NULL);
if (NT_SUCCESS(Status)) { /* Check values */ if (DriverExtension->ConnectMultiplePorts != 0 && DriverExtension->ConnectMultiplePorts != 1) { DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts; } if (DriverExtension->DataQueueSize == 0) { DriverExtension->DataQueueSize = DefaultDataQueueSize; } } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { /* Registry path doesn't exist. Set defaults */ DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts; DriverExtension->DataQueueSize = DefaultDataQueueSize; if (RtlCreateUnicodeString(&DriverExtension->DeviceBaseName, DefaultDeviceBaseName)) Status = STATUS_SUCCESS; else Status = STATUS_NO_MEMORY; }
ExFreePoolWithTag(ParametersRegistryKey.Buffer, CLASS_TAG); return Status;}
static NTSTATUSCreateClassDeviceObject( IN PDRIVER_OBJECT DriverObject, OUT PDEVICE_OBJECT *ClassDO OPTIONAL){ PCLASS_DRIVER_EXTENSION DriverExtension; ULONG DeviceId = 0; ULONG PrefixLength; UNICODE_STRING DeviceNameU; PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */ PDEVICE_OBJECT Fdo; PCLASS_DEVICE_EXTENSION DeviceExtension; NTSTATUS Status;
TRACE_(CLASS_NAME, "CreateClassDeviceObject(0x%p)\n", DriverObject);
/* Create new device object */ DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); DeviceNameU.Length = 0; DeviceNameU.MaximumLength = (USHORT)wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */ + DriverExtension->DeviceBaseName.Length /* "KeyboardClass" */ + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */ + sizeof(UNICODE_NULL); /* Final NULL char */ DeviceNameU.Buffer = ExAllocatePoolWithTag(PagedPool, DeviceNameU.MaximumLength, CLASS_TAG); if (!DeviceNameU.Buffer) { WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n"); return STATUS_NO_MEMORY; } Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\"); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status); goto cleanup; } Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status); goto cleanup; } PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL); DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)]; while (DeviceId < 9999) { DeviceNameU.Length = (USHORT)(PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR)); Status = IoCreateDevice( DriverObject, sizeof(CLASS_DEVICE_EXTENSION), &DeviceNameU, FILE_DEVICE_KEYBOARD, FILE_DEVICE_SECURE_OPEN, FALSE, &Fdo); if (NT_SUCCESS(Status)) goto cleanup; else if (Status != STATUS_OBJECT_NAME_COLLISION) { WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status); goto cleanup; } DeviceId++; } WARN_(CLASS_NAME, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName); Status = STATUS_TOO_MANY_NAMES;cleanup: if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG); return Status; }
DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension; RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION)); DeviceExtension->Common.IsClassDO = TRUE; DeviceExtension->DriverExtension = DriverExtension; InitializeListHead(&DeviceExtension->ListHead); KeInitializeSpinLock(&DeviceExtension->ListSpinLock); KeInitializeSpinLock(&DeviceExtension->SpinLock); DeviceExtension->InputCount = 0; DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA), CLASS_TAG); if (!DeviceExtension->PortData) { ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG); return STATUS_NO_MEMORY; } DeviceExtension->DeviceName = DeviceNameU.Buffer; Fdo->Flags |= DO_POWER_PAGABLE; Fdo->Flags |= DO_BUFFERED_IO; /* FIXME: Why is it needed for 1st stage setup? */ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
/* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */ RtlWriteRegistryValue( RTL_REGISTRY_DEVICEMAP, DriverExtension->DeviceBaseName.Buffer, DeviceExtension->DeviceName, REG_SZ, DriverExtension->RegistryPath.Buffer, DriverExtension->RegistryPath.MaximumLength);
if (ClassDO) *ClassDO = Fdo;
return STATUS_SUCCESS;}
static NTSTATUSFillEntries( IN PDEVICE_OBJECT ClassDeviceObject, IN PIRP Irp, IN PKEYBOARD_INPUT_DATA DataStart, IN SIZE_T NumberOfEntries){ NTSTATUS Status = STATUS_SUCCESS;
if (ClassDeviceObject->Flags & DO_BUFFERED_IO) { RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, DataStart, NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA)); } else if (ClassDeviceObject->Flags & DO_DIRECT_IO) { PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (DestAddress) { RtlCopyMemory( DestAddress, DataStart, NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA)); } else Status = STATUS_UNSUCCESSFUL; } else { _SEH2_TRY { RtlCopyMemory( Irp->UserBuffer, DataStart, NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; }
return Status;}
static BOOLEAN NTAPIClassCallback( IN PDEVICE_OBJECT ClassDeviceObject, IN OUT PKEYBOARD_INPUT_DATA DataStart, IN PKEYBOARD_INPUT_DATA DataEnd, IN OUT PULONG ConsumedCount){ PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension; KIRQL OldIrql; SIZE_T InputCount = DataEnd - DataStart; SIZE_T ReadSize;
TRACE_(CLASS_NAME, "ClassCallback()\n");
ASSERT(ClassDeviceExtension->Common.IsClassDO);
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql); if (InputCount > 0) { if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize) { /* * We're exceeding the buffer, and data will be thrown away... * FIXME: What could we do, as we are at DISPATCH_LEVEL? */ ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount; } else ReadSize = InputCount;
/* * Move the input data from the port data queue to our class data * queue. */ RtlCopyMemory( &ClassDeviceExtension->PortData[ClassDeviceExtension->InputCount], (PCHAR)DataStart, sizeof(KEYBOARD_INPUT_DATA) * ReadSize);
/* Move the counter up */ ClassDeviceExtension->InputCount += ReadSize;
(*ConsumedCount) += (ULONG)ReadSize;
/* Complete pending IRP (if any) */ if (ClassDeviceExtension->PendingIrp) HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE); } KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
TRACE_(CLASS_NAME, "Leaving ClassCallback()\n"); return TRUE;}
/* Send IOCTL_INTERNAL_*_CONNECT to port */static NTSTATUSConnectPortDriver( IN PDEVICE_OBJECT PortDO, IN PDEVICE_OBJECT ClassDO){ KEVENT Event; PIRP Irp; IO_STATUS_BLOCK IoStatus; CONNECT_DATA ConnectData; NTSTATUS Status;
TRACE_(CLASS_NAME, "Connecting PortDO %p to ClassDO %p\n", PortDO, ClassDO);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
ConnectData.ClassDeviceObject = ClassDO; ConnectData.ClassService = ClassCallback;
Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_KEYBOARD_CONNECT, PortDO, &ConnectData, sizeof(CONNECT_DATA), NULL, 0, TRUE, &Event, &IoStatus); if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
Status = IoCallDriver(PortDO, Irp);
if (Status == STATUS_PENDING) KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); else IoStatus.Status = Status;
if (NT_SUCCESS(IoStatus.Status)) { ObReferenceObject(PortDO); ExInterlockedInsertTailList( &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListHead, &((PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension)->ListEntry, &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListSpinLock); if (ClassDO->StackSize <= PortDO->StackSize) { /* Increase the stack size, in case we have to * forward some IRPs to the port device object */ ClassDO->StackSize = PortDO->StackSize + 1; } }
return IoStatus.Status;}
/* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */static VOIDDestroyPortDriver( IN PDEVICE_OBJECT PortDO){ PPORT_DEVICE_EXTENSION DeviceExtension; PCLASS_DEVICE_EXTENSION ClassDeviceExtension; PCLASS_DRIVER_EXTENSION DriverExtension; KEVENT Event; PIRP Irp; IO_STATUS_BLOCK IoStatus; KIRQL OldIrql; NTSTATUS Status;
TRACE_(CLASS_NAME, "Destroying PortDO %p\n", PortDO);
DeviceExtension = (PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension; ClassDeviceExtension = DeviceExtension->ClassDO->DeviceExtension; DriverExtension = IoGetDriverObjectExtension(PortDO->DriverObject, PortDO->DriverObject);
/* Send IOCTL_INTERNAL_*_DISCONNECT */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_KEYBOARD_DISCONNECT, PortDO, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus); if (Irp) { Status = IoCallDriver(PortDO, Irp); if (Status == STATUS_PENDING) KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); }
/* Remove from ClassDeviceExtension->ListHead list */ KeAcquireSpinLock(&ClassDeviceExtension->ListSpinLock, &OldIrql); RemoveEntryList(&DeviceExtension->ListEntry); KeReleaseSpinLock(&ClassDeviceExtension->ListSpinLock, OldIrql);
/* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */ RtlDeleteRegistryValue( RTL_REGISTRY_DEVICEMAP, DriverExtension->DeviceBaseName.Buffer, ClassDeviceExtension->DeviceName);
if (DeviceExtension->LowerDevice) IoDetachDevice(DeviceExtension->LowerDevice); ObDereferenceObject(PortDO);
if (!DriverExtension->ConnectMultiplePorts && DeviceExtension->ClassDO) { ExFreePoolWithTag(ClassDeviceExtension->PortData, CLASS_TAG); ExFreePoolWithTag((PVOID)ClassDeviceExtension->DeviceName, CLASS_TAG); IoDeleteDevice(DeviceExtension->ClassDO); }
IoDeleteDevice(PortDO);}
static NTSTATUS NTAPIClassAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo){ PCLASS_DRIVER_EXTENSION DriverExtension; PDEVICE_OBJECT Fdo = NULL; PPORT_DEVICE_EXTENSION DeviceExtension = NULL; NTSTATUS Status;
TRACE_(CLASS_NAME, "ClassAddDevice called. Pdo = 0x%p\n", Pdo);
DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
if (Pdo == NULL) /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */ return STATUS_SUCCESS;
/* Create new device object */ Status = IoCreateDevice( DriverObject, sizeof(PORT_DEVICE_EXTENSION), NULL, Pdo->DeviceType, Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0, FALSE, &Fdo); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status); goto cleanup; } IoSetStartIoAttributes(Fdo, TRUE, TRUE);
DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension; RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION)); DeviceExtension->Common.IsClassDO = FALSE; DeviceExtension->DeviceObject = Fdo; DeviceExtension->PnpState = dsStopped; Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); goto cleanup; } if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE) Fdo->Flags |= DO_POWER_PAGABLE; if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO) Fdo->Flags |= DO_BUFFERED_IO; if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO) Fdo->Flags |= DO_DIRECT_IO;
if (DriverExtension->ConnectMultiplePorts) DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject; else { /* We need a new class device object for this Fdo */ Status = CreateClassDeviceObject( DriverObject, &DeviceExtension->ClassDO); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status); goto cleanup; } } Status = ConnectPortDriver(Fdo, DeviceExtension->ClassDO); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "ConnectPortDriver() failed with status 0x%08lx\n", Status); goto cleanup; } Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
/* Register interface ; ignore the error (if any) as having * a registered interface is not so important... */ Status = IoRegisterDeviceInterface( Pdo, &GUID_DEVINTERFACE_KEYBOARD, NULL, &DeviceExtension->InterfaceName); if (!NT_SUCCESS(Status)) DeviceExtension->InterfaceName.Length = 0;
return STATUS_SUCCESS;
cleanup: if (Fdo) DestroyPortDriver(Fdo); return Status;}
static VOID NTAPIClassCancelRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension; KIRQL OldIrql; BOOLEAN wasQueued = FALSE;
TRACE_(CLASS_NAME, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
ASSERT(ClassDeviceExtension->Common.IsClassDO);
IoReleaseCancelSpinLock(Irp->CancelIrql);
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
if (ClassDeviceExtension->PendingIrp == Irp) { ClassDeviceExtension->PendingIrp = NULL; wasQueued = TRUE; } KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
if (wasQueued) { Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { DPRINT1("Cancelled IRP is not pending. Race condition?\n"); }}
static NTSTATUSHandleReadIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, BOOLEAN IsInStartIo){ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; NTSTATUS Status; KIRQL OldIrql;
TRACE_(CLASS_NAME, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
ASSERT(DeviceExtension->Common.IsClassDO);
if (DeviceExtension->InputCount > 0) { SIZE_T NumberOfEntries;
NumberOfEntries = MIN( DeviceExtension->InputCount, IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));
Status = FillEntries( DeviceObject, Irp, DeviceExtension->PortData, NumberOfEntries);
if (NT_SUCCESS(Status)) { if (DeviceExtension->InputCount > NumberOfEntries) { RtlMoveMemory( &DeviceExtension->PortData[0], &DeviceExtension->PortData[NumberOfEntries], (DeviceExtension->InputCount - NumberOfEntries) * sizeof(KEYBOARD_INPUT_DATA)); }
DeviceExtension->InputCount -= NumberOfEntries;
Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA); }
/* Go to next packet and complete this request */ Irp->IoStatus.Status = Status;
(VOID)IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT); DeviceExtension->PendingIrp = NULL; } else { IoAcquireCancelSpinLock(&OldIrql); if (Irp->Cancel) { DeviceExtension->PendingIrp = NULL; Status = STATUS_CANCELLED; } else { IoMarkIrpPending(Irp); DeviceExtension->PendingIrp = Irp; (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine); Status = STATUS_PENDING; } IoReleaseCancelSpinLock(OldIrql); } return Status;}
static NTSTATUS NTAPIClassPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK Iosb; NTSTATUS Status;
switch (IrpSp->MinorFunction) { case IRP_MN_START_DEVICE: if (IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp)) { Status = Irp->IoStatus.Status; } else { Status = STATUS_UNSUCCESSFUL; }
if (NT_SUCCESS(Status)) { InitializeObjectAttributes(&ObjectAttributes, &DeviceExtension->InterfaceName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwOpenFile(&DeviceExtension->FileHandle, FILE_READ_DATA, &ObjectAttributes, &Iosb, 0, 0); if (!NT_SUCCESS(Status)) DeviceExtension->FileHandle = NULL; } else DeviceExtension->FileHandle = NULL; if (DeviceExtension->InterfaceName.Length != 0) IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, TRUE); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status;
case IRP_MN_STOP_DEVICE: if (DeviceExtension->FileHandle) { ZwClose(DeviceExtension->FileHandle); DeviceExtension->FileHandle = NULL; } Status = STATUS_SUCCESS; break;
case IRP_MN_REMOVE_DEVICE: if (DeviceExtension->InterfaceName.Length != 0) IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE); if (DeviceExtension->FileHandle) { ZwClose(DeviceExtension->FileHandle); DeviceExtension->FileHandle = NULL; } IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->LowerDevice, Irp); DestroyPortDriver(DeviceObject); return Status;
default: Status = Irp->IoStatus.Status; break; }
Irp->IoStatus.Status = Status; if (NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED) { IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(DeviceExtension->LowerDevice, Irp); } else { IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }}
static VOID NTAPIClassStartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; KIRQL OldIrql;
TRACE_(CLASS_NAME, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
ASSERT(DeviceExtension->Common.IsClassDO);
KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql); HandleReadIrp(DeviceObject, Irp, TRUE); KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);}
static VOID NTAPISearchForLegacyDrivers( IN PDRIVER_OBJECT DriverObject, IN PVOID Context, /* PCLASS_DRIVER_EXTENSION */ IN ULONG Count){ UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP"); PCLASS_DRIVER_EXTENSION DriverExtension; UNICODE_STRING PortBaseName = { 0, 0, NULL }; PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE hDeviceMapKey = (HANDLE)-1; HANDLE hPortKey = (HANDLE)-1; ULONG Index = 0; ULONG Size, ResultLength; NTSTATUS Status;
TRACE_(CLASS_NAME, "SearchForLegacyDrivers(%p %p %lu)\n", DriverObject, Context, Count);
if (Count != 1) return; DriverExtension = (PCLASS_DRIVER_EXTENSION)Context;
/* Create port base name, by replacing Class by Port at the end of the class base name */ Status = DuplicateUnicodeString( RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &DriverExtension->DeviceBaseName, &PortBaseName); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status); goto cleanup; } PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL)); RtlAppendUnicodeToString(&PortBaseName, L"Port");
/* Allocate memory */ Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH; KeyValueInformation = ExAllocatePoolWithTag(PagedPool, Size, CLASS_TAG); if (!KeyValueInformation) { WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n"); Status = STATUS_NO_MEMORY; goto cleanup; }
/* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */ InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes); if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n"); Status = STATUS_SUCCESS; goto cleanup; } else if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status); goto cleanup; }
/* Open sub key */ InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL); Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes); if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName); Status = STATUS_SUCCESS; goto cleanup; } else if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status); goto cleanup; }
/* Read each value name */ while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS) { UNICODE_STRING PortName; PDEVICE_OBJECT PortDeviceObject = NULL; PFILE_OBJECT FileObject = NULL;
PortName.Length = PortName.MaximumLength = (USHORT)KeyValueInformation->NameLength; PortName.Buffer = KeyValueInformation->Name;
/* Open the device object pointer */ Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName, Status); continue; } INFO_(CLASS_NAME, "Legacy driver found\n");
Status = ClassAddDevice(DriverObject, PortDeviceObject); if (!NT_SUCCESS(Status)) { /* FIXME: Log the error */ WARN_(CLASS_NAME, "ClassAddDevice() failed with status 0x%08lx\n", Status); }
ObDereferenceObject(FileObject); }
cleanup: if (KeyValueInformation != NULL) ExFreePoolWithTag(KeyValueInformation, CLASS_TAG); if (hDeviceMapKey != (HANDLE)-1) ZwClose(hDeviceMapKey); if (hPortKey != (HANDLE)-1) ZwClose(hPortKey);}
/* * Standard DriverEntry method. */NTSTATUS NTAPIDriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){ PCLASS_DRIVER_EXTENSION DriverExtension; NTSTATUS Status;
Status = IoAllocateDriverObjectExtension( DriverObject, DriverObject, sizeof(CLASS_DRIVER_EXTENSION), (PVOID*)&DriverExtension); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status); return Status; } RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
Status = DuplicateUnicodeString( RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, RegistryPath, &DriverExtension->RegistryPath); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status); return Status; }
Status = ReadRegistryEntries(RegistryPath, DriverExtension); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "ReadRegistryEntries() failed with status 0x%08lx\n", Status); return Status; }
if (DriverExtension->ConnectMultiplePorts == 1) { Status = CreateClassDeviceObject( DriverObject, &DriverExtension->MainClassDeviceObject); if (!NT_SUCCESS(Status)) { WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status); return Status; } }
DriverObject->DriverExtension->AddDevice = ClassAddDevice; DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup; DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead; DriverObject->MajorFunction[IRP_MJ_POWER] = ClassPower; DriverObject->MajorFunction[IRP_MJ_PNP] = ClassPnp; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ForwardIrpAndForget; DriverObject->DriverStartIo = ClassStartIo;
/* We will detect the legacy devices later */ IoRegisterDriverReinitialization( DriverObject, SearchForLegacyDrivers, DriverExtension);
return STATUS_SUCCESS;}