--- /dev/null
--- /dev/null
++Intel 8042 port driver
++
++This directory contains a driver for Intels 8042 and compatible controllers.
++It is based on the information in the DDK documentation on MSDN. It is intended
++to be compatible with keyboard and mouse drivers written for Windows. It is
++not based on the i8042prt example driver that's included with the DDK.
++
++The directory contains these files:
++
++i8042prt.c: Main controller functionality, things shared by keyboards and mice
++
++keyboard.c: keyboard functionality: detection, interrupt handling
++
++mouse.c: mouse functionality: detection, interrupt handling, packet parsing for
++ standard ps2 and microsoft mice
++
++ps2pp.c: logitech ps2++ mouse packat parsing (basic)
++
++registry.c: registry reading
++
++makefile, i8042prt.rc: obvious
++
++
++Some parts of the driver make little sense. This is because it implements
++an interface that has evolved over a long time, and because the ps/2
++'standard' is really awful.
++
++Things to add:
++
++- Better AT (before ps2) keyboard handling
++- SiS keyboard controller detection
++- Mouse identification
++- General robustness: reset mouse if things go wrong
++- Handling all registry settings
++- ACPI
++- Make it work more like a WDM driver
++
++Things not to add:
++
++- Other mouse protocols, touchpad handling etc. : Write a filter driver instead
++- Keyboard lights handling: Should be in win32k
++- Keyboard scancode translation: Should be in win32k
++
++Things requiring work elsewhere:
++
++- Debugger interface (TAB + key):
++ Currently this interface wants translated keycodes, which are not
++ implemented by this driver. As it just uses a giant switch with
++ hardcoded cases, this should not be hard to fix.
++
++- Class drivers:
++ I wrote a keyboard class driver, which does keycode translations. It
++ should not do this, win32k should get untranslated keycodes and do
++ the translation itself.
++
++ I changed the mouse class driver (mouclass) to work like Microsofts mouclass.
++ Unfortunately this means that the original psaux driver doesn't work
++ anymore (the same holds for the other mice drivers, probably).
++
++ The keyboard class driver passes on ioctls from win32k, so it can change
++ keyboard settings. As far as I could see, the mouse class driver does not
++ do this yet.
++
++ The class drivers should be able to handle reads for more than one packet
++ at a time (kbdclass should, mouclass does not). Win32k should send such
++ requests.
++
++
++I put a lot of work in making it work like Microsofts driver does, so third party drivers can work. Please keep it that way.
++
++
++Links:
++
++Here's a link describing most of the registry settings:
++
++http://www.microsoft.com/resources/documentation/Windows/2000/server/reskit/en-us/Default.asp?url=/resources/documentation/Windows/2000/server/reskit/en-us/regentry/31493.asp
++
++PS/2 protocol documentation:
++
++http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html
++
++It also contains a link to a description of the ps2++ protocol, which has
++since disappeared. Archive.org still has it.
--- /dev/null
--- /dev/null
++/*
++ * COPYRIGHT: See COPYING in the top level directory
++ * PROJECT: ReactOS kernel
++ * FILE: drivers/input/i8042prt/i8042prt.c
++ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
++ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
++ * Jason Filby (jasonfilby@yahoo.com)
++ * Tinus
++ */
++
++/* INCLUDES ****************************************************************/
++
++#define NDEBUG
++#include <debug.h>
++
++#include "i8042prt.h"
++
++/* GLOBALS *******************************************************************/
++
++/*
++ * Driver data
++ */
++#define I8042_TIMEOUT 500000
++
++#define I8042_MAX_COMMAND_LENGTH 16
++#define I8042_MAX_UPWARDS_STACK 5
++
++UNICODE_STRING I8042RegistryPath;
++
++/* FUNCTIONS *****************************************************************/
++
++/*
++ * FUNCTION: Write data to a port, waiting first for it to become ready
++ */
++BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data)
++{
++ ULONG ResendIterations = DevExt->Settings.PollingIterations;
++
++ while ((KBD_IBF & READ_PORT_UCHAR(I8042_CTRL_PORT)) &&
++ (ResendIterations--))
++ {
++ KeStallExecutionProcessor(50);
++ }
++
++ if (ResendIterations) {
++ WRITE_PORT_UCHAR(addr,data);
++ DPRINT("Sent %x to %x\n", data, addr);
++ return TRUE;
++ }
++ return FALSE;
++}
++
++#if 0 /* function is not needed */
++/*
++ * FUNCTION: Write data to a port, without waiting first
++ */
++static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, UCHAR data)
++{
++ WRITE_PORT_UCHAR((PUCHAR)addr,data);
++ DPRINT("Sent %x to %x\n", data, addr);
++ return TRUE;
++}
++#endif
++
++/*
++ * FUNCTION: Read data from port 0x60
++ */
++NTSTATUS I8042ReadData(UCHAR *Data)
++{
++ UCHAR Status;
++ Status=READ_PORT_UCHAR(I8042_CTRL_PORT);
++
++ // If data is available
++ if ((Status & KBD_OBF)) {
++ Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
++ DPRINT("Read: %x (status: %x)\n", Data[0], Status);
++
++ // If the data is valid (not timeout, not parity error)
++ if (0 == (Status & KBD_PERR))
++ return STATUS_SUCCESS;
++ }
++ return STATUS_UNSUCCESSFUL;
++}
++
++NTSTATUS I8042ReadStatus(UCHAR *Status)
++{
++ Status[0]=READ_PORT_UCHAR(I8042_CTRL_PORT);
++ return STATUS_SUCCESS;
++}
++
++/*
++ * FUNCTION: Read data from port 0x60
++ */
++NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data)
++{
++ ULONG Counter = DevExt->Settings.PollingIterations;
++ NTSTATUS Status;
++
++ while (Counter--) {
++ Status = I8042ReadData(Data);
++
++ if (STATUS_SUCCESS == Status)
++ return Status;
++
++ KeStallExecutionProcessor(50);
++ }
++ // Timed out
++ return STATUS_IO_TIMEOUT;
++}
++
++VOID I8042Flush()
++{
++ UCHAR Ignore;
++
++ while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
++ DPRINT("Data flushed\n"); /* drop */
++ }
++}
++
++VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
++ UCHAR Value,
++ UCHAR SelectCmd)
++{
++ if (SelectCmd)
++ if (!I8042Write(DevExt, I8042_CTRL_PORT, SelectCmd))
++ return;
++
++ I8042Write(DevExt, I8042_DATA_PORT, Value);
++}
++
++/*
++ * These functions are callbacks for filter driver custom
++ * initialization routines.
++ */
++NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
++ UCHAR Port,
++ UCHAR Value,
++ BOOLEAN WaitForAck)
++{
++ NTSTATUS Status;
++ UCHAR Ack;
++ ULONG ResendIterations = DevExt->Settings.ResendIterations + 1;
++
++ do {
++ if (Port)
++ if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
++ {
++ DPRINT1("Failed to write Port\n");
++ return STATUS_IO_TIMEOUT;
++ }
++
++ if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
++ {
++ DPRINT1("Failed to write Value\n");
++ return STATUS_IO_TIMEOUT;
++ }
++
++ if (WaitForAck) {
++ Status = I8042ReadDataWait(DevExt, &Ack);
++ if (!NT_SUCCESS(Status))
++ {
++ DPRINT1("Failed to read Ack\n");
++ return Status;
++ }
++ if (Ack == KBD_ACK)
++ return STATUS_SUCCESS;
++ if (Ack != KBD_RESEND)
++ {
++ DPRINT1("Unexpected Ack 0x%x\n", Ack);
++ return STATUS_UNEXPECTED_IO_ERROR;
++ }
++ } else {
++ return STATUS_SUCCESS;
++ }
++ DPRINT("Reiterating\n");
++ ResendIterations--;
++ } while (ResendIterations);
++ return STATUS_IO_TIMEOUT;
++}
++
++/*
++ * This one reads a value from the port; You don't have to specify
++ * which one, it'll always be from the one you talked to, so one function
++ * is enough this time. Note how MSDN specifies the
++ * WaitForAck parameter to be ignored.
++ */
++static NTSTATUS STDCALL I8042SynchReadPort(PVOID Context,
++ PUCHAR Value,
++ BOOLEAN WaitForAck)
++{
++ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)Context;
++
++ return I8042ReadDataWait(DevExt, Value);
++}
++
++/* Write the current byte of the packet. Returns FALSE in case
++ * of problems.
++ */
++static BOOLEAN STDCALL I8042PacketWrite(PDEVICE_EXTENSION DevExt)
++{
++ UCHAR Port = DevExt->PacketPort;
++
++ if (Port) {
++ if (!I8042Write(DevExt,
++ I8042_CTRL_PORT,
++ Port)) {
++ /* something is really wrong! */
++ DPRINT1("Failed to send packet byte!\n");
++ return FALSE;
++ }
++ }
++
++ return I8042Write(DevExt,
++ I8042_DATA_PORT,
++ DevExt->Packet.Bytes[DevExt->Packet.CurrentByte]);
++}
++
++
++/*
++ * This function starts a packet. It must be called with the
++ * correct DIRQL.
++ */
++NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
++ PDEVICE_OBJECT Device,
++ PUCHAR Bytes,
++ ULONG ByteCount,
++ PIRP Irp)
++{
++ KIRQL Irql;
++ NTSTATUS Status;
++ PFDO_DEVICE_EXTENSION FdoDevExt = Device->DeviceExtension;
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++
++ DevExt->CurrentIrp = Irp;
++ DevExt->CurrentIrpDevice = Device;
++
++ if (Idle != DevExt->Packet.State) {
++ Status = STATUS_DEVICE_BUSY;
++ goto startpacketdone;
++ }
++
++ DevExt->Packet.Bytes = Bytes;
++ DevExt->Packet.CurrentByte = 0;
++ DevExt->Packet.ByteCount = ByteCount;
++ DevExt->Packet.State = SendingBytes;
++ DevExt->PacketResult = Status = STATUS_PENDING;
++
++ if (Mouse == FdoDevExt->Type)
++ DevExt->PacketPort = 0xD4;
++ else
++ DevExt->PacketPort = 0;
++
++ if (!I8042PacketWrite(DevExt)) {
++ Status = STATUS_IO_TIMEOUT;
++ DevExt->Packet.State = Idle;
++ DevExt->PacketResult = STATUS_ABANDONED;
++ goto startpacketdone;
++ }
++
++ DevExt->Packet.CurrentByte++;
++
++startpacketdone:
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++
++ if (STATUS_PENDING != Status) {
++ DevExt->CurrentIrp = NULL;
++ DevExt->CurrentIrpDevice = NULL;
++ Irp->IoStatus.Status = Status;
++ IoCompleteRequest(Irp, IO_NO_INCREMENT);
++ }
++ return Status;
++}
++
++BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
++ UCHAR Output)
++{
++ if (Idle == DevExt->Packet.State)
++ return FALSE;
++
++ switch (Output) {
++ case KBD_RESEND:
++ DevExt->PacketResends++;
++ if (DevExt->PacketResends > DevExt->Settings.ResendIterations) {
++ DevExt->Packet.State = Idle;
++ DevExt->PacketComplete = TRUE;
++ DevExt->PacketResult = STATUS_IO_TIMEOUT;
++ DevExt->PacketResends = 0;
++ return TRUE;
++ }
++ DevExt->Packet.CurrentByte--;
++ break;
++
++ case KBD_NACK:
++ DevExt->Packet.State = Idle;
++ DevExt->PacketComplete = TRUE;
++ DevExt->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
++ DevExt->PacketResends = 0;
++ return TRUE;
++
++ default:
++ DevExt->PacketResends = 0;
++ }
++
++ if (DevExt->Packet.CurrentByte >= DevExt->Packet.ByteCount) {
++ DevExt->Packet.State = Idle;
++ DevExt->PacketComplete = TRUE;
++ DevExt->PacketResult = STATUS_SUCCESS;
++ return TRUE;
++ }
++
++ if (!I8042PacketWrite(DevExt)) {
++ DevExt->Packet.State = Idle;
++ DevExt->PacketComplete = TRUE;
++ DevExt->PacketResult = STATUS_IO_TIMEOUT;
++ return TRUE;
++ }
++ DevExt->Packet.CurrentByte++;
++
++ return TRUE;
++}
++
++VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
++{
++ BOOLEAN FinishIrp = FALSE;
++ NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
++ KIRQL Irql;
++
++ /* If the interrupt happens before this is setup, the key
++ * was already in the buffer. Too bad! */
++ if (!DevExt->HighestDIRQLInterrupt)
++ return;
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++
++ if (Idle == DevExt->Packet.State &&
++ DevExt->PacketComplete) {
++ FinishIrp = TRUE;
++ Result = DevExt->PacketResult;
++ DevExt->PacketComplete = FALSE;
++ }
++
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt,
++ Irql);
++
++ if (!FinishIrp)
++ return;
++
++ if (DevExt->CurrentIrp) {
++ DevExt->CurrentIrp->IoStatus.Status = Result;
++ IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
++ IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
++ DevExt->CurrentIrp = NULL;
++ DevExt->CurrentIrpDevice = NULL;
++ }
++}
++
++VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
++ PVOID Context)
++{
++ KEVENT Event;
++ IO_STATUS_BLOCK IoStatus;
++ NTSTATUS Status;
++ PDEVICE_EXTENSION DevExt;
++ PFDO_DEVICE_EXTENSION FdoDevExt;
++ PIRP NewIrp;
++ PI8042_HOOK_WORKITEM WorkItemData = (PI8042_HOOK_WORKITEM)Context;
++
++ ULONG IoControlCode;
++ PVOID InputBuffer;
++ ULONG InputBufferLength;
++ BOOLEAN IsKbd;
++
++ DPRINT("HookWorkItem\n");
++
++ FdoDevExt = (PFDO_DEVICE_EXTENSION)
++ DeviceObject->DeviceExtension;
++
++ DevExt = FdoDevExt->PortDevExt;
++
++ if (WorkItemData->Target == DevExt->KeyboardData.ClassDeviceObject) {
++ IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
++ InputBuffer = &DevExt->KeyboardHook;
++ InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
++ IsKbd = TRUE;
++ DPRINT ("is for keyboard.\n");
++ } else if (WorkItemData->Target == DevExt->MouseData.ClassDeviceObject){
++ IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
++ InputBuffer = &DevExt->MouseHook;
++ InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
++ IsKbd = FALSE;
++ DPRINT ("is for mouse.\n");
++ } else {
++ DPRINT1("I8042SendHookWorkItem: Can't find DeviceObject\n");
++ WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
++ goto hookworkitemdone;
++ }
++
++ KeInitializeEvent(&Event, NotificationEvent, FALSE);
++
++ NewIrp = IoBuildDeviceIoControlRequest(
++ IoControlCode,
++ WorkItemData->Target,
++ InputBuffer,
++ InputBufferLength,
++ NULL,
++ 0,
++ TRUE,
++ &Event,
++ &IoStatus);
++
++ if (!NewIrp) {
++ DPRINT("IOCTL_INTERNAL_(device)_CONNECT: "
++ "Can't allocate IRP\n");
++ WorkItemData->Irp->IoStatus.Status =
++ STATUS_INSUFFICIENT_RESOURCES;
++ goto hookworkitemdone;
++ }
++
++#if 0
++ Status = IoCallDriver(
++ WorkItemData->Target,
++ NewIrp);
++
++ if (STATUS_PENDING == Status)
++ KeWaitForSingleObject(&Event,
++ Executive,
++ KernelMode,
++ FALSE,
++ NULL);
++#endif
++
++ if (IsKbd) {
++ /* Call the hooked initialization if it exists */
++ if (DevExt->KeyboardHook.InitializationRoutine) {
++ Status = DevExt->KeyboardHook.InitializationRoutine(
++ DevExt->KeyboardHook.Context,
++ DevExt,
++ I8042SynchReadPort,
++ I8042SynchWritePortKbd,
++ FALSE);
++ if (!NT_SUCCESS(Status)) {
++ WorkItemData->Irp->IoStatus.Status = Status;
++ goto hookworkitemdone;
++ }
++ }
++ /* TODO: Now would be the right time to enable the interrupt */
++
++ DevExt->KeyboardClaimed = TRUE;
++ } else {
++ /* Mouse doesn't have this, but we need to send a
++ * reset to start the detection.
++ */
++ KIRQL Irql;
++
++ Irql = KeAcquireInterruptSpinLock(
++ DevExt->HighestDIRQLInterrupt);
++
++ I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
++ I8042Write(DevExt, I8042_DATA_PORT, 0xFF);
++
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++ }
++
++ 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);
++ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
++ 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);
++ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
++ }
++ 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);
++ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
++ }
++ 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);
++}
--- /dev/null
--- /dev/null
++#ifndef _I8042DRV_H
++#define _I8042DRV_H
++
++#include <ntddk.h>
++#include <kbdmou.h>
++#include <ntdd8042.h>
++
++#ifdef _MSC_VER
++ #define STDCALL
++ #define DDKAPI
++#endif
++
++#define KEYBOARD_IRQ 1
++#define MOUSE_IRQ 12
++#define KBD_BUFFER_SIZE 32
++
++#define WHEEL_DELTA 120
++
++/*-----------------------------------------------------
++ * DeviceExtension
++ * --------------------------------------------------*/
++typedef struct _COMMAND_CONTEXT
++{
++ int NumInput;
++ int CurInput;
++ UCHAR * Input;
++ int NumOutput;
++ int CurOutput;
++ UCHAR * Output;
++ NTSTATUS Status;
++
++ BOOLEAN GotAck;
++ KEVENT Event;
++
++ PVOID DevExt;
++} COMMAND_CONTEXT, *PCOMMAND_CONTEXT;
++
++typedef enum _MOUSE_TIMEOUT_STATE
++{
++ NoChange,
++ TimeoutStart,
++ TimeoutCancel
++} MOUSE_TIMEOUT_STATE, *PMOUSE_TIMEOUT_STATE;
++
++/* TODO: part of this should be in the _ATTRIBUTES structs instead */
++typedef struct _I8042_SETTINGS
++{
++ ULONG Headless; /* done */
++ ULONG CrashScroll;
++ ULONG CrashSysRq; /* done */
++ ULONG ReportResetErrors;
++ ULONG PollStatusIterations; /* done */
++ ULONG ResendIterations; /* done */
++ ULONG PollingIterations;
++ ULONG PollingIterationsMaximum;
++ ULONG OverrideKeyboardType;
++ ULONG OverrideKeyboardSubtype;
++ ULONG MouseResendStallTime;
++ ULONG MouseSynchIn100ns; /* done */
++ ULONG MouseResolution; /* done */
++ ULONG NumberOfButtons;
++ ULONG EnableWheelDetection;
++} I8042_SETTINGS, *PI8042_SETTINGS;
++
++typedef enum _I8042_MOUSE_TYPE
++{
++ GenericPS2,
++ Intellimouse,
++ IntellimouseExplorer,
++ Ps2pp
++} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
++
++typedef enum _I8042_DEVICE_TYPE
++{
++ Keyboard,
++ Mouse
++} I8042_DEVICE_TYPE, *PI8042_DEVICE_TYPE;
++
++typedef struct _I8042_DEVICE
++{
++ LIST_ENTRY ListEntry;
++ PDEVICE_OBJECT Pdo;
++} I8042_DEVICE, *PI8042_DEVICE;
++
++typedef struct _DEVICE_EXTENSION
++{
++ PDEVICE_OBJECT KeyboardObject;
++ PDEVICE_OBJECT MouseObject;
++
++ CONNECT_DATA KeyboardData;
++ CONNECT_DATA MouseData;
++
++ BOOLEAN KeyboardExists;
++ BOOLEAN KeyboardIsAT;
++ BOOLEAN MouseExists;
++
++ BOOLEAN KeyboardClaimed;
++ BOOLEAN MouseClaimed;
++
++ ULONG BusNumber;
++ LIST_ENTRY BusDevices;
++
++ INTERNAL_I8042_START_INFORMATION KeyboardStartInformation;
++ INTERNAL_I8042_START_INFORMATION MouseStartInformation;
++
++ INTERNAL_I8042_HOOK_KEYBOARD KeyboardHook;
++ INTERNAL_I8042_HOOK_MOUSE MouseHook;
++
++ PKINTERRUPT KeyboardInterruptObject;
++ PKINTERRUPT MouseInterruptObject;
++ PKINTERRUPT HighestDIRQLInterrupt;
++ KSPIN_LOCK SpinLock;
++ KDPC DpcKbd;
++ KDPC DpcMouse;
++
++ KTIMER TimerMouseTimeout;
++ KDPC DpcMouseTimeout;
++ MOUSE_TIMEOUT_STATE MouseTimeoutState;
++ BOOLEAN MouseTimeoutActive;
++
++ KEYBOARD_ATTRIBUTES KeyboardAttributes;
++ KEYBOARD_INDICATOR_PARAMETERS KeyboardIndicators;
++ KEYBOARD_TYPEMATIC_PARAMETERS KeyboardTypematic;
++
++ BOOLEAN WantAck;
++ BOOLEAN WantOutput;
++ BOOLEAN SignalEvent;
++
++ KEYBOARD_SCAN_STATE KeyboardScanState;
++ BOOLEAN KeyComplete;
++ KEYBOARD_INPUT_DATA *KeyboardBuffer;
++ ULONG KeysInBuffer;
++
++ MOUSE_ATTRIBUTES MouseAttributes;
++
++ MOUSE_STATE MouseState;
++ BOOLEAN MouseComplete;
++ MOUSE_RESET_SUBSTATE MouseResetState;
++ MOUSE_INPUT_DATA *MouseBuffer;
++ ULONG MouseInBuffer;
++ USHORT MouseButtonState;
++ ULARGE_INTEGER MousePacketStartTime;
++
++ UCHAR MouseLogiBuffer[3];
++ UCHAR MouseLogitechID;
++ I8042_MOUSE_TYPE MouseType;
++
++ OUTPUT_PACKET Packet;
++ ULONG PacketResends;
++ BOOLEAN PacketComplete;
++ NTSTATUS PacketResult;
++ UCHAR PacketBuffer[16];
++ UCHAR PacketPort;
++
++ PIRP CurrentIrp;
++ PDEVICE_OBJECT CurrentIrpDevice;
++
++ /* registry config values */
++ I8042_SETTINGS Settings;
++
++ /* Debugger stuff */
++ BOOLEAN TabPressed;
++ ULONG DebugKey;
++ PIO_WORKITEM DebugWorkItem;
++} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
++
++typedef struct _FDO_DEVICE_EXTENSION
++{
++ PDEVICE_EXTENSION PortDevExt;
++ I8042_DEVICE_TYPE Type;
++ PDEVICE_OBJECT DeviceObject;
++
++ LIST_ENTRY BusDevices;
++} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
++
++typedef struct _I8042_HOOK_WORKITEM
++{
++ PIO_WORKITEM WorkItem;
++ PDEVICE_OBJECT Target;
++ PIRP Irp;
++} I8042_HOOK_WORKITEM, *PI8042_HOOK_WORKITEM;
++
++/*
++ * Some defines
++ */
++#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
++#define TAG_I8042 TAG('8', '0', '4', '2')
++
++#define KBD_WRAP_MASK 0x1F
++
++#define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
++#define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
++
++
++/*
++ * Keyboard controller ports
++ */
++
++#define I8042_DATA_PORT ((PUCHAR)0x60)
++#define I8042_CTRL_PORT ((PUCHAR)0x64)
++
++
++/*
++ * Controller commands
++ */
++
++#define KBD_READ_MODE 0x20
++#define KBD_WRITE_MODE 0x60
++#define KBD_SELF_TEST 0xAA
++#define KBD_LINE_TEST 0xAB
++#define KBD_CTRL_ENABLE 0xAE
++
++#define MOUSE_LINE_TEST 0xA9
++#define MOUSE_CTRL_ENABLE 0xA8
++
++#define KBD_READ_OUTPUT_PORT 0xD0
++#define KBD_WRITE_OUTPUT_PORT 0xD1
++
++/*
++ * Keyboard commands
++ */
++
++#define KBD_SET_LEDS 0xED
++#define KBD_GET_ID 0xF2
++#define KBD_ENABLE 0xF4
++#define KBD_DISABLE 0xF5
++#define KBD_RESET 0xFF
++
++
++/*
++ * Keyboard responces
++ */
++
++#define KBD_BATCC 0xAA
++#define KBD_ACK 0xFA
++#define KBD_NACK 0xFC
++#define KBD_RESEND 0xFE
++
++/*
++ * Controller status register bits
++ */
++
++#define KBD_OBF 0x01
++#define KBD_IBF 0x02
++#define KBD_AUX 0x10
++#define KBD_GTO 0x40
++#define KBD_PERR 0x80
++
++/*
++ * Controller command byte bits
++ */
++#define CCB_KBD_INT_ENAB 0x01
++#define CCB_MOUSE_INT_ENAB 0x02
++#define CCB_SYSTEM_FLAG 0x04
++#define CCB_IGN_KEY_LOCK 0x08
++#define CCB_KBD_DISAB 0x10
++#define CCB_MOUSE_DISAB 0x20
++#define CCB_TRANSLATE 0x40
++
++
++/*
++ * LED bits
++ */
++
++#define KBD_LED_SCROLL 0x01
++#define KBD_LED_NUM 0x02
++#define KBD_LED_CAPS 0x04
++
++/*
++ * Mouse responses
++ */
++#define MOUSE_ACK 0xFA
++#define MOUSE_ERROR 0xFC
++#define MOUSE_NACK 0xFE
++
++/* i8042prt.c */
++extern UNICODE_STRING I8042RegistryPath;
++
++NTSTATUS I8042ReadData(UCHAR *Data);
++
++NTSTATUS I8042ReadStatus(UCHAR *Status);
++
++NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data);
++
++VOID I8042Flush();
++
++VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
++ UCHAR Value,
++ UCHAR SelectCmd);
++
++NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
++ UCHAR Port,
++ UCHAR Value,
++ BOOLEAN WaitForAck);
++
++NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
++ PDEVICE_OBJECT Device,
++ PUCHAR Bytes,
++ ULONG ByteCount,
++ PIRP Irp);
++
++BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
++ UCHAR Output);
++
++VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt);
++
++VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
++ PVOID Context);
++
++BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data);
++
++NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
++ PUNICODE_STRING RegistryPath);
++
++/* keyboard.c */
++VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
++ UCHAR Value);
++
++NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
++ UCHAR Value,
++ BOOLEAN WaitForAck);
++
++BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
++ VOID * Context);
++
++VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
++ PVOID DeferredContext,
++ PVOID SystemArgument1,
++ PVOID SystemArgument2);
++
++BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp);
++
++NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject,
++ PIRP Irp);
++
++BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt);
++
++BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt);
++
++BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt);
++
++/* registry.c */
++VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
++ PDEVICE_EXTENSION DevExt);
++
++/* mouse.c */
++VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
++ PVOID DeferredContext,
++ PVOID SystemArgument1,
++ PVOID SystemArgument2);
++
++VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
++ PVOID DeferredContext,
++ PVOID SystemArgument1,
++ PVOID SystemArgument2);
++
++BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
++ VOID *Context);
++
++NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject,
++ PIRP Irp);
++
++VOID STDCALL I8042QueueMousePacket(PVOID Context);
++
++VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
++ USHORT Mask);
++
++VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
++ UCHAR Output);
++
++BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt);
++BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt);
++BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt);
++
++/* ps2pp.c */
++VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input);
++
++#endif // _KEYBOARD_H_
--- /dev/null
--- /dev/null
++<module name="i8042prt" type="kernelmodedriver" installbase="system32/drivers" installname="i8042prt.sys">
++ <bootstrap base="reactos" />
++ <include base="i8042prt">.</include>
++ <define name="__USE_W32API" />
++ <define name="__REACTOS__" />
++ <library>ntoskrnl</library>
++ <library>hal</library>
++ <file>i8042prt.c</file>
++ <file>keyboard.c</file>
++ <file>mouse.c</file>
++ <file>ps2pp.c</file>
++ <file>registry.c</file>
++ <file>i8042prt.rc</file>
++</module>
--- /dev/null
--- /dev/null
++#define REACTOS_VERSION_DLL
++#define REACTOS_STR_FILE_DESCRIPTION "I8042 Port Device Driver\0"
++#define REACTOS_STR_INTERNAL_NAME "i8042prt\0"
++#define REACTOS_STR_ORIGINAL_FILENAME "i8042prt.sys\0"
++#include <reactos/version.rc>
--- /dev/null
--- /dev/null
++/*
++ * COPYRIGHT: See COPYING in the top level directory
++ * PROJECT: ReactOS kernel
++ * FILE: drivers/input/i8042prt/keyboard.c
++ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
++ * keyboard specifics
++ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
++ * Jason Filby (jasonfilby@yahoo.com)
++ * Tinus
++ */
++
++/* INCLUDES ****************************************************************/
++
++#include "i8042prt.h"
++
++#define NDEBUG
++#include <debug.h>
++
++/* GLOBALS *******************************************************************/
++
++static UCHAR TypematicTable[] = {
++ 0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /* 0-9 */
++ 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
++ 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };
++
++typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
++ USHORT NumberOfIndicatorKeys;
++ INDICATOR_LIST IndicatorList[3];
++} LOCAL_KEYBOARD_INDICATOR_TRANSLATION, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION;
++
++static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, {
++ {0x3A, KEYBOARD_CAPS_LOCK_ON},
++ {0x45, KEYBOARD_NUM_LOCK_ON},
++ {0x46, KEYBOARD_SCROLL_LOCK_ON}}};
++
++static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
++ PVOID Context);
++
++/* FUNCTIONS *****************************************************************/
++
++/*
++ * These functions are callbacks for filter driver custom interrupt
++ * service routines.
++ */
++VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
++ UCHAR Value)
++{
++ I8042IsrWritePort(Context, Value, 0);
++}
++
++static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
++{
++ PDEVICE_OBJECT DeviceObject = Context;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ DevExt->KeyComplete = TRUE;
++ DevExt->KeysInBuffer++;
++ if (DevExt->KeysInBuffer >
++ DevExt->KeyboardAttributes.InputDataQueueLength) {
++ DPRINT1("Keyboard buffer overflow\n");
++ DevExt->KeysInBuffer--;
++ }
++
++ DPRINT("Irq completes key\n");
++ KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
++}
++
++/*
++ * These functions are callbacks for filter driver custom
++ * initialization routines.
++ */
++NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
++ UCHAR Value,
++ BOOLEAN WaitForAck)
++{
++ return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
++ 0,
++ Value,
++ WaitForAck);
++}
++
++BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
++ VOID * Context)
++{
++ UCHAR Output;
++ UCHAR PortStatus;
++ NTSTATUS Status;
++ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
++ BOOLEAN HookContinue = FALSE, HookReturn;
++ ULONG Iterations = 0;
++
++ KEYBOARD_INPUT_DATA *InputData =
++ DevExt->KeyboardBuffer + DevExt->KeysInBuffer;
++
++ do {
++ Status = I8042ReadStatus(&PortStatus);
++ DPRINT("PortStatus: %x\n", PortStatus);
++ Status = I8042ReadData(&Output);
++ Iterations++;
++ if (STATUS_SUCCESS == Status)
++ break;
++ KeStallExecutionProcessor(1);
++ } while (Iterations < DevExt->Settings.PollStatusIterations);
++
++ if (STATUS_SUCCESS != Status) {
++ DPRINT("Spurious I8042 interrupt\n");
++ return FALSE;
++ }
++
++ DPRINT("Got: %x\n", Output);
++
++ if (DevExt->KeyboardHook.IsrRoutine) {
++ HookReturn = DevExt->KeyboardHook.IsrRoutine(
++ DevExt->KeyboardHook.Context,
++ InputData,
++ &DevExt->Packet,
++ PortStatus,
++ &Output,
++ &HookContinue,
++ &DevExt->KeyboardScanState);
++
++ if (!HookContinue)
++ return HookReturn;
++ }
++
++ if (I8042PacketIsr(DevExt, Output)) {
++ if (DevExt->PacketComplete) {
++ DPRINT("Packet complete\n");
++ KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
++ }
++ DPRINT("Irq eaten by packet\n");
++ return TRUE;
++ }
++
++ DPRINT("Irq is keyboard input\n");
++
++ if (Normal == DevExt->KeyboardScanState) {
++ switch (Output) {
++ case 0xe0:
++ DevExt->KeyboardScanState = GotE0;
++ return TRUE;
++ case 0xe1:
++ DevExt->KeyboardScanState = GotE1;
++ return TRUE;
++ default:
++ ;/* continue */
++ }
++ }
++
++ InputData->Flags = 0;
++
++ switch (DevExt->KeyboardScanState) {
++ case GotE0:
++ InputData->Flags |= KEY_E0;
++ break;
++ case GotE1:
++ InputData->Flags |= KEY_E1;
++ break;
++ default:
++ ;
++ }
++ DevExt->KeyboardScanState = Normal;
++
++ if (Output & 0x80)
++ InputData->Flags |= KEY_BREAK;
++ else
++ InputData->Flags |= KEY_MAKE;
++
++ InputData->MakeCode = Output & 0x7f;
++
++ I8042QueueKeyboardPacket(DevExt->KeyboardObject);
++
++ return TRUE;
++}
++
++VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
++ PVOID DeferredContext,
++ PVOID SystemArgument1,
++ PVOID SystemArgument2)
++{
++ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
++ ULONG KeysTransferred = 0;
++ ULONG KeysInBufferCopy;
++ KIRQL Irql;
++
++ I8042PacketDpc(DevExt);
++
++ if (!DevExt->KeyComplete)
++ return;
++
++ /* We got the interrupt as it was being enabled, too bad */
++ if (!DevExt->HighestDIRQLInterrupt)
++ return;
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++
++ DevExt->KeyComplete = FALSE;
++ KeysInBufferCopy = DevExt->KeysInBuffer;
++
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++
++ /* Test for TAB (debugging) */
++ if (DevExt->Settings.CrashSysRq) {
++ PKEYBOARD_INPUT_DATA InputData = DevExt->KeyboardBuffer +
++ KeysInBufferCopy - 1;
++ if (InputData->MakeCode == 0x0F) {
++ DPRINT("Tab!\n");
++ DevExt->TabPressed = !(InputData->Flags & KEY_BREAK);
++ } else if (DevExt->TabPressed) {
++ DPRINT ("Queueing work item %x\n", DevExt->DebugWorkItem);
++ DevExt->DebugKey = InputData->MakeCode;
++ DevExt->TabPressed = FALSE;
++
++ IoQueueWorkItem(DevExt->DebugWorkItem,
++ &(I8042DebugWorkItem),
++ DelayedWorkQueue,
++ DevExt);
++ }
++ }
++
++ DPRINT ("Send a key\n");
++
++ if (!DevExt->KeyboardData.ClassService)
++ return;
++
++ ((PSERVICE_CALLBACK_ROUTINE) DevExt->KeyboardData.ClassService)(
++ DevExt->KeyboardData.ClassDeviceObject,
++ DevExt->KeyboardBuffer,
++ DevExt->KeyboardBuffer + KeysInBufferCopy,
++ &KeysTransferred);
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++ DevExt->KeysInBuffer -= KeysTransferred;
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++}
++
++/* You have to send the rate/delay in a somewhat awkward format */
++static UCHAR I8042GetTypematicByte(USHORT Rate, USHORT Delay)
++{
++ UCHAR ret;
++
++ if (Rate < 3) {
++ ret = 0x0;
++ } else if (Rate > 26) {
++ ret = 0x1F;
++ } else {
++ ret = TypematicTable[Rate];
++ }
++
++ if (Delay < 375) {
++ ;
++ } else if (Delay < 625) {
++ ret |= 0x20;
++ } else if (Delay < 875) {
++ ret |= 0x40;
++ } else {
++ ret |= 0x60;
++ }
++ return ret;
++}
++/*
++ * Process the keyboard internal device requests
++ * returns FALSE if it doesn't understand the
++ * call so someone else can handle it.
++ */
++BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
++{
++ PIO_STACK_LOCATION Stk;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ Stk = IoGetCurrentIrpStackLocation(Irp);
++
++ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
++ case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
++ I8042StartPacket(
++ DevExt,
++ DeviceObject,
++ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
++ Stk->Parameters.DeviceIoControl.InputBufferLength,
++ Irp);
++ break;
++
++ case IOCTL_KEYBOARD_SET_INDICATORS:
++ DevExt->PacketBuffer[0] = 0xED;
++ DevExt->PacketBuffer[1] = 0;
++ if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
++ DevExt->PacketBuffer[1] |= 0x04;
++
++ if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
++ DevExt->PacketBuffer[1] |= 0x02;
++
++ if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
++ DevExt->PacketBuffer[1] |= 0x01;
++
++ I8042StartPacket(DevExt,
++ DeviceObject,
++ DevExt->PacketBuffer,
++ 2,
++ Irp);
++ break;
++ case IOCTL_KEYBOARD_SET_TYPEMATIC:
++ DevExt->PacketBuffer[0] = 0xF3;
++ DevExt->PacketBuffer[1] = I8042GetTypematicByte(
++ DevExt->KeyboardTypematic.Rate,
++ DevExt->KeyboardTypematic.Delay);
++
++ I8042StartPacket(DevExt,
++ DeviceObject,
++ DevExt->PacketBuffer,
++ 2,
++ Irp);
++ break;
++ default:
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++/*
++ * Runs the keyboard IOCTL_INTERNAL dispatch.
++ * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
++ * so someone else can have a try at it.
++ */
++NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
++{
++ PIO_STACK_LOCATION Stk;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ DPRINT("InternalDeviceControl\n");
++
++ Irp->IoStatus.Information = 0;
++ Stk = IoGetCurrentIrpStackLocation(Irp);
++
++ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
++
++ case IOCTL_INTERNAL_KEYBOARD_CONNECT:
++ DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
++ sizeof(CONNECT_DATA)) {
++ DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
++ goto intcontfailure;
++ }
++
++ if (!DevExt->KeyboardExists) {
++ Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
++ goto intcontfailure;
++ }
++
++ if (DevExt->KeyboardClaimed) {
++ DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
++ "Keyboard is already claimed\n");
++ Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
++ goto intcontfailure;
++ }
++
++ memcpy(&DevExt->KeyboardData,
++ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
++ sizeof(CONNECT_DATA));
++ DevExt->KeyboardHook.IsrWritePort = I8042IsrWritePortKbd;
++ DevExt->KeyboardHook.QueueKeyboardPacket =
++ I8042QueueKeyboardPacket;
++ DevExt->KeyboardHook.CallContext = DevExt;
++
++ {
++ PIO_WORKITEM WorkItem;
++ PI8042_HOOK_WORKITEM WorkItemData;
++
++ WorkItem = IoAllocateWorkItem(DeviceObject);
++ if (!WorkItem) {
++ DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
++ "Can't allocate work item\n");
++ Irp->IoStatus.Status =
++ STATUS_INSUFFICIENT_RESOURCES;
++ goto intcontfailure;
++ }
++
++ WorkItemData = ExAllocatePoolWithTag(
++ NonPagedPool,
++ sizeof(I8042_HOOK_WORKITEM),
++ TAG_I8042);
++ if (!WorkItemData) {
++ DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
++ "Can't allocate work item data\n");
++ Irp->IoStatus.Status =
++ STATUS_INSUFFICIENT_RESOURCES;
++ IoFreeWorkItem(WorkItem);
++ goto intcontfailure;
++ }
++ WorkItemData->WorkItem = WorkItem;
++ WorkItemData->Target =
++ DevExt->KeyboardData.ClassDeviceObject;
++ WorkItemData->Irp = Irp;
++
++ IoMarkIrpPending(Irp);
++ IoQueueWorkItem(WorkItem,
++ I8042SendHookWorkItem,
++ DelayedWorkQueue,
++ WorkItemData);
++
++ Irp->IoStatus.Status = STATUS_PENDING;
++ }
++
++ break;
++ case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
++ DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
++ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
++ goto intcontfailure;
++ }
++ if (!DevExt->KeyboardInterruptObject) {
++ Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
++ goto intcontfailure;
++ }
++
++ IoMarkIrpPending(Irp);
++ IoStartPacket(DeviceObject, Irp, NULL, NULL);
++ Irp->IoStatus.Status = STATUS_PENDING;
++
++ break;
++ case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
++ DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
++ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
++ sizeof(KEYBOARD_ATTRIBUTES)) {
++ DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++ memcpy(Irp->AssociatedIrp.SystemBuffer,
++ &DevExt->KeyboardAttributes,
++ sizeof(KEYBOARD_ATTRIBUTES));
++
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ break;
++ case IOCTL_KEYBOARD_QUERY_INDICATORS:
++ DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
++ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
++ sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
++ DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++ memcpy(Irp->AssociatedIrp.SystemBuffer,
++ &DevExt->KeyboardIndicators,
++ sizeof(KEYBOARD_INDICATOR_PARAMETERS));
++
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ break;
++ case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
++ DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
++ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
++ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
++ DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++ memcpy(Irp->AssociatedIrp.SystemBuffer,
++ &DevExt->KeyboardTypematic,
++ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
++
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ break;
++ case IOCTL_KEYBOARD_SET_INDICATORS:
++ DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
++ sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
++ DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++
++ memcpy(&DevExt->KeyboardIndicators,
++ Irp->AssociatedIrp.SystemBuffer,
++ sizeof(KEYBOARD_INDICATOR_PARAMETERS));
++
++ DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
++
++ IoMarkIrpPending(Irp);
++ IoStartPacket(DeviceObject, Irp, NULL, NULL);
++ Irp->IoStatus.Status = STATUS_PENDING;
++
++ break;
++ case IOCTL_KEYBOARD_SET_TYPEMATIC:
++ DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
++ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
++ DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++
++ memcpy(&DevExt->KeyboardTypematic,
++ Irp->AssociatedIrp.SystemBuffer,
++ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
++
++ IoMarkIrpPending(Irp);
++ IoStartPacket(DeviceObject, Irp, NULL, NULL);
++ Irp->IoStatus.Status = STATUS_PENDING;
++
++ break;
++ case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
++ /* We should check the UnitID, but it's kind of pointless as
++ * all keyboards are supposed to have the same one
++ */
++ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
++ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) {
++ DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
++ "invalid buffer size (expected)\n");
++ /* It's to query the buffer size */
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++ Irp->IoStatus.Information =
++ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
++
++ memcpy(Irp->AssociatedIrp.SystemBuffer,
++ &IndicatorTranslation,
++ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
++
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ break;
++ case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
++ /* Nothing to do here */
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ break;
++ default:
++ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
++ break;
++ }
++
++intcontfailure:
++ return Irp->IoStatus.Status;
++}
++
++/* This is all pretty confusing. There's more than one way to
++ * disable/enable the keyboard. You can send KBD_ENABLE to the
++ * keyboard, and it will start scanning keys. Sending KBD_DISABLE
++ * will disable the key scanning but also reset the parameters to
++ * defaults.
++ *
++ * You can also send 0xAE to the controller for enabling the
++ * keyboard clock line and 0xAD for disabling it. Then it'll
++ * automatically get turned on at the next command. The last
++ * way is by modifying the bit that drives the clock line in the
++ * 'command byte' of the controller. This is almost, but not quite,
++ * the same as the AE/AD thing. The difference can be used to detect
++ * some really old broken keyboard controllers which I hope won't be
++ * necessary.
++ *
++ * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
++ * some kvm switches.
++ */
++
++BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
++{
++ UCHAR Value;
++ NTSTATUS Status;
++
++ DPRINT("Enable keyboard\n");
++
++ 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; // don't disable keyboard
++
++ 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;
++ }
++
++ return TRUE;
++}
++
++static BOOLEAN STDCALL I8042KeyboardDefaultsAndDisable(PDEVICE_EXTENSION DevExt)
++{
++ UCHAR Value;
++ NTSTATUS Status;
++
++ DPRINT("Disabling keyboard\n");
++
++ 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; // disable keyboard
++
++ 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;
++ }
++
++ return TRUE;
++}
++
++BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
++{
++ UCHAR Value;
++ NTSTATUS Status;
++
++ DPRINT("Enabling keyboard interrupt\n");
++
++ 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; // don't disable keyboard
++ Value |= CCB_KBD_INT_ENAB; // enable keyboard 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;
++ }
++
++ return TRUE;
++}
++
++BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
++{
++ NTSTATUS Status;
++ UCHAR Value;
++ UCHAR Value2;
++ ULONG RetryCount = 10;
++
++ DPRINT("Detecting keyboard\n");
++
++ I8042KeyboardDefaultsAndDisable(DevExt);
++
++ do {
++ I8042Flush();
++ Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
++ } while (STATUS_IO_TIMEOUT == Status && RetryCount--);
++
++ if (!NT_SUCCESS(Status)) {
++ DPRINT1("Can't write GET_ID (%x)\n", Status);
++ /* Could be an AT keyboard */
++ DevExt->KeyboardIsAT = TRUE;
++ goto detectsetleds;
++ }
++
++ Status = I8042ReadDataWait(DevExt, &Value);
++ if (!NT_SUCCESS(Status)) {
++ DPRINT1("No response after GET_ID\n");
++ /* Could be an AT keyboard */
++ DevExt->KeyboardIsAT = TRUE;
++ goto detectsetleds;
++ }
++ DevExt->KeyboardIsAT = FALSE;
++
++ if (Value != 0xAB && Value != 0xAC) {
++ DPRINT("Bad ID: %x\n", Value);
++ /* This is certainly not a keyboard */
++ return FALSE;
++ }
++
++ Status = I8042ReadDataWait(DevExt, &Value2);
++ if (!NT_SUCCESS(Status)) {
++ DPRINT("Partial ID\n");
++ return FALSE;
++ }
++
++ DPRINT("Keyboard ID: 0x%x 0x%x\n", Value, Value2);
++
++detectsetleds:
++ I8042Flush(); /* Flush any bytes left over from GET_ID */
++
++ Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
++ if (!NT_SUCCESS(Status)) {
++ DPRINT("Can't write SET_LEDS (%x)\n", Status);
++ return FALSE;
++ }
++ Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
++ if (!NT_SUCCESS(Status)) {
++ DPRINT("Can't finish SET_LEDS (%x)\n", Status);
++ return FALSE;
++ }
++
++ // Turn on translation
++
++ 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 |= 0x40; // enable keyboard translation
++
++ 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;
++ }
++
++ return TRUE;
++}
++
++/* debug stuff */
++VOID STDCALL
++KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2);
++#define EnterDebugger ((PVOID)0x25)
++
++static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
++ PVOID Context)
++{
++ ULONG Key;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ Key = InterlockedExchange((PLONG)&DevExt->DebugKey, 0);
++ DPRINT("Debug key: %x\n", Key);
++
++ if (!Key)
++ return;
++
++#ifdef __REACTOS__
++ /* We hope kernel would understand this. If
++ * that's not the case, nothing would happen.
++ */
++ KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
++#endif /* __REACTOS__ */
++}
--- /dev/null
--- /dev/null
++/*
++ * COPYRIGHT: See COPYING in the top level directory
++ * PROJECT: ReactOS kernel
++ * FILE: drivers/input/i8042prt/mouse.c
++ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
++ * mouse specifics
++ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
++ * Jason Filby (jasonfilby@yahoo.com)
++ * Tinus
++ */
++
++/* INCLUDES ****************************************************************/
++
++#include "i8042prt.h"
++
++#define NDEBUG
++#include <debug.h>
++
++/*
++ * These functions are callbacks for filter driver custom interrupt
++ * service routines.
++ */
++static VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
++ UCHAR Value)
++{
++ I8042IsrWritePort(Context, Value, 0xD4);
++}
++
++#if 0
++static NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
++ UCHAR Value,
++ BOOLEAN WaitForAck)
++{
++ return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
++ 0xD4,
++ Value,
++ WaitForAck);
++}
++#endif
++
++/* Test if packets are taking too long to come in. If they do, we
++ * might have gotten out of sync and should just drop what we have.
++ *
++ * If we want to be totally right, we'd also have to keep a count of
++ * errors, and totally reset the mouse after too much of them (can
++ * happen if the user is using a KVM switch and an OS on another port
++ * resets the mouse, or if the user hotplugs the mouse, or if we're just
++ * generally unlucky). Also note the input parsing routine where we
++ * drop invalid input packets.
++ */
++static VOID STDCALL I8042MouseInputTestTimeout(PDEVICE_EXTENSION DevExt)
++{
++ ULARGE_INTEGER Now;
++
++ if (DevExt->MouseState == MouseExpectingACK ||
++ DevExt->MouseState == MouseResetting)
++ return;
++
++ Now.QuadPart = KeQueryInterruptTime();
++
++ if (DevExt->MouseState != MouseIdle) {
++ /* Check if the last byte came too long ago */
++ if (Now.QuadPart - DevExt->MousePacketStartTime.QuadPart >
++ DevExt->Settings.MouseSynchIn100ns) {
++ DPRINT("Mouse input packet timeout\n");
++ DevExt->MouseState = MouseIdle;
++ }
++ }
++
++ if (DevExt->MouseState == MouseIdle)
++ DevExt->MousePacketStartTime.QuadPart = Now.QuadPart;
++}
++
++/*
++ * Call the customization hook. The Ret2 parameter is about wether
++ * we should go on with the interrupt. The return value is what
++ * we should return (indicating to the system wether someone else
++ * should try to handle the interrupt)
++ */
++static BOOLEAN STDCALL I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt,
++ UCHAR Status,
++ PUCHAR Input,
++ PBOOLEAN ToReturn)
++{
++ BOOLEAN HookReturn, HookContinue;
++
++ HookContinue = FALSE;
++
++ if (DevExt->MouseHook.IsrRoutine) {
++ HookReturn = DevExt->MouseHook.IsrRoutine(
++ DevExt->MouseHook.Context,
++ DevExt->MouseBuffer + DevExt->MouseInBuffer,
++ &DevExt->Packet,
++ Status,
++ Input,
++ &HookContinue,
++ &DevExt->MouseState,
++ &DevExt->MouseResetState);
++
++ if (!HookContinue) {
++ *ToReturn = HookReturn;
++ return TRUE;
++ }
++ }
++ return FALSE;
++}
++
++static BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
++ UCHAR Status,
++ PUCHAR Value)
++{
++ BOOLEAN ToReturn = FALSE;
++
++ if (I8042MouseCallIsrHook(DevExt, Status, Value, &ToReturn))
++ return ToReturn;
++
++ if (MouseResetting != DevExt->MouseState) {
++ return FALSE;
++ }
++ DevExt->MouseTimeoutState = TimeoutStart;
++
++ switch (DevExt->MouseResetState) {
++ case 1100: /* the first ack, drop it. */
++ DevExt->MouseResetState = ExpectingReset;
++ return TRUE;
++ /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
++ * FC00 if not.
++ */
++ case ExpectingReset:
++ if (0xAA == *Value) {
++ DevExt->MouseResetState++;
++ } else {
++ DevExt->MouseExists = FALSE;
++ DevExt->MouseState = MouseIdle;
++ DPRINT("Mouse returned bad reset reply: "
++ "%x (expected aa)\n", *Value);
++ }
++ return TRUE;
++ case ExpectingResetId:
++ if (0x00 == *Value) {
++ DevExt->MouseResetState++;
++ DevExt->MouseType = GenericPS2;
++ I8042IsrWritePortMouse(DevExt, 0xF2);
++ } else {
++ DevExt->MouseExists = FALSE;
++ DevExt->MouseState = MouseIdle;
++ DPRINT1("Mouse returned bad reset reply part two: "
++ "%x (expected 0)\n", *Value);
++ }
++ return TRUE;
++ case ExpectingGetDeviceIdACK:
++ if (MOUSE_ACK == *Value) {
++ DevExt->MouseResetState++;
++ } else if (MOUSE_NACK == *Value ||
++ MOUSE_ERROR == *Value) {
++ DevExt->MouseResetState++;
++ /* Act as if 00 (normal mouse) was received */
++ DPRINT("Mouse doesn't support 0xd2, "
++ "(returns %x, expected %x), faking.\n",
++ *Value, MOUSE_ACK);
++ *Value = 0;
++ I8042MouseResetIsr(DevExt, Status, Value);
++ }
++ return TRUE;
++ case ExpectingGetDeviceIdValue:
++ switch (*Value) {
++ case 0x02:
++ DevExt->MouseAttributes.MouseIdentifier =
++ BALLPOINT_I8042_HARDWARE;
++ break;
++ case 0x03:
++ case 0x04:
++ DevExt->MouseAttributes.MouseIdentifier =
++ WHEELMOUSE_I8042_HARDWARE;
++ break;
++ default:
++ DevExt->MouseAttributes.MouseIdentifier =
++ MOUSE_I8042_HARDWARE;
++ }
++ DevExt->MouseResetState++;
++ I8042IsrWritePortMouse(DevExt, 0xE8);
++ return TRUE;
++ case ExpectingSetResolutionDefaultACK:
++ DevExt->MouseResetState++;
++ I8042IsrWritePortMouse(DevExt, 0x00);
++ return TRUE;
++ case ExpectingSetResolutionDefaultValueACK:
++ DevExt->MouseResetState = ExpectingSetScaling1to1ACK;
++ I8042IsrWritePortMouse(DevExt, 0xE6);
++ return TRUE;
++ case ExpectingSetScaling1to1ACK:
++ case ExpectingSetScaling1to1ACK2:
++ DevExt->MouseResetState++;
++ I8042IsrWritePortMouse(DevExt, 0xE6);
++ return TRUE;
++ case ExpectingSetScaling1to1ACK3:
++ DevExt->MouseResetState++;
++ I8042IsrWritePortMouse(DevExt, 0xE9);
++ return TRUE;
++ case ExpectingReadMouseStatusACK:
++ DevExt->MouseResetState++;
++ return TRUE;
++ case ExpectingReadMouseStatusByte1:
++ DevExt->MouseLogiBuffer[0] = *Value;
++ DevExt->MouseResetState++;
++ return TRUE;
++ case ExpectingReadMouseStatusByte2:
++ DevExt->MouseLogiBuffer[1] = *Value;
++ DevExt->MouseResetState++;
++ return TRUE;
++ case ExpectingReadMouseStatusByte3:
++ DevExt->MouseLogiBuffer[2] = *Value;
++ /* Now MouseLogiBuffer is a set of info. If the second
++ * byte is 0, the mouse didn't understand the magic
++ * code. Otherwise, it it a Logitech and the second byte
++ * is the number of buttons, bit 7 of the first byte tells
++ * if it understands special E7 commands, the rest is an ID.
++ */
++ if (DevExt->MouseLogiBuffer[1]) {
++ DevExt->MouseAttributes.NumberOfButtons =
++ DevExt->MouseLogiBuffer[1];
++ /* For some reason the ID is the wrong way around */
++ DevExt->MouseLogitechID =
++ ((DevExt->MouseLogiBuffer[0] >> 4) & 0x07) |
++ ((DevExt->MouseLogiBuffer[0] << 3) & 0x78);
++ DevExt->MouseType = Ps2pp;
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState = ExpectingSetSamplingRateACK;
++ return TRUE;
++ /* TODO: Go through EnableWheel and Enable5Buttons */
++ }
++ DevExt->MouseResetState = EnableWheel;
++ I8042MouseResetIsr(DevExt, Status, Value);
++ return TRUE;
++ case EnableWheel:
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState = 1001;
++ return TRUE;
++ case 1001:
++ I8042IsrWritePortMouse(DevExt, 0xc8);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1002:
++ case 1004:
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1003:
++ I8042IsrWritePortMouse(DevExt, 0x64);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1005:
++ I8042IsrWritePortMouse(DevExt, 0x50);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1006:
++ I8042IsrWritePortMouse(DevExt, 0xf2);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1007:
++ /* Ignore ACK */
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1008:
++ /* Now if the value == 3, it's either an Intellimouse
++ * or Intellimouse Explorer. */
++ if (0x03 == *Value) {
++ DevExt->MouseAttributes.NumberOfButtons = 3;
++ DevExt->MouseAttributes.MouseIdentifier =
++ WHEELMOUSE_I8042_HARDWARE;
++ DevExt->MouseType = Intellimouse;
++ DevExt->MouseResetState = Enable5Buttons;
++ I8042MouseResetIsr(DevExt, Status, Value);
++ return TRUE;
++ } /* Else, just set the default settings and be done */
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState = ExpectingSetSamplingRateACK;
++ return TRUE;
++ case Enable5Buttons:
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState = 1021;
++ return TRUE;
++ case 1022:
++ case 1024:
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1021:
++ case 1023:
++ I8042IsrWritePortMouse(DevExt, 0xc8);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1025:
++ I8042IsrWritePortMouse(DevExt, 0x50);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1026:
++ I8042IsrWritePortMouse(DevExt, 0xf2);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case 1027:
++ if (0x04 == *Value) {
++ DevExt->MouseAttributes.NumberOfButtons = 5;
++ DevExt->MouseAttributes.MouseIdentifier =
++ WHEELMOUSE_I8042_HARDWARE;
++ DevExt->MouseType = IntellimouseExplorer;
++ }
++ I8042IsrWritePortMouse(DevExt, 0xf3);
++ DevExt->MouseResetState = ExpectingSetSamplingRateACK;
++ return TRUE;
++ case ExpectingSetSamplingRateACK:
++ I8042IsrWritePortMouse(DevExt,
++ (UCHAR)DevExt->MouseAttributes.SampleRate);
++ DevExt->MouseResetState++;
++ return TRUE;
++ case ExpectingSetSamplingRateValueACK:
++ if (MOUSE_NACK == *Value) {
++ I8042IsrWritePortMouse(DevExt, 0x3c);
++ DevExt->MouseAttributes.SampleRate = 60;
++ DevExt->MouseResetState = 1040;
++ return TRUE;
++ }
++ case 1040: /* Fallthrough */
++ I8042IsrWritePortMouse(DevExt, 0xe8);
++ DevExt->MouseResetState = ExpectingFinalResolutionACK;
++ return TRUE;
++ case ExpectingFinalResolutionACK:
++ I8042IsrWritePortMouse(DevExt,
++ (UCHAR)(DevExt->Settings.MouseResolution & 0xff));
++ DPRINT("%x\n", DevExt->Settings.MouseResolution);
++ DevExt->MouseResetState = ExpectingFinalResolutionValueACK;
++ return TRUE;
++ case ExpectingFinalResolutionValueACK:
++ I8042IsrWritePortMouse(DevExt, 0xf4);
++ DevExt->MouseResetState = ExpectingEnableACK;
++ return TRUE;
++ case ExpectingEnableACK:
++ DevExt->MouseState = MouseIdle;
++ DevExt->MouseTimeoutState = TimeoutCancel;
++ DPRINT("Mouse type = %d\n", DevExt->MouseType);
++ return TRUE;
++ default:
++ if (DevExt->MouseResetState < 100 ||
++ DevExt->MouseResetState > 999)
++ DPRINT1("MouseResetState went out of range: %d\n",
++ DevExt->MouseResetState);
++ return FALSE;
++ }
++}
++
++/*
++ * Prepare for reading the next packet and queue the dpc for handling
++ * this one.
++ *
++ * Context is the device object.
++ */
++VOID STDCALL I8042QueueMousePacket(PVOID Context)
++{
++ PDEVICE_OBJECT DeviceObject = Context;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ DevExt->MouseComplete = TRUE;
++ DevExt->MouseInBuffer++;
++ if (DevExt->MouseInBuffer >
++ DevExt->MouseAttributes.InputDataQueueLength) {
++ DPRINT1("Mouse buffer overflow\n");
++ DevExt->MouseInBuffer--;
++ }
++
++ DPRINT("Irq completes mouse packet\n");
++ KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
++}
++
++/*
++ * Updates ButtonFlags according to RawButtons and a saved state;
++ * Only takes in account the bits that are set in Mask
++ */
++VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
++ USHORT Mask)
++{
++ PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
++ DevExt->MouseInBuffer;
++ USHORT NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
++ USHORT ButtonDiff = (NewButtonData ^ DevExt->MouseButtonState) & Mask;
++
++ /* Note that the defines are such:
++ * MOUSE_LEFT_BUTTON_DOWN 1
++ * MOUSE_LEFT_BUTTON_UP 2
++ */
++ MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) |
++ (((~(NewButtonData)) << 1) &
++ (ButtonDiff << 1)) |
++ (MouseInput->RawButtons & 0xfc00);
++
++ DPRINT("Left raw/up/down: %d/%d/%d\n", MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
++ MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
++ MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
++
++ DevExt->MouseButtonState = (DevExt->MouseButtonState & ~Mask) |
++ (NewButtonData & Mask);
++}
++
++VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
++ UCHAR Output)
++{
++ PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
++ DevExt->MouseInBuffer;
++ CHAR Scroll;
++
++ switch (DevExt->MouseState) {
++ case MouseIdle:
++ /* This bit should be 1, if not drop the packet, we
++ * might be lucky and get in sync again
++ */
++ if (!(Output & 8)) {
++ DPRINT1("Bad input, dropping..\n");
++ return;
++ }
++
++ MouseInput->Buttons = 0;
++ MouseInput->RawButtons = 0;
++ MouseInput->Flags = MOUSE_MOVE_RELATIVE;
++
++ /* Note how we ignore the overflow bits, like Windows
++ * is said to do. There's no reasonable thing to do
++ * anyway.
++ */
++
++ if (Output & 16)
++ MouseInput->LastX = 1;
++ else
++ MouseInput->LastX = 0;
++
++ if (Output & 32)
++ MouseInput->LastY = 1;
++ else
++ MouseInput->LastY = 0;
++
++ if (Output & 1) {
++ MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN;
++ }
++
++ if (Output & 2) {
++ MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN;
++ }
++
++ if (Output & 4) {
++ MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN;
++ }
++ DevExt->MouseState = XMovement;
++ break;
++ case XMovement:
++ if (MouseInput->LastX)
++ MouseInput->LastX = (LONG) Output - 256;
++ else
++ MouseInput->LastX = Output;
++
++ DevExt->MouseState = YMovement;
++ break;
++ case YMovement:
++ if (MouseInput->LastY)
++ MouseInput->LastY = (LONG)Output - 256;
++ else
++ MouseInput->LastY = (LONG)Output;
++
++ /* Windows wants it the other way around */
++ MouseInput->LastY = -MouseInput->LastY;
++
++ if (DevExt->MouseType == GenericPS2 ||
++ DevExt->MouseType == Ps2pp) {
++ I8042MouseHandleButtons(DevExt,
++ MOUSE_LEFT_BUTTON_DOWN |
++ MOUSE_RIGHT_BUTTON_DOWN |
++ MOUSE_MIDDLE_BUTTON_DOWN);
++ I8042QueueMousePacket(
++ DevExt->MouseObject);
++ DevExt->MouseState = MouseIdle;
++ } else {
++ DevExt->MouseState = ZMovement;
++ }
++ break;
++ case ZMovement:
++ Scroll = Output & 0x0f;
++ if (Scroll & 8)
++ Scroll |= 0xf0;
++
++ if (Scroll) {
++ MouseInput->RawButtons |= MOUSE_WHEEL;
++ MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
++ }
++
++ if (DevExt->MouseType == IntellimouseExplorer) {
++ if (Output & 16)
++ MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
++
++ if (Output & 32)
++ MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
++ }
++ I8042MouseHandleButtons(DevExt, MOUSE_LEFT_BUTTON_DOWN |
++ MOUSE_RIGHT_BUTTON_DOWN |
++ MOUSE_MIDDLE_BUTTON_DOWN |
++ MOUSE_BUTTON_4_DOWN |
++ MOUSE_BUTTON_5_DOWN);
++ I8042QueueMousePacket(DevExt->MouseObject);
++ DevExt->MouseState = MouseIdle;
++ break;
++ default:
++ DPRINT1("Unexpected state!\n");
++ }
++}
++
++BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
++ VOID *Context)
++{
++ UCHAR Output, PortStatus;
++ NTSTATUS Status;
++ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
++ ULONG Iterations = 0;
++
++ do {
++ Status = I8042ReadStatus(&PortStatus);
++ Status = I8042ReadData(&Output);
++ Iterations++;
++ if (STATUS_SUCCESS == Status)
++ break;
++ KeStallExecutionProcessor(1);
++ } while (Iterations < DevExt->Settings.PollStatusIterations);
++
++ if (STATUS_SUCCESS != Status) {
++ DPRINT1("Spurious I8042 mouse interrupt\n");
++ return FALSE;
++ }
++
++ DPRINT("Got: %x\n", Output);
++
++ if (I8042PacketIsr(DevExt, Output)) {
++ if (DevExt->PacketComplete) {
++ DPRINT("Packet complete\n");
++ KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
++ }
++ DPRINT("Irq eaten by packet\n");
++ return TRUE;
++ }
++
++ I8042MouseInputTestTimeout(DevExt);
++
++ if (I8042MouseResetIsr(DevExt, PortStatus, &Output)) {
++ DPRINT("Handled by ResetIsr or hooked Isr\n");
++ if (NoChange != DevExt->MouseTimeoutState) {
++ KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
++ }
++ return TRUE;
++ }
++
++ if (DevExt->MouseType == Ps2pp)
++ I8042MouseHandlePs2pp(DevExt, Output);
++ else
++ I8042MouseHandle(DevExt, Output);
++
++ return TRUE;
++}
++
++VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
++ PVOID DeferredContext,
++ PVOID SystemArgument1,
++ PVOID SystemArgument2)
++{
++ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
++ ULONG MouseTransferred = 0;
++ ULONG MouseInBufferCopy;
++ KIRQL Irql;
++ LARGE_INTEGER Timeout;
++
++ switch (DevExt->MouseTimeoutState) {
++ case TimeoutStart:
++ DevExt->MouseTimeoutState = NoChange;
++ if (DevExt->MouseTimeoutActive &&
++ !KeCancelTimer(&DevExt->TimerMouseTimeout)) {
++ /* The timer fired already, give up */
++ DevExt->MouseTimeoutActive = FALSE;
++ return;
++ }
++
++ Timeout.QuadPart = -15000000;
++ /* 1.5 seconds, should be enough */
++
++ KeSetTimer(&DevExt->TimerMouseTimeout,
++ Timeout,
++ &DevExt->DpcMouseTimeout);
++ DevExt->MouseTimeoutActive = TRUE;
++ return;
++ case TimeoutCancel:
++ DevExt->MouseTimeoutState = NoChange;
++ KeCancelTimer(&DevExt->TimerMouseTimeout);
++ DevExt->MouseTimeoutActive = FALSE;
++ default:
++ /* nothing, don't want a warning */ ;
++ }
++
++ /* Should be unlikely */
++ if (!DevExt->MouseComplete)
++ return;
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++
++ DevExt->MouseComplete = FALSE;
++ MouseInBufferCopy = DevExt->MouseInBuffer;
++
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++
++ DPRINT ("Send a mouse packet\n");
++
++ if (!DevExt->MouseData.ClassService)
++ return;
++
++ ((PSERVICE_CALLBACK_ROUTINE) DevExt->MouseData.ClassService)(
++ DevExt->MouseData.ClassDeviceObject,
++ DevExt->MouseBuffer,
++ DevExt->MouseBuffer + MouseInBufferCopy,
++ &MouseTransferred);
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++
++ DevExt->MouseInBuffer -= MouseTransferred;
++ if (DevExt->MouseInBuffer)
++ RtlMoveMemory(DevExt->MouseBuffer,
++ DevExt->MouseBuffer+MouseTransferred,
++ DevExt->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
++
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++}
++
++/* This timer DPC will be called when the mouse reset times out.
++ * I'll just send the 'disable mouse port' command to the controller
++ * and say the mouse doesn't exist.
++ */
++VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
++ PVOID DeferredContext,
++ PVOID SystemArgument1,
++ PVOID SystemArgument2)
++{
++ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
++ KIRQL Irql;
++
++ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
++
++ DPRINT1("Mouse initialization timeout! (substate %x) "
++ "Disabling mouse.\n",
++ DevExt->MouseResetState);
++
++ if (!I8042MouseDisable(DevExt)) {
++ DPRINT1("Failed to disable mouse.\n");
++ }
++
++ DevExt->MouseExists = FALSE;
++
++ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
++}
++
++/*
++ * Process the mouse internal device requests
++ * returns FALSE if it doesn't understand the
++ * call so someone else can handle it.
++ */
++#if 0
++static BOOLEAN STDCALL I8042StartIoMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
++{
++ PIO_STACK_LOCATION Stk;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ Stk = IoGetCurrentIrpStackLocation(Irp);
++
++ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
++ case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
++ I8042StartPacket(
++ DevExt,
++ DeviceObject,
++ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
++ Stk->Parameters.DeviceIoControl.InputBufferLength,
++ Irp);
++ break;
++
++ default:
++ return FALSE;
++ }
++
++ return TRUE;
++}
++#endif
++
++/*
++ * Runs the mouse IOCTL_INTERNAL dispatch.
++ * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
++ * so someone else can have a try at it.
++ */
++NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
++{
++ PIO_STACK_LOCATION Stk;
++ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
++ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
++
++ DPRINT("InternalDeviceControl\n");
++
++ Irp->IoStatus.Information = 0;
++ Stk = IoGetCurrentIrpStackLocation(Irp);
++
++ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
++
++ case IOCTL_INTERNAL_MOUSE_CONNECT:
++ DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
++ sizeof(CONNECT_DATA)) {
++ DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
++ goto intcontfailure;
++ }
++
++ if (!DevExt->MouseExists) {
++ Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
++ goto intcontfailure;
++ }
++
++ if (DevExt->MouseClaimed) {
++ DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
++ "Mouse is already claimed\n");
++ Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
++ goto intcontfailure;
++ }
++
++ memcpy(&DevExt->MouseData,
++ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
++ sizeof(CONNECT_DATA));
++ DevExt->MouseHook.IsrWritePort = I8042IsrWritePortMouse;
++ DevExt->MouseHook.QueueMousePacket =
++ I8042QueueMousePacket;
++ DevExt->MouseHook.CallContext = DevExt;
++
++ {
++ PIO_WORKITEM WorkItem;
++ PI8042_HOOK_WORKITEM WorkItemData;
++
++ WorkItem = IoAllocateWorkItem(DeviceObject);
++ if (!WorkItem) {
++ DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
++ "Can't allocate work item\n");
++ Irp->IoStatus.Status =
++ STATUS_INSUFFICIENT_RESOURCES;
++ goto intcontfailure;
++ }
++
++ WorkItemData = ExAllocatePoolWithTag(
++ NonPagedPool,
++ sizeof(I8042_HOOK_WORKITEM),
++ TAG_I8042);
++ if (!WorkItemData) {
++ DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
++ "Can't allocate work item data\n");
++ Irp->IoStatus.Status =
++ STATUS_INSUFFICIENT_RESOURCES;
++ IoFreeWorkItem(WorkItem);
++ goto intcontfailure;
++ }
++ WorkItemData->WorkItem = WorkItem;
++ WorkItemData->Target =
++ DevExt->MouseData.ClassDeviceObject;
++ WorkItemData->Irp = Irp;
++
++ IoMarkIrpPending(Irp);
++ DevExt->MouseState = MouseResetting;
++ DevExt->MouseResetState = 1100;
++ IoQueueWorkItem(WorkItem,
++ I8042SendHookWorkItem,
++ DelayedWorkQueue,
++ WorkItemData);
++
++ Irp->IoStatus.Status = STATUS_PENDING;
++ }
++
++ break;
++ case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
++ DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
++ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
++ goto intcontfailure;
++ }
++ if (!DevExt->MouseInterruptObject) {
++ Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
++ goto intcontfailure;
++ }
++
++ IoMarkIrpPending(Irp);
++ IoStartPacket(DeviceObject, Irp, NULL, NULL);
++ Irp->IoStatus.Status = STATUS_PENDING;
++
++ break;
++ case IOCTL_MOUSE_QUERY_ATTRIBUTES:
++ DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
++ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
++ sizeof(MOUSE_ATTRIBUTES)) {
++ DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
++ "invalid buffer size\n");
++ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
++ goto intcontfailure;
++ }
++ memcpy(Irp->AssociatedIrp.SystemBuffer,
++ &DevExt->MouseAttributes,
++ sizeof(MOUSE_ATTRIBUTES));
++
++ Irp->IoStatus.Status = STATUS_SUCCESS;
++ break;
++ default:
++ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
++ break;
++ }
++
++intcontfailure:
++ return Irp->IoStatus.Status;
++}
++
++BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
++{
++ UCHAR Value;
++ NTSTATUS Status;
++
++ DPRINT("Enabling mouse\n");
++
++ 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 &= ~(0x20); // don't disable mouse
++ Value |= 0x02; // enable 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;
++ }
++
++ return TRUE;
++}
++
++BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
++{
++ UCHAR Value;
++ NTSTATUS Status;
++
++ DPRINT("Disabling mouse\n");
++
++ I8042Flush(); /* Just to be (kind of) sure */
++
++ 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 |= 0x20; // don't disable mouse
++ Value &= ~(0x02); // enable 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;
++ }
++
++ I8042Flush();
++ /* Just to be (kind of) sure; if the mouse would
++ * say something while we are disabling it, these bytes would
++ * block the keyboard.
++ */
++
++ return TRUE;
++}
++
++BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt)
++{
++ BOOLEAN Ok = TRUE;
++ NTSTATUS Status;
++ UCHAR Value;
++ UCHAR ExpectedReply[] = { 0xFA, 0xAA, 0x00 };
++ unsigned ReplyByte;
++
++ if (! I8042Write(DevExt, I8042_CTRL_PORT, 0xD4) ||
++ ! I8042Write(DevExt, I8042_DATA_PORT, 0xFF))
++ {
++ DPRINT1("Failed to write reset command to mouse\n");
++ Ok = FALSE;
++ }
++
++ for (ReplyByte = 0;
++ ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]) && Ok;
++ ReplyByte++)
++ {
++ Status = I8042ReadDataWait(DevExt, &Value);
++ if (! NT_SUCCESS(Status))
++ {
++ DPRINT1("No ACK after mouse reset, status 0x%08x\n",
++ Status);
++ Ok = FALSE;
++ }
++ else if (Value != ExpectedReply[ReplyByte])
++ {
++ DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
++ Value, ExpectedReply[ReplyByte]);
++ Ok = FALSE;
++ }
++ }
++
++ if (! Ok)
++ {
++ /* There is probably no mouse present. On some systems,
++ the probe locks the entire keyboard controller. Let's
++ try to get access to the keyboard again by sending a
++ reset */
++ I8042Flush();
++ I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST);
++ I8042ReadDataWait(DevExt, &Value);
++ I8042Flush();
++ }
++
++ DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
++
++ return Ok;
++}
--- /dev/null
--- /dev/null
++/*
++ * COPYRIGHT: See COPYING in the top level directory
++ * PROJECT: ReactOS kernel
++ * FILE: drivers/input/i8042prt/ps2pp.c
++ * PURPOSE: i8042prt driver
++ * ps2pp protocol handling
++ * PROGRAMMER: Tinus
++ */
++
++/* INCLUDES ****************************************************************/
++
++#ifndef NDEBUG
++#define NDEBUG
++#endif
++#include <debug.h>
++
++#include "i8042prt.h"
++
++
++VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input)
++{
++ UCHAR PktType;
++ PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
++ DevExt->MouseInBuffer;
++
++/* First, collect 3 bytes for a packet
++ * We can detect out-of-sync only by checking
++ * the whole packet anyway.
++ *
++ * If bit 7 and 8 of the first byte are 0, its
++ * a normal packet.
++ *
++ * Otherwise, the packet is different, like this:
++ * 1: E 1 b3 b2 x x x x
++ * 2: x x b1 b0 x1 x0 1 0
++ * 3: x x x x x x x1 x0
++ *
++ * b3-0 form a code that specifies the packet type:
++ *
++ * 0 Device Type
++ * 1 Rollers and buttons
++ * 2 Reserved
++ * 3 Reserved
++ * 4 Device ID
++ * 5 Channel & Battery
++ * 6 Wireless notifications
++ * 7 Reserved
++ * 8 ShortID LSB (ShortID is a number that is supposed to differentiate
++ * 9 ShortID MSB between your mouse and your neighbours')
++ * 10 Reserved
++ * 11 Mouse capabilities
++ * 12 Remote control LSB
++ * 13 Remote control MSB
++ * 14 Reserved
++ * 15 Extended packet
++ */
++
++ switch (DevExt->MouseState) {
++ case MouseIdle:
++ case XMovement:
++ DevExt->MouseLogiBuffer[DevExt->MouseState] = Input;
++ DevExt->MouseState++;
++ break;
++
++ case YMovement:
++ DevExt->MouseLogiBuffer[2] = Input;
++ DevExt->MouseState = MouseIdle;
++
++ /* first check if it's a normal packet */
++
++ if (!(DevExt->MouseLogiBuffer[0] & 0xC0)) {
++ DevExt->MouseState = MouseIdle;
++ I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[0]);
++ I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[1]);
++ I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[2]);
++ /* We could care about wether MouseState really
++ * advances, but we don't need to because we're
++ * only doing three bytes anyway, so the packet
++ * will never complete if it's broken.
++ */
++ return;
++ }
++
++ /* sanity check */
++
++ if (((DevExt->MouseLogiBuffer[0] & 0x48) != 0x48) ||
++ (((DevExt->MouseLogiBuffer[1] & 0x0C) >> 2) !=
++ (DevExt->MouseLogiBuffer[2] & 0x03))) {
++ DPRINT1("Ps2pp packet fails sanity checks\n");
++ return;
++ }
++
++ /* Now get the packet type */
++
++ PktType = ((DevExt->MouseLogiBuffer[0] & 0x30) >> 4) &
++ ((DevExt->MouseLogiBuffer[1] & 0x30) >> 6);
++
++ switch (PktType) {
++ case 0:
++ /* The packet contains the device ID, but we
++ * already read that in the initialization
++ * sequence. Ignore it.
++ */
++ return;
++ case 1:
++ RtlZeroMemory(MouseInput, sizeof(MOUSE_INPUT_DATA));
++ if (DevExt->MouseLogiBuffer[2] & 0x10)
++ MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
++
++ if (DevExt->MouseLogiBuffer[2] & 0x20)
++ MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
++
++ if (DevExt->MouseLogiBuffer[2] & 0x0F) {
++ MouseInput->ButtonFlags |= MOUSE_WHEEL;
++ if (DevExt->MouseLogiBuffer[2] & 0x08)
++ MouseInput->ButtonData =
++ (DevExt->MouseLogiBuffer[2] & 0x07) -
++ 8;
++ else
++ MouseInput->ButtonData =
++ DevExt->MouseLogiBuffer[2] & 0x07;
++ }
++ I8042MouseHandleButtons(DevExt, MOUSE_BUTTON_4_DOWN |
++ MOUSE_BUTTON_5_DOWN);
++ I8042QueueMousePacket(
++ DevExt->MouseObject);
++ return;
++ default:
++ /* These are for things that would probably
++ * be handled by logitechs own driver.
++ */
++ return;
++ }
++ default:
++ DPRINT1("Unexpected input state for ps2pp!\n");
++ }
++}
--- /dev/null
--- /dev/null
++/*
++ * COPYRIGHT: See COPYING in the top level directory
++ * PROJECT: ReactOS kernel
++ * FILE: drivers/input/i8042prt/registry.c
++ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
++ * Reading the registry
++ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
++ * Jason Filby (jasonfilby@yahoo.com)
++ * Tinus
++ */
++
++/* INCLUDES ****************************************************************/
++
++#ifndef NDEBUG
++#define NDEBUG
++#endif
++#include <debug.h>
++
++#include "i8042prt.h"
++
++/* FUNCTIONS *****************************************************************/
++
++/*
++ * Read the registry keys associated with this device. The RegistryPath
++ * var is a hack. This should be more like what microsoft does, but I
++ * don't know exactly what they do except that it's a hack too...
++ */
++VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
++ PDEVICE_EXTENSION DevExt)
++
++{
++ RTL_QUERY_REGISTRY_TABLE Parameters[19];
++
++ NTSTATUS Status;
++
++ ULONG DefaultHeadless = 0;
++ ULONG DefaultCrashScroll = 0;
++ ULONG DefaultCrashSysRq = 0;
++ ULONG DefaultReportResetErrors = 0;
++ ULONG DefaultPollStatusIterations = 1;
++ ULONG DefaultResendIterations = 3;
++ ULONG DefaultPollingIterations = 12000;
++ ULONG DefaultPollingIterationsMaximum = 12000;
++ ULONG DefaultKeyboardDataQueueSize = 100;
++ ULONG DefaultOverrideKeyboardType = 0;
++ ULONG DefaultOverrideKeyboardSubtype = 0;
++ ULONG DefaultMouseDataQueueSize = 100;
++ ULONG DefaultMouseResendStallTime = 1000;
++ ULONG DefaultMouseSynchIn100ns = 20000000;
++ ULONG DefaultMouseResolution = 3;
++ ULONG DefaultSampleRate = 60;
++ ULONG DefaultNumberOfButtons = 2;
++ ULONG DefaultEnableWheelDetection = 1;
++
++ RtlZeroMemory(Parameters, sizeof(Parameters));
++
++ Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[0].Name = L"Headless";
++ Parameters[0].EntryContext = &DevExt->Settings.Headless;
++ Parameters[0].DefaultType = REG_DWORD;
++ Parameters[0].DefaultData = &DefaultHeadless;
++ Parameters[0].DefaultLength = sizeof(ULONG);
++
++ Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[1].Name = L"CrashOnCtrlScroll";
++ Parameters[1].EntryContext = &DevExt->Settings.CrashScroll;
++ Parameters[1].DefaultType = REG_DWORD;
++ Parameters[1].DefaultData = &DefaultCrashScroll;
++ Parameters[1].DefaultLength = sizeof(ULONG);
++
++ Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[2].Name = L"BreakOnSysRq";
++ Parameters[2].EntryContext = &DevExt->Settings.CrashSysRq;
++ Parameters[2].DefaultType = REG_DWORD;
++ Parameters[2].DefaultData = &DefaultCrashSysRq;
++ Parameters[2].DefaultLength = sizeof(ULONG);
++
++ Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[3].Name = L"ReportResetErrors";
++ Parameters[3].EntryContext = &DevExt->Settings.ReportResetErrors;
++ Parameters[3].DefaultType = REG_DWORD;
++ Parameters[3].DefaultData = &DefaultReportResetErrors;
++ Parameters[3].DefaultLength = sizeof(ULONG);
++
++ Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[4].Name = L"PollStatusIterations";
++ Parameters[4].EntryContext = &DevExt->Settings.PollStatusIterations;
++ Parameters[4].DefaultType = REG_DWORD;
++ Parameters[4].DefaultData = &DefaultPollStatusIterations;
++ Parameters[4].DefaultLength = sizeof(ULONG);
++
++ Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[5].Name = L"ResendIterations";
++ Parameters[5].EntryContext = &DevExt->Settings.ResendIterations;
++ Parameters[5].DefaultType = REG_DWORD;
++ Parameters[5].DefaultData = &DefaultResendIterations;
++ Parameters[5].DefaultLength = sizeof(ULONG);
++
++ Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[6].Name = L"PollingIterations";
++ Parameters[6].EntryContext = &DevExt->Settings.PollingIterations;
++ Parameters[6].DefaultType = REG_DWORD;
++ Parameters[6].DefaultData = &DefaultPollingIterations;
++ Parameters[6].DefaultLength = sizeof(ULONG);
++
++ Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[7].Name = L"PollingIterationsMaximum";
++ Parameters[7].EntryContext = &DevExt->Settings.PollingIterationsMaximum;
++ Parameters[7].DefaultType = REG_DWORD;
++ Parameters[7].DefaultData = &DefaultPollingIterationsMaximum;
++ Parameters[7].DefaultLength = sizeof(ULONG);
++
++ Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[8].Name = L"KeyboardDataQueueSize";
++ Parameters[8].EntryContext =
++ &DevExt->KeyboardAttributes.InputDataQueueLength;
++ Parameters[8].DefaultType = REG_DWORD;
++ Parameters[8].DefaultData = &DefaultKeyboardDataQueueSize;
++ Parameters[8].DefaultLength = sizeof(ULONG);
++
++ Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[9].Name = L"OverrideKeyboardType";
++ Parameters[9].EntryContext = &DevExt->Settings.OverrideKeyboardType;
++ Parameters[9].DefaultType = REG_DWORD;
++ Parameters[9].DefaultData = &DefaultOverrideKeyboardType;
++ Parameters[9].DefaultLength = sizeof(ULONG);
++
++ Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[10].Name = L"OverrideKeyboardSubtype";
++ Parameters[10].EntryContext = &DevExt->Settings.OverrideKeyboardSubtype;
++ Parameters[10].DefaultType = REG_DWORD;
++ Parameters[10].DefaultData = &DefaultOverrideKeyboardSubtype;
++ Parameters[10].DefaultLength = sizeof(ULONG);
++
++ Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[11].Name = L"MouseDataQueueSize";
++ Parameters[11].EntryContext =
++ &DevExt->MouseAttributes.InputDataQueueLength;
++ Parameters[11].DefaultType = REG_DWORD;
++ Parameters[11].DefaultData = &DefaultMouseDataQueueSize;
++ Parameters[11].DefaultLength = sizeof(ULONG);
++
++ Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[12].Name = L"MouseResendStallTime";
++ Parameters[12].EntryContext = &DevExt->Settings.MouseResendStallTime;
++ Parameters[12].DefaultType = REG_DWORD;
++ Parameters[12].DefaultData = &DefaultMouseResendStallTime;
++ Parameters[12].DefaultLength = sizeof(ULONG);
++
++ Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[13].Name = L"MouseSynchIn100ns";
++ Parameters[13].EntryContext = &DevExt->Settings.MouseSynchIn100ns;
++ Parameters[13].DefaultType = REG_DWORD;
++ Parameters[13].DefaultData = &DefaultMouseSynchIn100ns;
++ Parameters[13].DefaultLength = sizeof(ULONG);
++
++ Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[14].Name = L"MouseResolution";
++ Parameters[14].EntryContext = &DevExt->Settings.MouseResolution;
++ Parameters[14].DefaultType = REG_DWORD;
++ Parameters[14].DefaultData = &DefaultMouseResolution;
++ Parameters[14].DefaultLength = sizeof(ULONG);
++
++ Parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[15].Name = L"SampleRate";
++ Parameters[15].EntryContext = &DevExt->MouseAttributes.SampleRate;
++ Parameters[15].DefaultType = REG_DWORD;
++ Parameters[15].DefaultData = &DefaultSampleRate;
++ Parameters[15].DefaultLength = sizeof(ULONG);
++
++ Parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[16].Name = L"NumberOfButtons";
++ Parameters[16].EntryContext = &DevExt->Settings.NumberOfButtons;
++ Parameters[16].DefaultType = REG_DWORD;
++ Parameters[16].DefaultData = &DefaultNumberOfButtons;
++ Parameters[16].DefaultLength = sizeof(ULONG);
++
++ Parameters[17].Flags = RTL_QUERY_REGISTRY_DIRECT;
++ Parameters[17].Name = L"EnableWheelDetection";
++ Parameters[17].EntryContext = &DevExt->Settings.EnableWheelDetection;
++ Parameters[17].DefaultType = REG_DWORD;
++ Parameters[17].DefaultData = &DefaultEnableWheelDetection;
++ Parameters[17].DefaultLength = sizeof(ULONG);
++
++ Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
++ I8042RegistryPath.Buffer,
++ Parameters,
++ NULL,
++ NULL);
++
++ if (!NT_SUCCESS(Status)) {
++ /* Actually, the defaults are not set when the function
++ * fails, as would happen during setup, so you have to
++ * set them manually anyway...
++ */
++ RTL_QUERY_REGISTRY_TABLE *Current = Parameters;
++ DPRINT1 ("Can't read registry: %x\n", Status);
++ while (Current->Name) {
++ *((PULONG)Current->EntryContext) =
++ *((PULONG)Current->DefaultData);
++ Current++;
++ }
++ DPRINT1 ("Manually set defaults\n");
++
++ }
++
++ if (DevExt->Settings.MouseResolution > 3)
++ DevExt->Settings.MouseResolution = 3;
++
++ DPRINT("Done reading registry\n");
++}