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 + -
显示快捷键?