i8042prt.c
来自「一个类似windows」· C语言 代码 · 共 925 行 · 第 1/2 页
C
925 行
WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
hookworkitemdone:
WorkItemData->Irp->IoStatus.Information = 0;
IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
IoFreeWorkItem(WorkItemData->WorkItem);
ExFreePool(WorkItemData);
DPRINT("HookWorkItem done\n");
}
static VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
if (!I8042StartIoKbd(DeviceObject, Irp)) {
DPRINT1("Unhandled StartIo!\n");
}
}
static NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
DPRINT("InternalDeviceControl\n");
switch (FdoDevExt->Type) {
case Keyboard:
Status = I8042InternalDeviceControlKbd(DeviceObject, Irp);
break;
case Mouse:
Status = I8042InternalDeviceControlMouse(DeviceObject, Irp);
break;
}
if (Status == STATUS_INVALID_DEVICE_REQUEST) {
DPRINT1("Invalid internal device request!\n");
}
if (Status != STATUS_PENDING)
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
static NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status;
DPRINT ("I8042CreateDispatch\n");
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
{
NTSTATUS Status;
UCHAR Value = 0;
ULONG Counter;
DevExt->MouseExists = FALSE;
DevExt->KeyboardExists = FALSE;
I8042Flush();
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST)) {
DPRINT1("Writing KBD_SELF_TEST command failed\n");
return STATUS_IO_TIMEOUT;
}
// Wait longer?
Counter = 10;
do {
Status = I8042ReadDataWait(DevExt, &Value);
} while ((Counter--) && (STATUS_IO_TIMEOUT == Status));
if (!NT_SUCCESS(Status)) {
DPRINT1("Failed to read KBD_SELF_TEST response, status 0x%x\n",
Status);
return Status;
}
if (Value != 0x55) {
DPRINT1("Got %x instead of 55\n", Value);
return STATUS_IO_DEVICE_ERROR;
}
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value |= CCB_KBD_DISAB | CCB_MOUSE_DISAB; /* disable keyboard/mouse */
Value &= ~(CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB);
/* don't enable keyboard and mouse interrupts */
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
DPRINT1("Can't set i8042 mode\n");
return FALSE;
}
if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
DPRINT1("Can't send i8042 mode\n");
return FALSE;
}
/*
* We used to send a KBD_LINE_TEST command here, but on at least HP
* Pavilion notebooks the response to that command was incorrect.
* So now we just assume that a keyboard is attached.
*/
DevExt->KeyboardExists = TRUE;
if (I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
{
Status = I8042ReadDataWait(DevExt, &Value);
if (NT_SUCCESS(Status) && Value == 0)
DevExt->MouseExists = TRUE;
}
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
{
NTSTATUS Status;
Status = I8042BasicDetect(DevExt);
if (!NT_SUCCESS(Status)) {
DPRINT1("Basic keyboard detection failed: %x\n", Status);
return Status;
}
if (DevExt->MouseExists) {
DPRINT("Aux port detected\n");
DevExt->MouseExists = I8042DetectMouse(DevExt);
}
if (!DevExt->KeyboardExists) {
DPRINT("Keyboard port not detected\n");
if (DevExt->Settings.Headless)
/* Act as if it exists regardless */
DevExt->KeyboardExists = TRUE;
} else {
DPRINT("Keyboard port detected\n");
DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
}
if (DevExt->KeyboardExists) {
DPRINT("Keyboard detected\n");
I8042KeyboardEnable(DevExt);
I8042KeyboardEnableInterrupt(DevExt);
}
if (DevExt->MouseExists) {
DPRINT("Mouse detected\n");
I8042MouseEnable(DevExt);
}
return STATUS_SUCCESS;
}
static NTSTATUS
AddRegistryEntry(
IN PCWSTR PortTypeName,
IN PUNICODE_STRING DeviceName,
IN PCWSTR RegistryPath)
{
UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hDeviceMapKey = (HANDLE)-1;
HANDLE hPortKey = (HANDLE)-1;
UNICODE_STRING PortTypeNameU;
NTSTATUS Status;
InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
if (!NT_SUCCESS(Status))
{
DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
Status = STATUS_SUCCESS;
cleanup:
if (hDeviceMapKey != (HANDLE)-1)
ZwClose(hDeviceMapKey);
if (hPortKey != (HANDLE)-1)
ZwClose(hPortKey);
return Status;
}
static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT Pdo)
{
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPort8042");
UNICODE_STRING MouseName = RTL_CONSTANT_STRING(L"\\Device\\PointerPort8042");
ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
KIRQL DirqlKeyboard = 0;
KIRQL DirqlMouse = 0;
KIRQL DirqlMax;
KAFFINITY Affinity;
NTSTATUS Status;
PDEVICE_EXTENSION DevExt;
PFDO_DEVICE_EXTENSION FdoDevExt;
PDEVICE_OBJECT Fdo;
DPRINT("I8042AddDevice\n");
if (Pdo != NULL)
{
/* Device detected by pnpmgr. Ignore it, as we already have
* detected the keyboard and mouse at first call */
return STATUS_UNSUCCESSFUL;
}
Status = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
NULL,
FILE_DEVICE_8042_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Fdo);
if (!NT_SUCCESS(Status))
return Status;
DevExt = Fdo->DeviceExtension;
RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
I8042ReadRegistry(DriverObject, DevExt);
KeInitializeSpinLock(&DevExt->SpinLock);
InitializeListHead(&DevExt->BusDevices);
KeInitializeDpc(&DevExt->DpcKbd,
I8042DpcRoutineKbd,
DevExt);
KeInitializeDpc(&DevExt->DpcMouse,
I8042DpcRoutineMouse,
DevExt);
KeInitializeDpc(&DevExt->DpcMouseTimeout,
I8042DpcRoutineMouseTimeout,
DevExt);
KeInitializeTimer(&DevExt->TimerMouseTimeout);
Status = I8042Initialize(DevExt);
if (!NT_SUCCESS(STATUS_SUCCESS)) {
DPRINT1("Initialization failure: %x\n", Status);
return Status;
}
if (DevExt->KeyboardExists) {
MappedIrqKeyboard = HalGetInterruptVector(Internal,
0,
0,
KEYBOARD_IRQ,
&DirqlKeyboard,
&Affinity);
Status = IoCreateDevice(DriverObject,
sizeof(FDO_DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_8042_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Fdo);
if (NT_SUCCESS(Status))
{
AddRegistryEntry(L"KeyboardPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
FdoDevExt = Fdo->DeviceExtension;
RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
FdoDevExt->PortDevExt = DevExt;
FdoDevExt->Type = Keyboard;
FdoDevExt->DeviceObject = Fdo;
Fdo->Flags |= DO_BUFFERED_IO;
DevExt->DebugWorkItem = IoAllocateWorkItem(Fdo);
DevExt->KeyboardObject = Fdo;
DevExt->KeyboardBuffer = ExAllocatePoolWithTag(
NonPagedPool,
DevExt->KeyboardAttributes.InputDataQueueLength *
sizeof(KEYBOARD_INPUT_DATA),
TAG_I8042);
if (!DevExt->KeyboardBuffer) {
DPRINT1("No memory for keyboardbuffer\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
}
else
DevExt->KeyboardExists = FALSE;
}
if (DevExt->MouseExists) {
MappedIrqMouse = HalGetInterruptVector(Internal,
0,
0,
MOUSE_IRQ,
&DirqlMouse,
&Affinity);
Status = IoCreateDevice(DriverObject,
sizeof(FDO_DEVICE_EXTENSION),
&MouseName,
FILE_DEVICE_8042_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Fdo);
if (NT_SUCCESS(Status))
{
AddRegistryEntry(L"PointerPort", &MouseName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
FdoDevExt = Fdo->DeviceExtension;
RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
FdoDevExt->PortDevExt = DevExt;
FdoDevExt->Type = Mouse;
FdoDevExt->DeviceObject = Fdo;
Fdo->Flags |= DO_BUFFERED_IO;
DevExt->MouseObject = Fdo;
DevExt->MouseBuffer = ExAllocatePoolWithTag(
NonPagedPool,
DevExt->MouseAttributes.InputDataQueueLength *
sizeof(MOUSE_INPUT_DATA),
TAG_I8042);
if (!DevExt->MouseBuffer) {
ExFreePoolWithTag(DevExt->KeyboardBuffer, TAG_I8042);
DPRINT1("No memory for mouse buffer\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
}
else
DevExt->MouseExists = FALSE;
}
if (DirqlKeyboard > DirqlMouse)
DirqlMax = DirqlKeyboard;
else
DirqlMax = DirqlMouse;
if (DevExt->KeyboardExists) {
Status = IoConnectInterrupt(&DevExt->KeyboardInterruptObject,
I8042InterruptServiceKbd,
(PVOID)DevExt,
&DevExt->SpinLock,
MappedIrqKeyboard,
DirqlKeyboard,
DirqlMax,
LevelSensitive,
FALSE,
Affinity,
FALSE);
DPRINT("Keyboard Irq Status: %x\n", Status);
}
if (DevExt->MouseExists) {
Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
I8042InterruptServiceMouse,
(PVOID)DevExt,
&DevExt->SpinLock,
MappedIrqMouse,
DirqlMouse,
DirqlMax,
LevelSensitive,
FALSE,
Affinity,
FALSE);
DPRINT("Mouse Irq Status: %x\n", Status);
}
if (DirqlKeyboard > DirqlMouse)
DevExt->HighestDIRQLInterrupt = DevExt->KeyboardInterruptObject;
else
DevExt->HighestDIRQLInterrupt = DevExt->MouseInterruptObject;
DPRINT("I8042AddDevice done\n");
return(STATUS_SUCCESS);
}
NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
/*
* FUNCTION: Module entry point
*/
{
DPRINT("I8042 Driver 0.0.1\n");
I8042RegistryPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
I8042RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
I8042RegistryPath.MaximumLength,
TAG_I8042);
if (I8042RegistryPath.Buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyUnicodeString(&I8042RegistryPath, RegistryPath);
RtlAppendUnicodeToString(&I8042RegistryPath, L"\\Parameters");
I8042RegistryPath.Buffer[I8042RegistryPath.Length / sizeof(WCHAR)] = 0;
DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
I8042InternalDeviceControl;
DriverObject->DriverStartIo = I8042StartIo;
DriverObject->DriverExtension->AddDevice = I8042AddDevice;
return(STATUS_SUCCESS);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?