HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Type",0x00010001,0x00000008
-; i8042 port driver
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","Group",0x00000000,"Keyboard Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt","Type",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\i8042prt\Parameters","BreakOnSysRq",0x00010001,0x00000001
-
; Kernel-Mode Tests
;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","ErrorControl",0x00010001,0x00000000
;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","Group",0x00000000,"Base"
;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","Start",0x00010001,0x00000001
;HKLM,"SYSTEM\CurrentControlSet\Services\Kmtest","Type",0x00010001,0x00000001
-; Keyboard class driver
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Group",0x00000000,"Keyboard Class"
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ImagePath",0x00020000,"system32\drivers\kbdclass.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Type",0x00010001,0x00000001
+; Keyboard parameters
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass\Parameters","ConnectMultiplePorts",0x00010001,1
-HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"kbdclass"
; SB16 driver
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","Group",0x00000000,"Base"
HKLM,"SYSTEM\CurrentControlSet\Services\mpu401","ErrorControl",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\mpu401","ImagePath",0x00020000,"system32\drivers\mpu401.sys"
-; Mouse class driver
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Group",0x00000000,"Pointer Class"
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","ImagePath",0x00020000,"system32\drivers\mouclass.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Type",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"mouclass"
-
; Mailslot filesystem driver
HKLM,"SYSTEM\CurrentControlSet\Services\Msfs","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\Msfs","Group",0x00000000,"File System"
The directory contains these files:
+createclose.c: open/close devices functionnality
+
i8042prt.c: Main controller functionality, things shared by keyboards and mice
keyboard.c: keyboard functionality: detection, interrupt handling
+misc.c: misc things, mostly related to Irp passing
+
mouse.c: mouse functionality: detection, interrupt handling, packet parsing for
standard ps2 and microsoft mice
+pnp.c: Plug&Play functionnality
+
ps2pp.c: logitech ps2++ mouse packat parsing (basic)
+readwrite.c: read/write to the i8042 controller
+
registry.c: registry reading
-makefile, i8042prt.rc: obvious
+setup.c: add keyboard support during the 1st stage setup
+
+i8042prt.rc: obvious
Some parts of the driver make little sense. This is because it implements
- 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:
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.
--- /dev/null
+/*
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/createclose.c
+ * PURPOSE: IRP_MJ_CREATE, IRP_MJ_CLEANUP and IRP_MJ_CLOSE operations
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS NTAPI
+i8042Create(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("IRP_MJ_CREATE\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+i8042Cleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("IRP_MJ_CLEANUP\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+i8042Close(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ DPRINT("IRP_MJ_CLOSE\n");
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+}
/*
- * 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
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/i8042prt.c
+ * PURPOSE: Driver entry function
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+ Copyright Jason Filby (jasonfilby@yahoo.com)
+ Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
-/* INCLUDES ****************************************************************/
-
-#define NDEBUG
-#include <debug.h>
+/* INCLUDES ******************************************************************/
+#define INITGUID
#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;
+#define NDEBUG
+#include <debug.h>
/* 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)
+NTSTATUS NTAPI
+i8042AddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT Pdo)
{
- ULONG Counter = DevExt->Settings.PollingIterations;
+ PI8042_DRIVER_EXTENSION DriverExtension;
+ PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
+ PDEVICE_OBJECT Fdo = NULL;
+ ULONG DeviceExtensionSize;
NTSTATUS Status;
- while (Counter--) {
- Status = I8042ReadData(Data);
+ DPRINT("i8042AddDevice(%p %p)\n", DriverObject, Pdo);
- if (STATUS_SUCCESS == Status)
- return Status;
+ DriverExtension = (PI8042_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject);
- KeStallExecutionProcessor(50);
+ if (Pdo == NULL)
+ {
+ /* We're getting a NULL Pdo at the first call as
+ * we are a legacy driver. Ignore it */
+ return STATUS_SUCCESS;
+ }
+
+ /* Create new device object. As we don't know if the device would be a keyboard
+ * or a mouse, we have to allocate the biggest device extension. */
+ DeviceExtensionSize = MAX(sizeof(I8042_KEYBOARD_EXTENSION), sizeof(I8042_MOUSE_EXTENSION));
+ Status = IoCreateDevice(
+ DriverObject,
+ DeviceExtensionSize,
+ NULL,
+ Pdo->DeviceType,
+ FILE_DEVICE_SECURE_OPEN,
+ TRUE,
+ &Fdo);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+ goto cleanup;
}
- // Timed out
- return STATUS_IO_TIMEOUT;
-}
-VOID I8042Flush()
-{
- UCHAR Ignore;
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
+ RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
+ DeviceExtension->Type = Unknown;
+ DeviceExtension->Fdo = Fdo;
+ DeviceExtension->Pdo = Pdo;
+ DeviceExtension->PortDeviceExtension = &DriverExtension->Port;
+ Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
- 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;
+ Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+ return STATUS_SUCCESS;
- I8042Write(DevExt, I8042_DATA_PORT, Value);
+cleanup:
+ if (DeviceExtension && DeviceExtension->LowerDevice)
+ IoDetachDevice(DeviceExtension->LowerDevice);
+ if (Fdo)
+ IoDeleteDevice(Fdo);
+ return Status;
}
-/*
- * These functions are callbacks for filter driver custom
- * initialization routines.
- */
-NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
- UCHAR Port,
- UCHAR Value,
- BOOLEAN WaitForAck)
+VOID NTAPI
+i8042SendHookWorkItem(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context)
{
+ PI8042_HOOK_WORKITEM WorkItemData;
+ PFDO_DEVICE_EXTENSION FdoDeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ PDEVICE_OBJECT TopOfStack = NULL;
+ ULONG IoControlCode;
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ IO_STATUS_BLOCK IoStatus;
+ KEVENT Event;
+ PIRP NewIrp;
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;
- }
+ DPRINT("i8042SendHookWorkItem(%p %p)\n", DeviceObject, Context);
- if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
- {
- DPRINT1("Failed to write Value\n");
- return STATUS_IO_TIMEOUT;
- }
+ WorkItemData = (PI8042_HOOK_WORKITEM)Context;
+ FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ PortDeviceExtension = FdoDeviceExtension->PortDeviceExtension;
- 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;
+ switch (FdoDeviceExtension->Type)
+ {
+ case Keyboard:
+ {
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
+ IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
+ InputBuffer = &DeviceExtension->KeyboardHook;
+ InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
+ break;
}
- 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;
+ case Mouse:
+ {
+ PI8042_MOUSE_EXTENSION DeviceExtension;
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)FdoDeviceExtension;
+ IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
+ InputBuffer = &DeviceExtension->MouseHook;
+ InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
+ break;
}
- }
-
- 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;
+ default:
+ {
+ DPRINT1("Unknown FDO type %u\n", FdoDeviceExtension->Type);
+ ASSERT(FALSE);
+ WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
+ goto cleanup;
}
- 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;
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ TopOfStack = IoGetAttachedDeviceReference(DeviceObject);
- if (DevExt->CurrentIrp) {
- DevExt->CurrentIrp->IoStatus.Status = Result;
- IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
- IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
- DevExt->CurrentIrp = NULL;
- DevExt->CurrentIrpDevice = NULL;
+ NewIrp = IoBuildDeviceIoControlRequest(
+ IoControlCode,
+ TopOfStack,
+ InputBuffer,
+ InputBufferLength,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatus);
+
+ if (!NewIrp)
+ {
+ DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+ WorkItemData->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
}
-}
-
-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;
+ Status = IoCallDriver(TopOfStack, NewIrp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(
+ &Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = IoStatus.Status;
}
-
- 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 (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoCallDriver() failed with status 0x%08lx\n", Status);
+ goto cleanup;
}
-#if 0
- Status = IoCallDriver(
- WorkItemData->Target,
- NewIrp);
-
- if (STATUS_PENDING == Status)
- KeWaitForSingleObject(&Event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
-#endif
+ if (FdoDeviceExtension->Type == Keyboard)
+ {
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
- if (IsKbd) {
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
/* 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)) {
+ if (DeviceExtension->KeyboardHook.InitializationRoutine)
+ {
+ Status = DeviceExtension->KeyboardHook.InitializationRoutine(
+ DeviceExtension->KeyboardHook.Context,
+ PortDeviceExtension,
+ i8042SynchReadPort,
+ i8042SynchWritePortKbd,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status);
WorkItemData->Irp->IoStatus.Status = Status;
- goto hookworkitemdone;
+ goto cleanup;
}
}
- /* TODO: Now would be the right time to enable the interrupt */
-
- DevExt->KeyboardClaimed = TRUE;
- } else {
+ }
+#if 0
+ else
+ {
/* Mouse doesn't have this, but we need to send a
* reset to start the detection.
*/
KIRQL Irql;
- Irql = KeAcquireInterruptSpinLock(
- DevExt->HighestDIRQLInterrupt);
+ Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
- I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
- I8042Write(DevExt, I8042_DATA_PORT, 0xFF);
+ i8042Write(PortDeviceExtension, PortDeviceExtension->ControlPort, CTRL_WRITE_MOUSE);
+ i8042Write(PortDeviceExtension, PortDeviceExtension->DataPort, MOU_CMD_RESET);
- KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+ KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
+#endif
WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
-hookworkitemdone:
+cleanup:
+ if (TopOfStack != NULL)
+ ObDereferenceObject(TopOfStack);
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)
+static VOID NTAPI
+i8042StartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- if (!I8042StartIoKbd(DeviceObject, Irp)) {
- DPRINT1("Unhandled StartIo!\n");
- }
-}
+ PFDO_DEVICE_EXTENSION DeviceExtension;
-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");
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ switch (DeviceExtension->Type)
+ {
+ case Keyboard:
+ i8042KbdStartIo(DeviceObject, Irp);
+ break;
+ default:
+ DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
+ ASSERT(FALSE);
+ break;
}
-
- if (Status != STATUS_PENDING)
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return Status;
}
-static NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+/* Write the current byte of the packet. Returns FALSE in case
+ * of problems.
+ */
+static BOOLEAN
+i8042PacketWrite(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
- NTSTATUS Status;
-
- DPRINT ("I8042CreateDispatch\n");
-
- Status = STATUS_SUCCESS;
+ UCHAR Port = DeviceExtension->PacketPort;
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ if (Port)
+ {
+ if (!i8042Write(DeviceExtension,
+ DeviceExtension->ControlPort,
+ Port))
+ {
+ /* something is really wrong! */
+ DPRINT1("Failed to send packet byte!\n");
+ return FALSE;
+ }
+ }
- return Status;
+ return i8042Write(DeviceExtension,
+ DeviceExtension->DataPort,
+ DeviceExtension->Packet.Bytes[DeviceExtension->Packet.CurrentByte]);
}
-static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
+BOOLEAN
+i8042PacketIsr(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR Output)
{
- 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");
+ if (DeviceExtension->Packet.State == Idle)
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 */
+ switch (Output)
+ {
+ case KBD_RESEND:
+ DeviceExtension->PacketResends++;
+ if (DeviceExtension->PacketResends > DeviceExtension->Settings.ResendIterations)
+ {
+ DeviceExtension->Packet.State = Idle;
+ DeviceExtension->PacketComplete = TRUE;
+ DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
+ DeviceExtension->PacketResends = 0;
+ return TRUE;
+ }
+ DeviceExtension->Packet.CurrentByte--;
+ break;
+
+ case KBD_NACK:
+ DeviceExtension->Packet.State = Idle;
+ DeviceExtension->PacketComplete = TRUE;
+ DeviceExtension->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
+ DeviceExtension->PacketResends = 0;
+ return TRUE;
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
- DPRINT1("Can't set i8042 mode\n");
- return FALSE;
+ default:
+ DeviceExtension->PacketResends = 0;
}
- if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
- DPRINT1("Can't send i8042 mode\n");
- return FALSE;
+ if (DeviceExtension->Packet.CurrentByte >= DeviceExtension->Packet.ByteCount)
+ {
+ DeviceExtension->Packet.State = Idle;
+ DeviceExtension->PacketComplete = TRUE;
+ DeviceExtension->PacketResult = STATUS_SUCCESS;
+ return TRUE;
}
- /*
- * 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))
+ if (!i8042PacketWrite(DeviceExtension))
{
- Status = I8042ReadDataWait(DevExt, &Value);
- if (NT_SUCCESS(Status) && Value == 0)
- DevExt->MouseExists = TRUE;
+ DeviceExtension->Packet.State = Idle;
+ DeviceExtension->PacketComplete = TRUE;
+ DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
+ return TRUE;
}
+ DeviceExtension->Packet.CurrentByte++;
- return STATUS_SUCCESS;
+ return TRUE;
}
-static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
+/*
+ * This function starts a packet. It must be called with the
+ * correct DIRQL.
+ */
+NTSTATUS
+i8042StartPacket(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
+ IN PUCHAR Bytes,
+ IN ULONG ByteCount,
+ IN PIRP Irp)
{
+ KIRQL Irql;
NTSTATUS Status;
- Status = I8042BasicDetect(DevExt);
- if (!NT_SUCCESS(Status)) {
- DPRINT1("Basic keyboard detection failed: %x\n", Status);
- return Status;
- }
+ Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
- if (DevExt->MouseExists) {
- DPRINT("Aux port detected\n");
- DevExt->MouseExists = I8042DetectMouse(DevExt);
+ if (DeviceExtension->Packet.State != Idle)
+ {
+ Status = STATUS_DEVICE_BUSY;
+ goto done;
}
- 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);
+ switch (FdoDeviceExtension->Type)
+ {
+ case Keyboard: DeviceExtension->PacketPort = 0; break;
+ case Mouse: DeviceExtension->PacketPort = CTRL_WRITE_MOUSE; break;
+ default:
+ DPRINT1("Unknown FDO type %u\n", FdoDeviceExtension->Type);
+ ASSERT(FALSE);
+ Status = STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
+ DeviceExtension->Packet.Bytes = Bytes;
+ DeviceExtension->Packet.CurrentByte = 0;
+ DeviceExtension->Packet.ByteCount = ByteCount;
+ DeviceExtension->Packet.State = SendingBytes;
+ DeviceExtension->PacketResult = Status = STATUS_PENDING;
+ DeviceExtension->CurrentIrp = Irp;
+ DeviceExtension->CurrentIrpDevice = FdoDeviceExtension->Fdo;
+
+ if (!i8042PacketWrite(DeviceExtension))
+ {
+ Status = STATUS_IO_TIMEOUT;
+ DeviceExtension->Packet.State = Idle;
+ DeviceExtension->PacketResult = STATUS_ABANDONED;
+ goto done;
}
- if (DevExt->KeyboardExists) {
- DPRINT("Keyboard detected\n");
- I8042KeyboardEnable(DevExt);
- I8042KeyboardEnableInterrupt(DevExt);
- }
+ DeviceExtension->Packet.CurrentByte++;
+
+done:
+ KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
- if (DevExt->MouseExists) {
- DPRINT("Mouse detected\n");
- I8042MouseEnable(DevExt);
+ if (Status != STATUS_PENDING)
+ {
+ DeviceExtension->CurrentIrp = NULL;
+ DeviceExtension->CurrentIrpDevice = NULL;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
+ return Status;
+}
- return STATUS_SUCCESS;
+static NTSTATUS NTAPI
+IrpStub(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ KEBUGCHECK(0);
+ return STATUS_NOT_IMPLEMENTED;
}
-static NTSTATUS
-AddRegistryEntry(
- IN PCWSTR PortTypeName,
- IN PUNICODE_STRING DeviceName,
- IN PCWSTR RegistryPath)
+static NTSTATUS NTAPI
+i8042DeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- 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;
+ PFDO_DEVICE_EXTENSION DeviceExtension;
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;
- }
+ DPRINT("i8042DeviceControl(%p %p)\n", DeviceObject, Irp);
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
- if (!NT_SUCCESS(Status))
+ switch (DeviceExtension->Type)
{
- DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
- goto cleanup;
+ case Keyboard:
+ return i8042KbdDeviceControl(DeviceObject, Irp);
+ break;
+ default:
+ return IrpStub(DeviceObject, Irp);
}
- 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)
+static NTSTATUS NTAPI
+i8042InternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- 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;
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ ULONG ControlCode;
NTSTATUS Status;
- PDEVICE_EXTENSION DevExt;
- PFDO_DEVICE_EXTENSION FdoDevExt;
- PDEVICE_OBJECT Fdo;
- DPRINT("I8042AddDevice\n");
+ DPRINT("i8042InternalDeviceControl(%p %p)\n", DeviceObject, Irp);
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
- if (Pdo != NULL)
+ switch (DeviceExtension->Type)
{
- /* 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))
+ case Unknown:
{
- 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;
+ ControlCode = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode;
+ switch (ControlCode)
+ {
+ case IOCTL_INTERNAL_KEYBOARD_CONNECT:
+ Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
+ break;
+ case IOCTL_INTERNAL_MOUSE_CONNECT:
+ Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
+ break;
+ default:
+ DPRINT1("Unknown IO control code 0x%lx\n", ControlCode);
+ ASSERT(FALSE);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
}
-
- InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
- Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
+ break;
}
- else
- DevExt->KeyboardExists = FALSE;
+ case Keyboard:
+ Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
+ break;
+ case Mouse:
+ Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
+ break;
+ default:
+ DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
+ ASSERT(FALSE);
+ Status = STATUS_INTERNAL_ERROR;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ break;
}
- 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);
+ return Status;
+}
- if (!DevExt->MouseBuffer) {
- ExFreePoolWithTag(DevExt->KeyboardBuffer, TAG_I8042);
- DPRINT1("No memory for mouse buffer\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+NTSTATUS NTAPI
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ PI8042_DRIVER_EXTENSION DriverExtension;
+ ULONG i;
+ NTSTATUS Status;
- InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
- Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
- }
- else
- DevExt->MouseExists = FALSE;
+ Status = IoAllocateDriverObjectExtension(
+ DriverObject,
+ DriverObject,
+ sizeof(I8042_DRIVER_EXTENSION),
+ (PVOID*)&DriverExtension);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
+ return Status;
}
+ RtlZeroMemory(DriverExtension, sizeof(I8042_DRIVER_EXTENSION));
+ KeInitializeSpinLock(&DriverExtension->Port.SpinLock);
- 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);
+ Status = RtlDuplicateUnicodeString(
+ RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+ RegistryPath,
+ &DriverExtension->RegistryPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
+ return 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);
+ Status = ReadRegistryEntries(RegistryPath, &DriverExtension->Port.Settings);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
+ return 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");
+ DriverObject->DriverExtension->AddDevice = i8042AddDevice;
+ DriverObject->DriverStartIo = i8042StartIo;
- I8042RegistryPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
- I8042RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
- I8042RegistryPath.MaximumLength,
- TAG_I8042);
- if (I8042RegistryPath.Buffer == NULL) {
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ DriverObject->MajorFunction[i] = IrpStub;
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = i8042Create;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = i8042Cleanup;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = i8042Close;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = i8042DeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = i8042InternalDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_PNP] = i8042Pnp;
- RtlCopyUnicodeString(&I8042RegistryPath, RegistryPath);
- RtlAppendUnicodeToString(&I8042RegistryPath, L"\\Parameters");
- I8042RegistryPath.Buffer[I8042RegistryPath.Length / sizeof(WCHAR)] = 0;
+ if (IsFirstStageSetup())
+ return i8042AddLegacyKeyboard(DriverObject, RegistryPath);
-
-
- DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
- DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
- I8042InternalDeviceControl;
-
- DriverObject->DriverStartIo = I8042StartIo;
- DriverObject->DriverExtension->AddDevice = I8042AddDevice;
-
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
-#ifndef _I8042DRV_H
-#define _I8042DRV_H
+#ifndef _I8042PRT_H_
+#define _I8042PRT_H_
-#include <ntddk.h>
+#include <ntifs.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
+#include <ntddkbd.h>
+#include <bugcodes.h>
+#include <poclass.h>
/*-----------------------------------------------------
- * DeviceExtension
+ * Structures
* --------------------------------------------------*/
-typedef struct _COMMAND_CONTEXT
-{
- int NumInput;
- int CurInput;
- UCHAR * Input;
- int NumOutput;
- int CurOutput;
- UCHAR * Output;
- NTSTATUS Status;
- BOOLEAN GotAck;
- KEVENT Event;
+typedef enum
+{
+ dsStopped,
+ dsStarted,
+ dsPaused,
+ dsRemoved,
+ dsSurpriseRemoved
+} DEVICE_STATE;
- PVOID DevExt;
-} COMMAND_CONTEXT, *PCOMMAND_CONTEXT;
+typedef struct _I8042_SETTINGS
+{
+ /* Registry settings */
+ ULONG KeyboardDataQueueSize; /* done */
+ UNICODE_STRING KeyboardDeviceBaseName;
+ ULONG MouseDataQueueSize; /* done */
+ ULONG MouseResolution;
+ ULONG MouseSynchIn100ns;
+ ULONG NumberOfButtons;
+ UNICODE_STRING PointerDeviceBaseName;
+ ULONG PollStatusIterations; /* done */
+ ULONG OverrideKeyboardType;
+ ULONG OverrideKeyboardSubtype;
+ ULONG PollingIterations; /* done */
+ ULONG PollingIterationsMaximum;
+ ULONG ResendIterations; /* done */
+ ULONG SampleRate;
+ ULONG CrashOnCtrlScroll; /* done */
+} I8042_SETTINGS, *PI8042_SETTINGS;
typedef enum _MOUSE_TIMEOUT_STATE
{
TimeoutCancel
} MOUSE_TIMEOUT_STATE, *PMOUSE_TIMEOUT_STATE;
-/* TODO: part of this should be in the _ATTRIBUTES structs instead */
-typedef struct _I8042_SETTINGS
+typedef struct _INTERRUPT_DATA
{
- 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;
+ PKINTERRUPT Object;
+ ULONG Vector;
+ KIRQL Dirql;
+ KINTERRUPT_MODE InterruptMode;
+ BOOLEAN ShareInterrupt;
+ KAFFINITY Affinity;
+} INTERRUPT_DATA, *PINTERRUPT_DATA;
-typedef enum _I8042_MOUSE_TYPE
+#define WHEEL_DELTA 120
+
+struct _I8042_KEYBOARD_EXTENSION;
+typedef struct _I8042_KEYBOARD_EXTENSION *PI8042_KEYBOARD_EXTENSION;
+struct _I8042_MOUSE_EXTENSION;
+typedef struct _I8042_MOUSE_EXTENSION *PI8042_MOUSE_EXTENSION;
+
+/* PORT_DEVICE_EXTENSION.Flags */
+#define KEYBOARD_PRESENT 0x01 /* A keyboard is attached */
+#define MOUSE_PRESENT 0x02 /* A mouse is attached */
+#define KEYBOARD_CONNECTED 0x04 /* Keyboard received IOCTL_INTERNAL_KEYBOARD_CONNECT */
+#define MOUSE_CONNECTED 0x08 /* Mouse received IOCTL_INTERNAL_MOUSE_CONNECT */
+#define KEYBOARD_STARTED 0x04 /* Keyboard FDO received IRP_MN_START_DEVICE */
+#define MOUSE_STARTED 0x08 /* Mouse FDO received IRP_MN_START_DEVICE */
+#define KEYBOARD_INITIALIZED 0x10 /* Keyboard interrupt is connected */
+#define MOUSE_INITIALIZED 0x20 /* Mouse interrupt is connected */
+
+typedef struct _PORT_DEVICE_EXTENSION
{
- GenericPS2,
- Intellimouse,
- IntellimouseExplorer,
- Ps2pp
-} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
+ PUCHAR DataPort; /* Usually 0x60 */
+ PUCHAR ControlPort; /* Usually 0x64 */
+ I8042_SETTINGS Settings;
+ ULONG Flags;
+
+ PI8042_KEYBOARD_EXTENSION KeyboardExtension;
+ INTERRUPT_DATA KeyboardInterrupt;
+ PI8042_MOUSE_EXTENSION MouseExtension;
+ INTERRUPT_DATA MouseInterrupt;
+ PKINTERRUPT HighestDIRQLInterrupt;
+ KSPIN_LOCK SpinLock;
+ KIRQL HighestDirql;
+
+ OUTPUT_PACKET Packet;
+ ULONG PacketResends;
+ BOOLEAN PacketComplete;
+ NTSTATUS PacketResult;
+ UCHAR PacketBuffer[16];
+ UCHAR PacketPort;
+
+ PIRP CurrentIrp;
+ PDEVICE_OBJECT CurrentIrpDevice;
+} PORT_DEVICE_EXTENSION, *PPORT_DEVICE_EXTENSION;
+
+typedef struct _I8042_DRIVER_EXTENSION
+{
+ UNICODE_STRING RegistryPath;
+
+ PORT_DEVICE_EXTENSION Port;
+} I8042_DRIVER_EXTENSION, *PI8042_DRIVER_EXTENSION;
typedef enum _I8042_DEVICE_TYPE
{
+ Unknown,
Keyboard,
- Mouse
+ Mouse,
+ PhysicalDeviceObject
} I8042_DEVICE_TYPE, *PI8042_DEVICE_TYPE;
-typedef struct _I8042_DEVICE
+typedef struct _FDO_DEVICE_EXTENSION
{
- LIST_ENTRY ListEntry;
+ I8042_DEVICE_TYPE Type;
+ // Associated device object (FDO)
+ PDEVICE_OBJECT Fdo;
+ // Associated device object (PDO)
PDEVICE_OBJECT Pdo;
-} I8042_DEVICE, *PI8042_DEVICE;
+ // Lower device object
+ PDEVICE_OBJECT LowerDevice;
+ // Current state of the driver
+ DEVICE_STATE PnpState;
-typedef struct _DEVICE_EXTENSION
-{
- PDEVICE_OBJECT KeyboardObject;
- PDEVICE_OBJECT MouseObject;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
+typedef struct _I8042_KEYBOARD_EXTENSION
+{
+ FDO_DEVICE_EXTENSION Common;
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;
+ KDPC DpcKeyboard;
- 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;
+ PKEYBOARD_INPUT_DATA KeyboardBuffer;
ULONG KeysInBuffer;
+ /* Power keys items */
+ ULONG ReportedCaps;
+ ULONG NewCaps;
+ ULONG LastPowerKey;
+ UNICODE_STRING PowerInterfaceName;
+ PIO_WORKITEM PowerWorkItem;
+ PIRP PowerIrp;
+
+ /* Debug items */
+ ULONG ComboPosition;
+ PIO_WORKITEM DebugWorkItem;
+#ifdef __REACTOS__
+ ULONG DebugKey;
+ BOOLEAN TabPressed;
+#endif
+} I8042_KEYBOARD_EXTENSION;
+
+typedef enum _I8042_MOUSE_TYPE
+{
+ GenericPS2,
+ Intellimouse,
+ IntellimouseExplorer,
+ Ps2pp
+} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
+
+typedef struct _I8042_MOUSE_EXTENSION
+{
+ FDO_DEVICE_EXTENSION Common;
+ CONNECT_DATA MouseData;
+ INTERNAL_I8042_HOOK_MOUSE MouseHook;
+ KDPC DpcMouse;
+
MOUSE_ATTRIBUTES MouseAttributes;
MOUSE_STATE MouseState;
BOOLEAN MouseComplete;
MOUSE_RESET_SUBSTATE MouseResetState;
- MOUSE_INPUT_DATA *MouseBuffer;
+ PMOUSE_INPUT_DATA MouseBuffer;
ULONG MouseInBuffer;
USHORT MouseButtonState;
ULARGE_INTEGER MousePacketStartTime;
+ KTIMER TimerMouseTimeout;
+ KDPC DpcMouseTimeout;
+ MOUSE_TIMEOUT_STATE MouseTimeoutState;
+ BOOLEAN MouseTimeoutActive;
+
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;
+} I8042_MOUSE_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)
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#define KEYBOARD_POWER_CODE 0x5E
+#define KEYBOARD_SLEEP_CODE 0x5F
+#define KEYBOARD_WAKE_CODE 0x63
-/*
+/*-----------------------------------------------------
* 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 CTRL_SELF_TEST 0xAA
+#define CTRL_WRITE_MOUSE 0xD4
-#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
+ * --------------------------------------------------*/
+#define KBD_CMD_SET_LEDS 0xED
+#define KBD_CMD_GET_ID 0xF2
-/*
- * Keyboard responces
- */
+/*-----------------------------------------------------
+ * Keyboard responses
+ * --------------------------------------------------*/
-#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 MOU_OBF 0x20
#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 commands
+ * --------------------------------------------------*/
+
+#define MOU_CMD_GET_ID 0xF2
+#define MOU_CMD_RESET 0xFF
+
+/*-----------------------------------------------------
* Mouse responses
- */
+ * --------------------------------------------------*/
+
#define MOUSE_ACK 0xFA
#define MOUSE_ERROR 0xFC
#define MOUSE_NACK 0xFE
-/* i8042prt.c */
-extern UNICODE_STRING I8042RegistryPath;
+/*-----------------------------------------------------
+ * Prototypes
+ * --------------------------------------------------*/
-NTSTATUS I8042ReadData(UCHAR *Data);
+/* createclose.c */
-NTSTATUS I8042ReadStatus(UCHAR *Status);
+VOID NTAPI
+i8042SendHookWorkItem(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context);
-NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *Data);
+NTSTATUS NTAPI
+i8042Create(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-VOID I8042Flush();
+NTSTATUS NTAPI
+i8042Cleanup(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
- UCHAR Value,
- UCHAR SelectCmd);
+NTSTATUS NTAPI
+i8042Close(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
- UCHAR Port,
- UCHAR Value,
- BOOLEAN WaitForAck);
+/* keyboard.c */
-NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
- PDEVICE_OBJECT Device,
- PUCHAR Bytes,
- ULONG ByteCount,
- PIRP Irp);
+NTSTATUS NTAPI
+i8042SynchWritePortKbd(
+ IN PVOID Context,
+ IN UCHAR Value,
+ IN BOOLEAN WaitForAck);
-BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
- UCHAR Output);
+BOOLEAN
+i8042KbdStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt);
+NTSTATUS
+i8042KbdDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
- PVOID Context);
+NTSTATUS
+i8042KbdInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data);
+BOOLEAN NTAPI
+i8042KbdInterruptService(
+ IN PKINTERRUPT Interrupt,
+ PVOID Context);
-NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
- PUNICODE_STRING RegistryPath);
+/* i8042prt.c */
-/* keyboard.c */
-VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
- UCHAR Value);
+NTSTATUS NTAPI
+i8042AddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT Pdo);
-NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
- UCHAR Value,
- BOOLEAN WaitForAck);
+BOOLEAN
+i8042PacketIsr(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR Output);
-BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
- VOID * Context);
+NTSTATUS
+i8042StartPacket(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
+ IN PUCHAR Bytes,
+ IN ULONG ByteCount,
+ IN PIRP Irp);
-VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2);
+/* misc.c */
-BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS NTAPI
+ForwardIrpAndForget(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject,
- PIRP Irp);
+NTSTATUS
+ForwardIrpAndWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt);
+/* mouse.c */
-BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt);
+VOID
+i8042MouHandle(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN UCHAR Output);
-BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt);
+VOID
+i8042MouHandleButtons(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN USHORT Mask);
-/* registry.c */
-VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
- PDEVICE_EXTENSION DevExt);
+NTSTATUS
+i8042MouInitialize(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension);
-/* mouse.c */
-VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2);
+NTSTATUS
+i8042MouInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2);
+BOOLEAN NTAPI
+i8042MouInterruptService(
+ IN PKINTERRUPT Interrupt,
+ PVOID Context);
-BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
- VOID *Context);
+VOID NTAPI
+i8042MouQueuePacket(
+ IN PVOID Context);
-NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject,
- PIRP Irp);
+/* pnp.c */
-VOID STDCALL I8042QueueMousePacket(PVOID Context);
+BOOLEAN
+i8042ChangeMode(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR FlagsToDisable,
+ IN UCHAR FlagsToEnable);
-VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
- USHORT Mask);
+NTSTATUS NTAPI
+i8042Pnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
-VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
- UCHAR Output);
+/* ps2pp.c */
+VOID
+i8042MouHandlePs2pp(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN UCHAR Input);
+
+/* readwrite.c */
+
+VOID
+i8042Flush(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension);
+
+VOID
+i8042IsrWritePort(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR Value,
+ IN UCHAR SelectCmd OPTIONAL);
+
+NTSTATUS
+i8042ReadData(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR StatusFlags,
+ OUT PUCHAR Data);
+#define i8042ReadKeyboardData(DeviceExtension, Data) \
+ i8042ReadData(DeviceExtension, KBD_OBF, Data)
+#define i8042ReadMouseData(DeviceExtension, Data) \
+ i8042ReadData(DeviceExtension, MOU_OBF, Data)
+
+NTSTATUS
+i8042ReadDataWait(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR Data);
+
+NTSTATUS
+i8042ReadStatus(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR Status);
+
+NTSTATUS NTAPI
+i8042SynchReadPort(
+ IN PVOID Context,
+ IN PUCHAR Value,
+ IN BOOLEAN WaitForAck);
+
+NTSTATUS NTAPI
+i8042SynchWritePort(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR Port,
+ IN UCHAR Value,
+ IN BOOLEAN WaitForAck);
+
+BOOLEAN
+i8042Write(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN PUCHAR addr,
+ IN UCHAR data);
-BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt);
-BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt);
-BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt);
+/* registry.c */
-/* ps2pp.c */
-VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input);
+NTSTATUS
+ReadRegistryEntries(
+ IN PUNICODE_STRING RegistryPath,
+ OUT PI8042_SETTINGS Settings);
+
+/* setup.c */
+
+BOOLEAN
+IsFirstStageSetup(
+ VOID);
+
+NTSTATUS
+i8042AddLegacyKeyboard(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
-#endif // _KEYBOARD_H_
+#endif // _I8042PRT_H_
<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>createclose.c</file>
<file>i8042prt.c</file>
<file>keyboard.c</file>
+ <file>misc.c</file>
<file>mouse.c</file>
+ <file>pnp.c</file>
<file>ps2pp.c</file>
+ <file>readwrite.c</file>
<file>registry.c</file>
+ <file>setup.c</file>
<file>i8042prt.rc</file>
</module>
#define REACTOS_VERSION_DLL
-#define REACTOS_STR_FILE_DESCRIPTION "I8042 Port Device Driver\0"
+#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>
/*
- * 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
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/keyboard.c
+ * PURPOSE: Keyboard specific functions
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+ Copyright Jason Filby (jasonfilby@yahoo.com)
+ Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ****************************************************************/
/* 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 };
-
+/* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
USHORT NumberOfIndicatorKeys;
INDICATOR_LIST IndicatorList[3];
{0x45, KEYBOARD_NUM_LOCK_ON},
{0x46, KEYBOARD_SCROLL_LOCK_ON}}};
-static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
- PVOID Context);
-
/* FUNCTIONS *****************************************************************/
+#ifdef __REACTOS__
+/* Debug stuff */
+VOID NTAPI
+KdpServiceDispatcher(IN ULONG Code, IN PVOID Context1, IN PVOID Context2);
+#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
+
+static VOID NTAPI
+i8042DebugWorkItem(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context)
+{
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ ULONG Key;
+
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+ Key = InterlockedExchange((PLONG)&DeviceExtension->DebugKey, 0);
+
+ DPRINT("Debug key: 0x%02x\n", Key);
+
+ if (!Key)
+ return;
+
+ /* We hope kernel would understand this. If
+ * that's not the case, nothing would happen.
+ */
+ KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
+}
+#endif
+
/*
* These functions are callbacks for filter driver custom interrupt
* service routines.
*/
-VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
- UCHAR Value)
+/*static VOID NTAPI
+i8042KbdIsrWritePort(
+ IN PVOID Context,
+ IN UCHAR Value)
{
- I8042IsrWritePort(Context, Value, 0);
-}
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
-static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
+ if (DeviceExtension->KeyboardHook.IsrWritePort)
+ {
+ DeviceExtension->KeyboardHook.IsrWritePort(
+ DeviceExtension->KeyboardHook.CallContext,
+ Value);
+ }
+ else
+ i8042IsrWritePort(Context, Value, 0);
+}*/
+
+static VOID NTAPI
+i8042KbdQueuePacket(
+ IN 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) {
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+
+ if (DeviceExtension->KeyboardHook.QueueKeyboardPacket)
+ {
+ DeviceExtension->KeyboardHook.QueueKeyboardPacket(
+ DeviceExtension->KeyboardHook.CallContext);
+ return;
+ }
+
+ DeviceExtension->KeyComplete = TRUE;
+ DeviceExtension->KeysInBuffer++;
+ if (DeviceExtension->KeysInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize)
+ {
DPRINT1("Keyboard buffer overflow\n");
- DevExt->KeysInBuffer--;
+ DeviceExtension->KeysInBuffer--;
}
DPRINT("Irq completes key\n");
- KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+ KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
}
/*
* These functions are callbacks for filter driver custom
* initialization routines.
*/
-NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
- UCHAR Value,
- BOOLEAN WaitForAck)
+NTSTATUS NTAPI
+i8042SynchWritePortKbd(
+ IN PVOID Context,
+ IN UCHAR Value,
+ IN BOOLEAN WaitForAck)
{
- return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
- 0,
- Value,
- WaitForAck);
+ return i8042SynchWritePort(
+ (PPORT_DEVICE_EXTENSION)Context,
+ 0,
+ Value,
+ WaitForAck);
}
-BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
- VOID * Context)
+/*
+ * Process the keyboard internal device requests
+ * returns FALSE if it doesn't understand the
+ * call so someone else can handle it.
+ */
+BOOLEAN
+i8042KbdStartIo(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- 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);
+ PIO_STACK_LOCATION Stack;
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ BOOLEAN Result = FALSE;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+
+ switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_KEYBOARD_SET_INDICATORS:
+ {
+ DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
- if (STATUS_SUCCESS != Status) {
- DPRINT("Spurious I8042 interrupt\n");
- return FALSE;
+ PortDeviceExtension->PacketBuffer[0] = KBD_CMD_SET_LEDS;
+ PortDeviceExtension->PacketBuffer[1] = 0;
+ if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
+ PortDeviceExtension->PacketBuffer[1] |= KBD_LED_CAPS;
+
+ if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
+ PortDeviceExtension->PacketBuffer[1] |= KBD_LED_NUM;
+
+ if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
+ PortDeviceExtension->PacketBuffer[1] |= KBD_LED_SCROLL;
+
+ i8042StartPacket(
+ PortDeviceExtension,
+ &DeviceExtension->Common,
+ PortDeviceExtension->PacketBuffer,
+ 2,
+ Irp);
+ break;
+ }
+ default:
+ {
+ DPRINT("Unknown ioctl code 0x%lx\n",
+ Stack->Parameters.DeviceIoControl.IoControlCode);
+ ASSERT(FALSE);
+ }
}
- DPRINT("Got: %x\n", Output);
+ return Result;
+}
- if (DevExt->KeyboardHook.IsrRoutine) {
- HookReturn = DevExt->KeyboardHook.IsrRoutine(
- DevExt->KeyboardHook.Context,
- InputData,
- &DevExt->Packet,
- PortStatus,
- &Output,
- &HookContinue,
- &DevExt->KeyboardScanState);
+static VOID
+i8042PacketDpc(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ BOOLEAN FinishIrp = FALSE;
+ KIRQL Irql;
+ NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
- if (!HookContinue)
- return HookReturn;
+ /* If the interrupt happens before this is setup, the key
+ * was already in the buffer. Too bad! */
+ if (!DeviceExtension->HighestDIRQLInterrupt)
+ return;
+
+ Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
+
+ if (DeviceExtension->Packet.State == Idle
+ && DeviceExtension->PacketComplete)
+ {
+ FinishIrp = TRUE;
+ Result = DeviceExtension->PacketResult;
+ DeviceExtension->PacketComplete = FALSE;
}
- if (I8042PacketIsr(DevExt, Output)) {
- if (DevExt->PacketComplete) {
- DPRINT("Packet complete\n");
- KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
- }
- DPRINT("Irq eaten by packet\n");
- return TRUE;
+ KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
+
+ if (!FinishIrp)
+ return;
+
+ if (DeviceExtension->CurrentIrp)
+ {
+ DeviceExtension->CurrentIrp->IoStatus.Status = Result;
+ IoCompleteRequest(DeviceExtension->CurrentIrp, IO_NO_INCREMENT);
+ IoStartNextPacket(DeviceExtension->CurrentIrpDevice, FALSE);
+ DeviceExtension->CurrentIrp = NULL;
+ DeviceExtension->CurrentIrpDevice = NULL;
}
+}
- DPRINT("Irq is keyboard input\n");
+static VOID NTAPI
+i8042PowerWorkItem(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context)
+{
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ NTSTATUS Status;
- if (Normal == DevExt->KeyboardScanState) {
- switch (Output) {
- case 0xe0:
- DevExt->KeyboardScanState = GotE0;
- return TRUE;
- case 0xe1:
- DevExt->KeyboardScanState = GotE1;
- return TRUE;
- default:
- ;/* continue */
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+
+ /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
+
+ /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
+ if (DeviceExtension->NewCaps != DeviceExtension->ReportedCaps)
+ {
+ if (DeviceExtension->PowerInterfaceName.MaximumLength == 0)
+ {
+ /* We have never registred this interface ; do it */
+ Status = IoRegisterDeviceInterface(
+ DeviceExtension->Common.Pdo,
+ &GUID_DEVICE_SYS_BUTTON,
+ NULL,
+ &DeviceExtension->PowerInterfaceName);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We can't do more yet, ignore the keypress... */
+ DPRINT("IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
+ Status);
+ DeviceExtension->PowerInterfaceName.MaximumLength = 0;
+ return;
+ }
+ }
+ else
+ {
+ /* Disable the interface. Once activated again, capabilities would be asked again */
+ Status = IoSetDeviceInterfaceState(
+ &DeviceExtension->PowerInterfaceName,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Ignore the key press... */
+ DPRINT("Disabling interface %wZ failed with status 0x%08lx\n",
+ &DeviceExtension->PowerInterfaceName, Status);
+ return;
+ }
+ }
+ /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
+ * so we can report new capability */
+ Status = IoSetDeviceInterfaceState(
+ &DeviceExtension->PowerInterfaceName,
+ TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Ignore the key press... */
+ DPRINT("Enabling interface %wZ failed with status 0x%08lx\n",
+ &DeviceExtension->PowerInterfaceName, Status);
+ return;
}
}
- InputData->Flags = 0;
+ /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
+ if (DeviceExtension->PowerIrp)
+ {
+ PULONG pEvent = (PULONG)DeviceExtension->PowerIrp->AssociatedIrp.SystemBuffer;
+
+ DeviceExtension->PowerIrp->IoStatus.Status = STATUS_SUCCESS;
+ DeviceExtension->PowerIrp->IoStatus.Information = sizeof(ULONG);
+ *pEvent = DeviceExtension->LastPowerKey;
- switch (DevExt->KeyboardScanState) {
- case GotE0:
- InputData->Flags |= KEY_E0;
- break;
- case GotE1:
- InputData->Flags |= KEY_E1;
- break;
- default:
- ;
+ IoCompleteRequest(DeviceExtension->PowerIrp, IO_NO_INCREMENT);
+ DeviceExtension->PowerIrp = NULL;
}
- DevExt->KeyboardScanState = Normal;
+}
- if (Output & 0x80)
- InputData->Flags |= KEY_BREAK;
- else
- InputData->Flags |= KEY_MAKE;
+/* Return TRUE if it was a power key */
+static BOOLEAN
+HandlePowerKeys(
+ IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
+{
+ PKEYBOARD_INPUT_DATA InputData;
+ ULONG KeyPress;
- InputData->MakeCode = Output & 0x7f;
+ InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer - 1;
+ if (!(InputData->Flags & KEY_E0))
+ return FALSE;
- I8042QueueKeyboardPacket(DevExt->KeyboardObject);
+ if (InputData->Flags & KEY_BREAK)
+ /* We already took care of the key press */
+ return TRUE;
+ switch (InputData->MakeCode)
+ {
+ case 0x52: /* VK_INSERT */
+ DPRINT1("FIXME: Remove debug code\n");
+ case KEYBOARD_POWER_CODE:
+ KeyPress = SYS_BUTTON_POWER;
+ break;
+ case KEYBOARD_SLEEP_CODE:
+ KeyPress = SYS_BUTTON_SLEEP;
+ break;
+
+ case KEYBOARD_WAKE_CODE:
+ KeyPress = SYS_BUTTON_WAKE;
+ break;
+ default:
+ return FALSE;
+ }
+
+ /* Our work can only be done at passive level, so use a workitem */
+ DeviceExtension->NewCaps |= KeyPress;
+ DeviceExtension->LastPowerKey = KeyPress;
+ IoQueueWorkItem(
+ DeviceExtension->PowerWorkItem,
+ &i8042PowerWorkItem,
+ DelayedWorkQueue,
+ DeviceExtension);
return TRUE;
}
-VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2)
+static VOID NTAPI
+i8042KbdDpcRoutine(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
{
- PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
ULONG KeysTransferred = 0;
ULONG KeysInBufferCopy;
KIRQL Irql;
- I8042PacketDpc(DevExt);
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeferredContext;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
- if (!DevExt->KeyComplete)
+ if (HandlePowerKeys(DeviceExtension))
+ {
+ DeviceExtension->KeyComplete = FALSE;
return;
+ }
+ i8042PacketDpc(PortDeviceExtension);
+ if (!DeviceExtension->KeyComplete)
+ return;
/* We got the interrupt as it was being enabled, too bad */
- if (!DevExt->HighestDIRQLInterrupt)
+ if (!PortDeviceExtension->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);
+ Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
+
+ DeviceExtension->KeyComplete = FALSE;
+ KeysInBufferCopy = DeviceExtension->KeysInBuffer;
+
+ KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
+
+#ifdef __REACTOS__
+ if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
+ {
+ PKEYBOARD_INPUT_DATA InputData;
+ InputData = DeviceExtension->KeyboardBuffer + KeysInBufferCopy - 1;
+
+ /* Test for TAB + key combination */
+ if (InputData->MakeCode == 0x0F)
+ DeviceExtension->TabPressed = !(InputData->Flags & KEY_BREAK);
+ else if (DeviceExtension->TabPressed)
+ {
+ DeviceExtension->DebugKey = InputData->MakeCode;
+ DeviceExtension->TabPressed = FALSE;
+
+ IoQueueWorkItem(
+ DeviceExtension->DebugWorkItem,
+ &i8042DebugWorkItem,
+ DelayedWorkQueue,
+ DeviceExtension);
}
}
+#endif
- DPRINT ("Send a key\n");
+ DPRINT("Send a key\n");
- if (!DevExt->KeyboardData.ClassService)
+ if (!DeviceExtension->KeyboardData.ClassService)
return;
- ((PSERVICE_CALLBACK_ROUTINE) DevExt->KeyboardData.ClassService)(
- DevExt->KeyboardData.ClassDeviceObject,
- DevExt->KeyboardBuffer,
- DevExt->KeyboardBuffer + KeysInBufferCopy,
- &KeysTransferred);
+ DPRINT("Sending %lu key(s)\n", KeysInBufferCopy);
+ (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->KeyboardData.ClassService)(
+ DeviceExtension->KeyboardData.ClassDeviceObject,
+ DeviceExtension->KeyboardBuffer,
+ DeviceExtension->KeyboardBuffer + KeysInBufferCopy,
+ &KeysTransferred);
- Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
- DevExt->KeysInBuffer -= KeysTransferred;
- KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+ Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
+ DeviceExtension->KeysInBuffer -= KeysTransferred;
+ KeReleaseInterruptSpinLock(PortDeviceExtension->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];
- }
+#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
- 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.
+ * Runs the keyboard IOCTL dispatch.
*/
-BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS
+i8042KbdDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN 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;
+ PIO_STACK_LOCATION Stack;
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ Irp->IoStatus.Information = 0;
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
+
+ switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_GET_SYS_BUTTON_CAPS:
+ {
+ /* Part of GUID_DEVICE_SYS_BUTTON interface */
+ PULONG pCaps;
+ DPRINT("IOCTL_GET_SYS_BUTTON_CAPS\n");
+
+ if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
+ Status = STATUS_INVALID_PARAMETER;
+ else
+ {
+ pCaps = (PULONG)Irp->AssociatedIrp.SystemBuffer;
+ *pCaps = DeviceExtension->NewCaps;
+ DeviceExtension->ReportedCaps = DeviceExtension->NewCaps;
+ Irp->IoStatus.Information = sizeof(ULONG);
+ Status = STATUS_SUCCESS;
+ }
+ break;
+ }
+ case IOCTL_GET_SYS_BUTTON_EVENT:
+ {
+ /* Part of GUID_DEVICE_SYS_BUTTON interface */
+ PIRP WaitingIrp;
+ DPRINT("IOCTL_GET_SYS_BUTTON_EVENT\n");
+
+ if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
+ Status = STATUS_INVALID_PARAMETER;
+ else
+ {
+ /* FIXME: Race condition here:
+ * If an interrupt comes before we can mark the Irp
+ * as pending, it might be possible to complete the
+ * Irp before pending it, leading to a crash! */
+ WaitingIrp = InterlockedCompareExchangePointer(
+ &DeviceExtension->PowerIrp,
+ Irp,
+ NULL);
+ /* Check if an Irp is already pending */
+ if (WaitingIrp != NULL)
+ {
+ /* Unable to have a 2nd pending IRP for this IOCTL */
+ DPRINT("Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ Status = STATUS_PENDING;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ DPRINT("IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
+ Stack->Parameters.DeviceIoControl.IoControlCode);
+ ASSERT(FALSE);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
}
- return TRUE;
+ Irp->IoStatus.Status = Status;
+ if (Status == STATUS_PENDING)
+ IoMarkIrpPending(Irp);
+ else
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ /* Special case for IOCTL_GET_SYS_BUTTON_CAPS */
+ if (Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_SYS_BUTTON_CAPS
+ && DeviceExtension->PowerIrp)
+ {
+ /* Also complete the pending IOCTL_GET_SYS_BUTTON_EVENT Irp */
+ PULONG pEvent = (PULONG)DeviceExtension->PowerIrp->AssociatedIrp.SystemBuffer;
+
+ DeviceExtension->PowerIrp->IoStatus.Status = STATUS_SUCCESS;
+ DeviceExtension->PowerIrp->IoStatus.Information = sizeof(ULONG);
+ *pEvent = DeviceExtension->LastPowerKey;
+ DeviceExtension->LastPowerKey = 0;
+
+ IoCompleteRequest(DeviceExtension->PowerIrp, IO_NO_INCREMENT);
+ DeviceExtension->PowerIrp = NULL;
+ }
+ return Status;
}
/*
* 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)
+NTSTATUS
+i8042KbdInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- PIO_STACK_LOCATION Stk;
- PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
- PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
- DPRINT("InternalDeviceControl\n");
+ PIO_STACK_LOCATION Stack;
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
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;
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
+ switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_INTERNAL_KEYBOARD_CONNECT:
{
- PIO_WORKITEM WorkItem;
- PI8042_HOOK_WORKITEM WorkItemData;
+ SIZE_T Size;
+ PIO_WORKITEM WorkItem = NULL;
+ PI8042_HOOK_WORKITEM WorkItemData = NULL;
+
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
+ if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+ DeviceExtension->KeyboardData =
+ *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
+
+ /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
WorkItem = IoAllocateWorkItem(DeviceObject);
- if (!WorkItem) {
- DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
- "Can't allocate work item\n");
- Irp->IoStatus.Status =
- STATUS_INSUFFICIENT_RESOURCES;
- goto intcontfailure;
+ if (!WorkItem)
+ {
+ DPRINT("IoAllocateWorkItem() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
}
-
- 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 = ExAllocatePool(
+ NonPagedPool,
+ sizeof(I8042_HOOK_WORKITEM));
+ if (!WorkItemData)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
}
WorkItemData->WorkItem = WorkItem;
- WorkItemData->Target =
- DevExt->KeyboardData.ClassDeviceObject;
WorkItemData->Irp = Irp;
+ /* Initialize extension */
+ DeviceExtension->Common.Type = Keyboard;
+ Size = DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize * sizeof(KEYBOARD_INPUT_DATA);
+ DeviceExtension->KeyboardBuffer = ExAllocatePool(
+ NonPagedPool,
+ Size);
+ if (!DeviceExtension->KeyboardBuffer)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+ RtlZeroMemory(DeviceExtension->KeyboardBuffer, Size);
+ KeInitializeDpc(
+ &DeviceExtension->DpcKeyboard,
+ i8042KbdDpcRoutine,
+ DeviceExtension);
+ DeviceExtension->PowerWorkItem = IoAllocateWorkItem(DeviceObject);
+ if (!DeviceExtension->PowerWorkItem)
+ {
+ DPRINT("IoAllocateWorkItem() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+ DeviceExtension->DebugWorkItem = IoAllocateWorkItem(DeviceObject);
+ if (!DeviceExtension->DebugWorkItem)
+ {
+ DPRINT("IoAllocateWorkItem() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+ DeviceExtension->Common.PortDeviceExtension->KeyboardExtension = DeviceExtension;
+ DeviceExtension->Common.PortDeviceExtension->Flags |= KEYBOARD_CONNECTED;
+
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;
- }
+ i8042SendHookWorkItem,
+ DelayedWorkQueue,
+ WorkItemData);
+ Status = STATUS_PENDING;
+ break;
- 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;
+cleanup:
+ if (DeviceExtension->KeyboardBuffer)
+ ExFreePool(DeviceExtension->KeyboardBuffer);
+ if (DeviceExtension->PowerWorkItem)
+ IoFreeWorkItem(DeviceExtension->PowerWorkItem);
+ if (DeviceExtension->DebugWorkItem)
+ IoFreeWorkItem(DeviceExtension->DebugWorkItem);
+ if (WorkItem)
+ IoFreeWorkItem(WorkItem);
+ if (WorkItemData)
+ ExFreePool(WorkItemData);
+ break;
}
- 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;
+ case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
+ /* MSDN says that operation is to implemented.
+ * To implement it, we just have to do:
+ * DeviceExtension->KeyboardData.ClassService = NULL;
+ */
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
}
- 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;
+ case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
+ /* Nothing to do here */
+ Status = STATUS_SUCCESS;
+ break;
}
- 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;
+ case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
+
+ /* We should check the UnitID, but it's kind of pointless as
+ * all keyboards are supposed to have the same one
+ */
+ if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ RtlCopyMemory(
+ Irp->AssociatedIrp.SystemBuffer,
+ &IndicatorTranslation,
+ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
+ Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
+ Status = STATUS_SUCCESS;
+ }
+ break;
}
+ case IOCTL_KEYBOARD_QUERY_INDICATORS:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
- 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;
+ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ RtlCopyMemory(
+ Irp->AssociatedIrp.SystemBuffer,
+ &DeviceExtension->KeyboardIndicators,
+ sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+ Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
+ Status = STATUS_SUCCESS;
+ }
+ break;
}
+ case IOCTL_KEYBOARD_SET_INDICATORS:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
- 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;
+ if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ RtlCopyMemory(
+ &DeviceExtension->KeyboardIndicators,
+ Irp->AssociatedIrp.SystemBuffer,
+ sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+ Status = STATUS_PENDING;
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ }
+ break;
+ }
+ default:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
+ Stack->Parameters.DeviceIoControl.IoControlCode);
+ ASSERT(FALSE);
+ return ForwardIrpAndForget(DeviceObject, Irp);
}
- 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;
+ Irp->IoStatus.Status = Status;
+ if (Status != STATUS_PENDING)
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return 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.
+/*
+ * Call the customization hook. The ToReturn 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)
*/
-
-BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
+static BOOLEAN
+i8042KbdCallIsrHook(
+ IN PI8042_KEYBOARD_EXTENSION DeviceExtension,
+ IN UCHAR Status,
+ IN UCHAR Input,
+ OUT PBOOLEAN ToReturn)
{
- UCHAR Value;
- NTSTATUS Status;
+ BOOLEAN HookReturn, HookContinue;
- DPRINT("Enable keyboard\n");
+ HookContinue = FALSE;
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
- DPRINT1("Can't read i8042 mode\n");
- return FALSE;
- }
+ if (DeviceExtension->KeyboardHook.IsrRoutine)
+ {
+ HookReturn = DeviceExtension->KeyboardHook.IsrRoutine(
+ DeviceExtension->KeyboardHook.Context,
+ DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer,
+ &DeviceExtension->Common.PortDeviceExtension->Packet,
+ Status,
+ &Input,
+ &HookContinue,
+ &DeviceExtension->KeyboardScanState);
- 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;
+ if (!HookContinue)
+ {
+ *ToReturn = HookReturn;
+ return TRUE;
+ }
}
-
- return TRUE;
+ return FALSE;
}
-BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
+BOOLEAN NTAPI
+i8042KbdInterruptService(
+ IN PKINTERRUPT Interrupt,
+ PVOID Context)
{
- UCHAR Value;
+ PI8042_KEYBOARD_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ PKEYBOARD_INPUT_DATA InputData;
+ ULONG Counter;
+ UCHAR PortStatus, Output;
+ BOOLEAN ToReturn = FALSE;
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;
- }
+ DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+ InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer;
+ Counter = PortDeviceExtension->Settings.PollStatusIterations;
- 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;
+ while (Counter)
+ {
+ Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("i8042ReadStatus() failed with status 0x%08lx\n", Status);
+ return FALSE;
+ }
+ Status = i8042ReadKeyboardData(PortDeviceExtension, &Output);
+ if (NT_SUCCESS(Status))
+ break;
+ KeStallExecutionProcessor(1);
+ Counter--;
}
-
- if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
- DPRINT1("Can't send i8042 mode\n");
+ if (Counter == 0)
+ {
+ DPRINT("Spurious i8042 keyboard interrupt\n");
return FALSE;
}
- return TRUE;
-}
-
-BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
-{
- NTSTATUS Status;
- UCHAR Value;
- UCHAR Value2;
- ULONG RetryCount = 10;
+ DPRINT("Got: 0x%02x\n", Output);
- 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;
- }
+ if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
+ {
+ /* Test for CTRL + SCROLL LOCK twice */
+ static UCHAR ScanCodes[] = { 0x1d, 0x46, 0x46, 0 };
- 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;
+ if (!(Output & 0x80))
+ {
+ if ((Output & 0x7f) == ScanCodes[DeviceExtension->ComboPosition])
+ {
+ DeviceExtension->ComboPosition++;
+ if (ScanCodes[DeviceExtension->ComboPosition] == 0)
+ KeBugCheck(MANUALLY_INITIATED_CRASH);
+ }
+ else if ((Output & 0x7f) == ScanCodes[0])
+ DeviceExtension->ComboPosition = 1;
+ else
+ DeviceExtension->ComboPosition = 0;
+ }
}
- DPRINT("Keyboard ID: 0x%x 0x%x\n", Value, Value2);
+ if (i8042KbdCallIsrHook(DeviceExtension, PortStatus, Output, &ToReturn))
+ return ToReturn;
-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;
+ if (i8042PacketIsr(PortDeviceExtension, Output))
+ {
+ if (PortDeviceExtension->PacketComplete)
+ {
+ DPRINT("Packet complete\n");
+ KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
+ }
+ DPRINT("Irq eaten by packet\n");
+ return TRUE;
}
- // Turn on translation
-
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
- DPRINT1("Can't read i8042 mode\n");
- return FALSE;
- }
+ DPRINT("Irq is keyboard input\n");
- Status = I8042ReadDataWait(DevExt, &Value);
- if (!NT_SUCCESS(Status)) {
- DPRINT1("No response after read i8042 mode\n");
- return FALSE;
+ if (DeviceExtension->KeyboardScanState == Normal)
+ {
+ switch (Output)
+ {
+ case 0xe0:
+ DeviceExtension->KeyboardScanState = GotE0;
+ return TRUE;
+ case 0xe1:
+ DeviceExtension->KeyboardScanState = GotE1;
+ return TRUE;
+ default:
+ break;
+ }
}
- Value |= 0x40; // enable keyboard translation
-
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
- DPRINT1("Can't set i8042 mode\n");
- return FALSE;
+ /* Update InputData */
+ InputData->Flags = 0;
+ switch (DeviceExtension->KeyboardScanState)
+ {
+ case GotE0:
+ InputData->Flags |= KEY_E0;
+ break;
+ case GotE1:
+ InputData->Flags |= KEY_E1;
+ break;
+ default:
+ break;
}
+ DeviceExtension->KeyboardScanState = Normal;
+ if (Output & 0x80)
+ InputData->Flags |= KEY_BREAK;
+ else
+ InputData->Flags |= KEY_MAKE;
+ InputData->MakeCode = Output & 0x7f;
+ InputData->Reserved = 0;
- if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
- DPRINT1("Can't send i8042 mode\n");
- return FALSE;
- }
+ i8042KbdQueuePacket(DeviceExtension);
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
+/*
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/misc.c
+ * PURPOSE: Misceallenous operations
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+static NTSTATUS NTAPI
+ForwardIrpAndWaitCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context)
+{
+ if (Irp->PendingReturned)
+ KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+ForwardIrpAndWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+ KEVENT Event;
+ NTSTATUS Status;
+
+ ASSERT(LowerDevice);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+
+ DPRINT("Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName);
+ IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
+
+ Status = IoCallDriver(LowerDevice, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ if (NT_SUCCESS(Status))
+ Status = Irp->IoStatus.Status;
+ }
+
+ return Status;
+}
+
+NTSTATUS NTAPI
+ForwardIrpAndForget(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+
+ ASSERT(LowerDevice);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(LowerDevice, Irp);
+}
/*
- * 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
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/mouse.c
+ * PURPOSE: Mouse specific functions
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+ Copyright Jason Filby (jasonfilby@yahoo.com)
+ Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ****************************************************************/
#define NDEBUG
#include <debug.h>
+/* FUNCTIONS *****************************************************************/
+
/*
* These functions are callbacks for filter driver custom interrupt
* service routines.
*/
-static VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
- UCHAR Value)
+static VOID NTAPI
+i8042MouIsrWritePort(
+ IN PVOID Context,
+ IN UCHAR Value)
{
- I8042IsrWritePort(Context, Value, 0xD4);
-}
+ PI8042_MOUSE_EXTENSION DeviceExtension;
-#if 0
-static NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
- UCHAR Value,
- BOOLEAN WaitForAck)
-{
- return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
- 0xD4,
- Value,
- WaitForAck);
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
+
+ if (DeviceExtension->MouseHook.IsrWritePort)
+ {
+ DeviceExtension->MouseHook.IsrWritePort(
+ DeviceExtension->MouseHook.CallContext,
+ Value);
+ }
+ else
+ i8042IsrWritePort(Context, Value, 0xD4);
}
-#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)
+VOID NTAPI
+i8042MouQueuePacket(
+ IN PVOID Context)
{
- ULARGE_INTEGER Now;
+ PI8042_MOUSE_EXTENSION DeviceExtension;
- if (DevExt->MouseState == MouseExpectingACK ||
- DevExt->MouseState == MouseResetting)
- return;
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
- Now.QuadPart = KeQueryInterruptTime();
+ if (DeviceExtension->MouseHook.QueueMousePacket)
+ {
+ DeviceExtension->MouseHook.QueueMousePacket(
+ DeviceExtension->MouseHook.CallContext);
+ return;
+ }
- 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;
- }
+ DeviceExtension->MouseComplete = TRUE;
+ DeviceExtension->MouseInBuffer++;
+ if (DeviceExtension->MouseInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize)
+ {
+ DPRINT1("Mouse buffer overflow\n");
+ DeviceExtension->MouseInBuffer--;
}
- if (DevExt->MouseState == MouseIdle)
- DevExt->MousePacketStartTime.QuadPart = Now.QuadPart;
+ DPRINT("Irq completes mouse packet\n");
+ KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
}
-/*
- * 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)
+VOID
+i8042MouHandle(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN UCHAR Output)
{
- BOOLEAN HookReturn, HookContinue;
+ PMOUSE_INPUT_DATA MouseInput;
+ CHAR Scroll;
- HookContinue = FALSE;
+ MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
- 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;
-}
+ switch (DeviceExtension->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;
+ }
-static BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
- UCHAR Status,
- PUCHAR Value)
-{
- BOOLEAN ToReturn = FALSE;
+ MouseInput->Buttons = 0;
+ MouseInput->RawButtons = 0;
+ MouseInput->Flags = MOUSE_MOVE_RELATIVE;
- if (I8042MouseCallIsrHook(DevExt, Status, Value, &ToReturn))
- return ToReturn;
+ /* Note how we ignore the overflow bits, like Windows
+ * is said to do. There's no reasonable thing to do
+ * anyway.
+ */
- if (MouseResetting != DevExt->MouseState) {
- return FALSE;
- }
- DevExt->MouseTimeoutState = TimeoutStart;
+ 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;
+
+ DeviceExtension->MouseState = XMovement;
+ break;
- 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;
+ case XMovement:
+ if (MouseInput->LastX)
+ MouseInput->LastX = (LONG) Output - 256;
+ else
+ MouseInput->LastX = Output;
+
+ DeviceExtension->MouseState = YMovement;
break;
- case 0x03:
- case 0x04:
- DevExt->MouseAttributes.MouseIdentifier =
- WHEELMOUSE_I8042_HARDWARE;
+
+ 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 (DeviceExtension->MouseType == GenericPS2 ||
+ DeviceExtension->MouseType == Ps2pp)
+ {
+ i8042MouHandleButtons(
+ DeviceExtension,
+ MOUSE_LEFT_BUTTON_DOWN |
+ MOUSE_RIGHT_BUTTON_DOWN |
+ MOUSE_MIDDLE_BUTTON_DOWN);
+ i8042MouQueuePacket(DeviceExtension);
+ DeviceExtension->MouseState = MouseIdle;
+ }
+ else
+ {
+ DeviceExtension->MouseState = ZMovement;
+ }
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--;
- }
+ case ZMovement:
+ Scroll = Output & 0x0f;
+ if (Scroll & 8)
+ Scroll |= 0xf0;
- DPRINT("Irq completes mouse packet\n");
- KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
+ if (Scroll)
+ {
+ MouseInput->RawButtons |= MOUSE_WHEEL;
+ MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
+ }
+
+ if (DeviceExtension->MouseType == IntellimouseExplorer)
+ {
+ if (Output & 16)
+ MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+ if (Output & 32)
+ MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+ }
+ i8042MouHandleButtons(
+ DeviceExtension,
+ MOUSE_LEFT_BUTTON_DOWN |
+ MOUSE_RIGHT_BUTTON_DOWN |
+ MOUSE_MIDDLE_BUTTON_DOWN |
+ MOUSE_BUTTON_4_DOWN |
+ MOUSE_BUTTON_5_DOWN);
+ i8042MouQueuePacket(DeviceExtension);
+ DeviceExtension->MouseState = MouseIdle;
+ break;
+
+ default:
+ DPRINT1("Unexpected state 0x%u!\n", DeviceExtension->MouseState);
+ ASSERT(FALSE);
+ }
}
/*
* 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)
+VOID
+i8042MouHandleButtons(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN USHORT Mask)
{
- PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
- DevExt->MouseInBuffer;
- USHORT NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
- USHORT ButtonDiff = (NewButtonData ^ DevExt->MouseButtonState) & Mask;
+ PMOUSE_INPUT_DATA MouseInput;
+ USHORT NewButtonData;
+ USHORT ButtonDiff;
+
+ MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
+ NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
+ ButtonDiff = (NewButtonData ^ DeviceExtension->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);
+ (((~(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);
+ DPRINT("Left raw/up/down: %u/%u/%u\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);
+ DeviceExtension->MouseButtonState =
+ (DeviceExtension->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");
- }
-}
+static NTSTATUS OldInitialization(PPORT_DEVICE_EXTENSION); /* FIXME */
-BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
- VOID *Context)
+/* Does lastest initializations for the mouse. This method
+ * is called just before connecting the interrupt.
+ */
+NTSTATUS
+i8042MouInitialize(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension)
{
- 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;
- }
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
- 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;
- }
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
- if (DevExt->MouseType == Ps2pp)
- I8042MouseHandlePs2pp(DevExt, Output);
- else
- I8042MouseHandle(DevExt, Output);
+/* FIXME */ OldInitialization(PortDeviceExtension);
- return TRUE;
+ return STATUS_SUCCESS;
}
-VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
- PVOID DeferredContext,
- PVOID SystemArgument1,
- PVOID SystemArgument2)
+static VOID NTAPI
+i8042MouDpcRoutine(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
{
- PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+ PI8042_MOUSE_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
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;
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+
+ switch (DeviceExtension->MouseTimeoutState)
+ {
+ case TimeoutStart:
+ {
+ DeviceExtension->MouseTimeoutState = NoChange;
+ if (DeviceExtension->MouseTimeoutActive &&
+ !KeCancelTimer(&DeviceExtension->TimerMouseTimeout))
+ {
+ /* The timer fired already, give up */
+ DeviceExtension->MouseTimeoutActive = FALSE;
+ return;
+ }
+
+ Timeout.QuadPart = -15000000; /* 1.5 seconds, should be enough */
+
+ KeSetTimer(
+ &DeviceExtension->TimerMouseTimeout,
+ Timeout,
+ &DeviceExtension->DpcMouseTimeout);
+ DeviceExtension->MouseTimeoutActive = TRUE;
return;
}
- Timeout.QuadPart = -15000000;
- /* 1.5 seconds, should be enough */
+ case TimeoutCancel:
+ {
+ DeviceExtension->MouseTimeoutState = NoChange;
+ KeCancelTimer(&DeviceExtension->TimerMouseTimeout);
+ DeviceExtension->MouseTimeoutActive = FALSE;
+ }
- 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 */ ;
+ default:
+ ;/* nothing, don't want a warning */
}
/* Should be unlikely */
- if (!DevExt->MouseComplete)
+ if (!DeviceExtension->MouseComplete)
return;
- Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+ Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
- DevExt->MouseComplete = FALSE;
- MouseInBufferCopy = DevExt->MouseInBuffer;
+ DeviceExtension->MouseComplete = FALSE;
+ MouseInBufferCopy = DeviceExtension->MouseInBuffer;
- KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+ KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
- DPRINT ("Send a mouse packet\n");
+ DPRINT("Send a mouse packet\n");
- if (!DevExt->MouseData.ClassService)
+ if (!DeviceExtension->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);
+ DPRINT("Sending %lu mouse move(s)\n", MouseInBufferCopy);
+ (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->MouseData.ClassService)(
+ DeviceExtension->MouseData.ClassDeviceObject,
+ DeviceExtension->MouseBuffer,
+ DeviceExtension->MouseBuffer + MouseInBufferCopy,
+ &MouseTransferred);
+
+ Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
+ DeviceExtension->MouseInBuffer -= MouseTransferred;
+ if (DeviceExtension->MouseInBuffer)
+ RtlMoveMemory(
+ DeviceExtension->MouseBuffer,
+ DeviceExtension->MouseBuffer + MouseTransferred,
+ DeviceExtension->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
+ KeReleaseInterruptSpinLock(PortDeviceExtension->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)
+static VOID NTAPI
+i8042DpcRoutineMouseTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
{
- PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
+ PI8042_MOUSE_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
KIRQL Irql;
- Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
- DPRINT1("Mouse initialization timeout! (substate %x) "
- "Disabling mouse.\n",
- DevExt->MouseResetState);
+ Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
- if (!I8042MouseDisable(DevExt)) {
- DPRINT1("Failed to disable mouse.\n");
- }
+ DPRINT1("Mouse initialization timeout! (substate %x). Disabling mouse.\n",
+ DeviceExtension->MouseResetState);
- DevExt->MouseExists = FALSE;
+ i8042Flush(PortDeviceExtension);
+ i8042ChangeMode(PortDeviceExtension, CCB_MOUSE_INT_ENAB, CCB_MOUSE_DISAB);
+ i8042Flush(PortDeviceExtension);
- KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
-}
+ PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
-/*
- * 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;
+ KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
-#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)
+NTSTATUS
+i8042MouInternalDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
{
- PIO_STACK_LOCATION Stk;
- PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
- PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
-
- DPRINT("InternalDeviceControl\n");
+ PIO_STACK_LOCATION Stack;
+ PI8042_MOUSE_EXTENSION DeviceExtension;
+ NTSTATUS Status;
+ Stack = IoGetCurrentIrpStackLocation(Irp);
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;
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)DeviceObject->DeviceExtension;
+ switch (Stack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case IOCTL_INTERNAL_MOUSE_CONNECT:
{
- PIO_WORKITEM WorkItem;
- PI8042_HOOK_WORKITEM WorkItemData;
+ SIZE_T Size;
+ PIO_WORKITEM WorkItem = NULL;
+ PI8042_HOOK_WORKITEM WorkItemData = NULL;
+
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
+ if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ DeviceExtension->MouseData =
+ *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
+ /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
WorkItem = IoAllocateWorkItem(DeviceObject);
- if (!WorkItem) {
- DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
- "Can't allocate work item\n");
- Irp->IoStatus.Status =
- STATUS_INSUFFICIENT_RESOURCES;
- goto intcontfailure;
+ if (!WorkItem)
+ {
+ DPRINT("IoAllocateWorkItem() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
}
-
- 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 = ExAllocatePool(
+ NonPagedPool,
+ sizeof(I8042_HOOK_WORKITEM));
+ if (!WorkItemData)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
}
WorkItemData->WorkItem = WorkItem;
- WorkItemData->Target =
- DevExt->MouseData.ClassDeviceObject;
WorkItemData->Irp = Irp;
+ /* Initialize extension */
+ DeviceExtension->Common.Type = Mouse;
+ Size = DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA);
+ DeviceExtension->MouseBuffer = ExAllocatePool(
+ NonPagedPool,
+ Size);
+ if (!DeviceExtension->MouseBuffer)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+ RtlZeroMemory(DeviceExtension->MouseBuffer, Size);
+ DeviceExtension->MouseAttributes.InputDataQueueLength =
+ DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize;
+ KeInitializeDpc(
+ &DeviceExtension->DpcMouse,
+ i8042MouDpcRoutine,
+ DeviceExtension);
+ KeInitializeDpc(
+ &DeviceExtension->DpcMouseTimeout,
+ i8042DpcRoutineMouseTimeout,
+ DeviceExtension);
+ KeInitializeTimer(&DeviceExtension->TimerMouseTimeout);
+ DeviceExtension->Common.PortDeviceExtension->MouseExtension = DeviceExtension;
+ DeviceExtension->Common.PortDeviceExtension->Flags |= MOUSE_CONNECTED;
+
IoMarkIrpPending(Irp);
- DevExt->MouseState = MouseResetting;
- DevExt->MouseResetState = 1100;
IoQueueWorkItem(WorkItem,
- I8042SendHookWorkItem,
- DelayedWorkQueue,
- WorkItemData);
+ i8042SendHookWorkItem,
+ DelayedWorkQueue,
+ WorkItemData);
+ Status = STATUS_PENDING;
+ break;
- Irp->IoStatus.Status = STATUS_PENDING;
+cleanup:
+ if (DeviceExtension->MouseBuffer)
+ ExFreePool(DeviceExtension->MouseBuffer);
+ if (WorkItem)
+ IoFreeWorkItem(WorkItem);
+ if (WorkItemData)
+ ExFreePool(WorkItemData);
+ break;
}
-
- 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;
+ case IOCTL_INTERNAL_MOUSE_DISCONNECT:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
+ /* MSDN says that operation is to implemented.
+ * To implement it, we just have to do:
+ * DeviceExtension->MouseData.ClassService = NULL;
+ */
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
}
- if (!DevExt->MouseInterruptObject) {
- Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
- goto intcontfailure;
+ case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
+ /* Nothing to do here */
+ Status = STATUS_SUCCESS;
+ break;
}
-
- 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;
+ default:
+ {
+ DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
+ Stack->Parameters.DeviceIoControl.IoControlCode);
+ ASSERT(FALSE);
+ return ForwardIrpAndForget(DeviceObject, Irp);
}
- 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;
+ Irp->IoStatus.Status = Status;
+ if (Status != STATUS_PENDING)
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
}
-BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
+/* 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
+i8042MouInputTestTimeout(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension)
{
- UCHAR Value;
- NTSTATUS Status;
+ ULARGE_INTEGER Now;
- DPRINT("Enabling mouse\n");
+ if (DeviceExtension->MouseState == MouseExpectingACK ||
+ DeviceExtension->MouseState == MouseResetting)
+ return;
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
- DPRINT1("Can't read i8042 mode\n");
- return FALSE;
- }
+ Now.QuadPart = KeQueryInterruptTime();
- Status = I8042ReadDataWait(DevExt, &Value);
- if (!NT_SUCCESS(Status)) {
- DPRINT1("No response after read i8042 mode\n");
- return FALSE;
+ if (DeviceExtension->MouseState != MouseIdle) {
+ /* Check if the last byte came too long ago */
+ if (Now.QuadPart - DeviceExtension->MousePacketStartTime.QuadPart >
+ DeviceExtension->Common.PortDeviceExtension->Settings.MouseSynchIn100ns)
+ {
+ DPRINT("Mouse input packet timeout\n");
+ DeviceExtension->MouseState = MouseIdle;
+ }
}
- Value &= ~(0x20); // don't disable mouse
- Value |= 0x02; // enable mouse interrupts
+ if (DeviceExtension->MouseState == MouseIdle)
+ DeviceExtension->MousePacketStartTime.QuadPart = Now.QuadPart;
+}
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
- DPRINT1("Can't set i8042 mode\n");
- return FALSE;
+/*
+ * Call the customization hook. The ToReturn 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
+i8042MouCallIsrHook(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN UCHAR Status,
+ IN UCHAR Input,
+ OUT PBOOLEAN ToReturn)
+{
+ BOOLEAN HookReturn, HookContinue;
+
+ HookContinue = FALSE;
+
+ if (DeviceExtension->MouseHook.IsrRoutine)
+ {
+ DPRINT1("IsrRoutine(%p %p %p 0x%x 0x%x %p %lu %lu)\n",
+ DeviceExtension->MouseHook.Context, DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
+ &DeviceExtension->Common.PortDeviceExtension->Packet, Status, &Input, &HookContinue,
+ DeviceExtension->MouseState, DeviceExtension->MouseResetState);
+ HookReturn = DeviceExtension->MouseHook.IsrRoutine(
+ DeviceExtension->MouseHook.Context,
+ DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
+ &DeviceExtension->Common.PortDeviceExtension->Packet,
+ Status,
+ &Input,
+ &HookContinue,
+ &DeviceExtension->MouseState,
+ &DeviceExtension->MouseResetState);
+ DPRINT1("IsrRoutine(%p %p %p 0x%x 0x%x %p %lu %lu)\n",
+ DeviceExtension->MouseHook.Context, DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
+ &DeviceExtension->Common.PortDeviceExtension->Packet, Status, &Input, &HookContinue,
+ DeviceExtension->MouseState, DeviceExtension->MouseResetState);
+
+ if (!HookContinue)
+ {
+ *ToReturn = HookReturn;
+ return TRUE;
+ }
}
+ return FALSE;
+}
+
+static BOOLEAN
+i8042MouResetIsr(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN UCHAR Status,
+ IN UCHAR Value)
+{
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ BOOLEAN ToReturn = FALSE;
+
+ if (i8042MouCallIsrHook(DeviceExtension, Status, Value, &ToReturn))
+ return ToReturn;
- if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
- DPRINT1("Can't send i8042 mode\n");
+ if (MouseResetting != DeviceExtension->MouseState)
return FALSE;
- }
+ DeviceExtension->MouseTimeoutState = TimeoutStart;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
- return TRUE;
+ switch (DeviceExtension->MouseResetState)
+ {
+ case 1100: /* the first ack, drop it. */
+ DeviceExtension->MouseResetState = ExpectingReset;
+ return TRUE;
+ case ExpectingReset:
+ /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
+ if (0xAA == Value)
+ {
+ DeviceExtension->MouseResetState++;
+ }
+ else
+ {
+ PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
+ DeviceExtension->MouseState = MouseIdle;
+ DPRINT("Mouse returned bad reset reply: %x (expected aa)\n", Value);
+ }
+ return TRUE;
+ case ExpectingResetId:
+ if (0x00 == Value)
+ {
+ DeviceExtension->MouseResetState++;
+ DeviceExtension->MouseType = GenericPS2;
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF2);
+ }
+ else
+ {
+ PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
+ DeviceExtension->MouseState = MouseIdle;
+ DPRINT1("Mouse returned bad reset reply part two: %x (expected 0)\n", Value);
+ }
+ return TRUE;
+ case ExpectingGetDeviceIdACK:
+ if (MOUSE_ACK == Value)
+ {
+ DeviceExtension->MouseResetState++;
+ }
+ else if (MOUSE_NACK == Value || MOUSE_ERROR == Value)
+ {
+ DeviceExtension->MouseResetState++;
+ /* Act as if 00 (normal mouse) was received */
+ DPRINT("Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value, MOUSE_ACK);
+ i8042MouResetIsr(DeviceExtension, Status, 0);
+ }
+ return TRUE;
+ case ExpectingGetDeviceIdValue:
+ switch (Value)
+ {
+ case 0x02:
+ DeviceExtension->MouseAttributes.MouseIdentifier =
+ BALLPOINT_I8042_HARDWARE;
+ break;
+ case 0x03:
+ case 0x04:
+ DeviceExtension->MouseAttributes.MouseIdentifier =
+ WHEELMOUSE_I8042_HARDWARE;
+ break;
+ default:
+ DeviceExtension->MouseAttributes.MouseIdentifier =
+ MOUSE_I8042_HARDWARE;
+ }
+ DeviceExtension->MouseResetState++;
+ i8042MouIsrWritePort(PortDeviceExtension, 0xE8);
+ return TRUE;
+ case ExpectingSetResolutionDefaultACK:
+ DeviceExtension->MouseResetState++;
+ i8042MouIsrWritePort(PortDeviceExtension, 0x00);
+ return TRUE;
+ case ExpectingSetResolutionDefaultValueACK:
+ DeviceExtension->MouseResetState = ExpectingSetScaling1to1ACK;
+ i8042MouIsrWritePort(PortDeviceExtension, 0xE6);
+ return TRUE;
+ case ExpectingSetScaling1to1ACK:
+ case ExpectingSetScaling1to1ACK2:
+ DeviceExtension->MouseResetState++;
+ i8042MouIsrWritePort(PortDeviceExtension, 0xE6);
+ return TRUE;
+ case ExpectingSetScaling1to1ACK3:
+ DeviceExtension->MouseResetState++;
+ i8042MouIsrWritePort(PortDeviceExtension, 0xE9);
+ return TRUE;
+ case ExpectingReadMouseStatusACK:
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case ExpectingReadMouseStatusByte1:
+ DeviceExtension->MouseLogiBuffer[0] = Value;
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case ExpectingReadMouseStatusByte2:
+ DeviceExtension->MouseLogiBuffer[1] = Value;
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case ExpectingReadMouseStatusByte3:
+ DeviceExtension->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 (DeviceExtension->MouseLogiBuffer[1])
+ {
+ DeviceExtension->MouseAttributes.NumberOfButtons =
+ DeviceExtension->MouseLogiBuffer[1];
+ DeviceExtension->MouseType = Ps2pp;
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
+ /* TODO: Go through EnableWheel and Enable5Buttons */
+ return TRUE;
+ }
+ DeviceExtension->MouseResetState = EnableWheel;
+ i8042MouResetIsr(DeviceExtension, Status, Value);
+ return TRUE;
+ case EnableWheel:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState = 1001;
+ return TRUE;
+ case 1001:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xC8);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1002:
+ case 1004:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1003:
+ i8042MouIsrWritePort(PortDeviceExtension, 0x64);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1005:
+ i8042MouIsrWritePort(PortDeviceExtension, 0x50);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1006:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF2);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1007:
+ /* Ignore ACK */
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1008:
+ if (0x03 == Value) {
+ /* It's either an Intellimouse or Intellimouse Explorer. */
+ DeviceExtension->MouseAttributes.NumberOfButtons = 3;
+ DeviceExtension->MouseAttributes.MouseIdentifier =
+ WHEELMOUSE_I8042_HARDWARE;
+ DeviceExtension->MouseType = Intellimouse;
+ DeviceExtension->MouseResetState = Enable5Buttons;
+ i8042MouResetIsr(DeviceExtension, Status, Value);
+ }
+ else
+ {
+ /* Just set the default settings and be done */
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
+ }
+ return TRUE;
+ case Enable5Buttons:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState = 1021;
+ return TRUE;
+ case 1022:
+ case 1024:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1021:
+ case 1023:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xC8);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1025:
+ i8042MouIsrWritePort(PortDeviceExtension, 0x50);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1026:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF2);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case 1027:
+ if (0x04 == Value)
+ {
+ DeviceExtension->MouseAttributes.NumberOfButtons = 5;
+ DeviceExtension->MouseAttributes.MouseIdentifier =
+ WHEELMOUSE_I8042_HARDWARE;
+ DeviceExtension->MouseType = IntellimouseExplorer;
+ }
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF3);
+ DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
+ return TRUE;
+ case ExpectingSetSamplingRateACK:
+ i8042MouIsrWritePort(PortDeviceExtension,
+ (UCHAR)DeviceExtension->MouseAttributes.SampleRate);
+ DeviceExtension->MouseResetState++;
+ return TRUE;
+ case ExpectingSetSamplingRateValueACK:
+ if (MOUSE_NACK == Value)
+ {
+ i8042MouIsrWritePort(PortDeviceExtension, 0x3C);
+ DeviceExtension->MouseAttributes.SampleRate = PortDeviceExtension->Settings.SampleRate;
+ DeviceExtension->MouseResetState = 1040;
+ return TRUE;
+ }
+ case 1040: /* Fallthrough */
+ i8042MouIsrWritePort(PortDeviceExtension, 0xE8);
+ DeviceExtension->MouseResetState = ExpectingFinalResolutionACK;
+ return TRUE;
+ case ExpectingFinalResolutionACK:
+ i8042MouIsrWritePort(PortDeviceExtension,
+ (UCHAR)(PortDeviceExtension->Settings.MouseResolution & 0xff));
+ DPRINT("Mouse resolution %lu\n",
+ PortDeviceExtension->Settings.MouseResolution);
+ DeviceExtension->MouseResetState = ExpectingFinalResolutionValueACK;
+ return TRUE;
+ case ExpectingFinalResolutionValueACK:
+ i8042MouIsrWritePort(PortDeviceExtension, 0xF4);
+ DeviceExtension->MouseResetState = ExpectingEnableACK;
+ return TRUE;
+ case ExpectingEnableACK:
+ DeviceExtension->MouseState = MouseIdle;
+ DeviceExtension->MouseTimeoutState = TimeoutCancel;
+ DPRINT("Mouse type = %u\n", DeviceExtension->MouseType);
+ return TRUE;
+ default:
+ if (DeviceExtension->MouseResetState < 100 || DeviceExtension->MouseResetState > 999)
+ DPRINT1("MouseResetState went out of range: %lu\n", DeviceExtension->MouseResetState);
+ return FALSE;
+ }
}
-BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
+BOOLEAN NTAPI
+i8042MouInterruptService(
+ IN PKINTERRUPT Interrupt,
+ PVOID Context)
{
- UCHAR Value;
+ PI8042_MOUSE_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ ULONG Counter;
+ UCHAR Output, PortStatus;
NTSTATUS Status;
- DPRINT("Disabling mouse\n");
+ DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+ Counter = PortDeviceExtension->Settings.PollStatusIterations;
- 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;
+ while (Counter)
+ {
+ Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("i8042ReadStatus() failed with status 0x%08lx\n", Status);
+ return FALSE;
+ }
+ Status = i8042ReadMouseData(PortDeviceExtension, &Output);
+ if (NT_SUCCESS(Status))
+ break;
+ KeStallExecutionProcessor(1);
+ Counter--;
}
-
- Status = I8042ReadDataWait(DevExt, &Value);
- if (!NT_SUCCESS(Status)) {
- DPRINT1("No response after read i8042 mode\n");
+ if (Counter == 0)
+ {
+ DPRINT("Spurious i8042 mouse interrupt\n");
return FALSE;
}
- Value |= 0x20; // don't disable mouse
- Value &= ~(0x02); // enable mouse interrupts
+ DPRINT("Got: 0x%02x\n", Output);
- if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
- DPRINT1("Can't set i8042 mode\n");
- return FALSE;
+ if (i8042PacketIsr(PortDeviceExtension, Output))
+ {
+ if (PortDeviceExtension->PacketComplete)
+ {
+ DPRINT("Packet complete\n");
+ KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
+ }
+ DPRINT("Irq eaten by packet\n");
+ return TRUE;
}
- if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
- DPRINT1("Can't send i8042 mode\n");
- return FALSE;
+ DPRINT("Irq is mouse input\n");
+
+ i8042MouInputTestTimeout(DeviceExtension);
+
+ if (i8042MouResetIsr(DeviceExtension, PortStatus, Output))
+ {
+ DPRINT("Handled by ResetIsr or hooked Isr\n");
+ if (NoChange != DeviceExtension->MouseTimeoutState) {
+ KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
+ }
+ return TRUE;
}
- I8042Flush();
- /* Just to be (kind of) sure; if the mouse would
- * say something while we are disabling it, these bytes would
- * block the keyboard.
- */
+ if (DeviceExtension->MouseType == Ps2pp)
+ i8042MouHandlePs2pp(DeviceExtension, Output);
+ else
+ i8042MouHandle(DeviceExtension, Output);
return TRUE;
}
-BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt)
+/* ================================================
+ * FIXME: this part is taken from psaux.sys driver,
+ * and doesn't follow the coding style of this file
+ * ===============================================*/
+
+#define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8
+#define PSMOUSE_CMD_ENABLE 0x00f4
+#define PSMOUSE_CMD_GETID (0x0200 | MOU_CMD_GET_ID)
+#define PSMOUSE_CMD_RESET_BAT (0x0200 | MOU_CMD_RESET)
+#define PSMOUSE_RET_ACK MOUSE_ACK
+#define PSMOUSE_RET_NAK MOUSE_NACK
+#define MOUSE_INTERRUPTS_ON (CCB_TRANSLATE | \
+ CCB_SYSTEM_FLAG | \
+ CCB_MOUSE_INT_ENAB)
+
+typedef struct _I8042_MOUSE_EXTENSION_OLD
{
- BOOLEAN Ok = TRUE;
- NTSTATUS Status;
- UCHAR Value;
- UCHAR ExpectedReply[] = { 0xFA, 0xAA, 0x00 };
- unsigned ReplyByte;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ UCHAR pkt[8];
+ UCHAR ack;
+ UINT RepliesExpected;
+} I8042_MOUSE_EXTENSION_OLD, *PI8042_MOUSE_EXTENSION_OLD;
+
+/* Sends a byte to the mouse */
+static INT SendByte(
+ IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension,
+ IN UCHAR byte)
+{
+ INT timeout = 100; /* 100 msec */
+ UCHAR scancode;
+ LARGE_INTEGER Millisecond_Timeout;
+
+ Millisecond_Timeout.QuadPart = -10000L;
+
+ DeviceExtension->ack = 0;
- if (! I8042Write(DevExt, I8042_CTRL_PORT, 0xD4) ||
- ! I8042Write(DevExt, I8042_DATA_PORT, 0xFF))
+ i8042IsrWritePort(DeviceExtension->PortDeviceExtension, byte, CTRL_WRITE_MOUSE);
+ while ((DeviceExtension->ack == 0) && timeout--)
{
- DPRINT1("Failed to write reset command to mouse\n");
- Ok = FALSE;
+ if (i8042ReadKeyboardData(DeviceExtension->PortDeviceExtension, &scancode))
+ {
+ switch(scancode)
+ {
+ case PSMOUSE_RET_ACK:
+ DeviceExtension->ack = 1;
+ break;
+ case PSMOUSE_RET_NAK:
+ DeviceExtension->ack = -1;
+ break;
+ default:
+ DeviceExtension->ack = 1; /* Workaround for mice which don't ACK the Get ID command */
+ if (DeviceExtension->RepliesExpected)
+ DeviceExtension->pkt[--DeviceExtension->RepliesExpected] = scancode;
+ break;
+ }
+ return (INT)(-(DeviceExtension->ack <= 0));
+ }
+ KeDelayExecutionThread(KernelMode, FALSE, &Millisecond_Timeout);
}
+ return (INT)(-(DeviceExtension->ack <= 0));
+}
+
+/* Send a PS/2 command to the mouse. */
+static INT SendCommand(
+ IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension,
+ IN PUCHAR param,
+ IN INT command)
+{
+ LARGE_INTEGER Millisecond_Timeout;
+ UCHAR scancode;
+ INT timeout = 500; /* 500 msec */
+ UCHAR send = (command >> 12) & 0xf;
+ UCHAR receive = (command >> 8) & 0xf;
+ UCHAR i;
- for (ReplyByte = 0;
- ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]) && Ok;
- ReplyByte++)
+ Millisecond_Timeout.QuadPart = -10000L;
+
+ DeviceExtension->RepliesExpected = receive;
+ if (command == PSMOUSE_CMD_RESET_BAT)
+ timeout = 2000; /* 2 sec */
+
+ if (command & 0xff)
+ if (SendByte(DeviceExtension, command & 0xff))
+ return (INT)(DeviceExtension->RepliesExpected = 0) - 1;
+
+ for (i = 0; i < send; i++)
+ if (SendByte(DeviceExtension, param[i]))
+ return (INT)(DeviceExtension->RepliesExpected = 0) - 1;
+
+ while (DeviceExtension->RepliesExpected && timeout--)
{
- Status = I8042ReadDataWait(DevExt, &Value);
- if (! NT_SUCCESS(Status))
+ if (DeviceExtension->RepliesExpected == 1 && command == PSMOUSE_CMD_RESET_BAT)
+ timeout = 100;
+
+ if (DeviceExtension->RepliesExpected == 1 && command == PSMOUSE_CMD_GETID &&
+ DeviceExtension->pkt[1] != 0xab && DeviceExtension->pkt[1] != 0xac)
{
- DPRINT1("No ACK after mouse reset, status 0x%08x\n",
- Status);
- Ok = FALSE;
+ DeviceExtension->RepliesExpected = 0;
+ break;
}
- else if (Value != ExpectedReply[ReplyByte])
+
+ if (i8042ReadKeyboardData(DeviceExtension->PortDeviceExtension, &scancode))
{
- DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
- Value, ExpectedReply[ReplyByte]);
- Ok = FALSE;
+ DeviceExtension->pkt[--DeviceExtension->RepliesExpected] = scancode;
}
+
+ KeDelayExecutionThread (KernelMode, FALSE, &Millisecond_Timeout);
}
- if (! Ok)
+ for (i = 0; i < receive; i++)
+ param[i] = DeviceExtension->pkt[(receive - 1) - i];
+
+ if (DeviceExtension->RepliesExpected)
+ return (int)(DeviceExtension->RepliesExpected = 0) - 1;
+
+ return 0;
+}
+
+/* Detect if mouse is just a standard ps/2 mouse */
+static BOOLEAN TestMouse(
+ IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension)
+{
+ UCHAR param[4];
+
+ param[0] = param[1] = 0xa5;
+
+ /*
+ * First, we check if it's a mouse. It should send 0x00 or 0x03
+ * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+ */
+ if(SendCommand(DeviceExtension, param, PSMOUSE_CMD_GETID))
+ return -1;
+
+ if(param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+ return -1;
+
+ /*
+ * Then we reset and disable the mouse so that it doesn't generate events.
+ */
+
+ return TRUE;
+}
+
+/* Initialize the PS/2 mouse support */
+static BOOLEAN SetupMouse(
+ IN PI8042_MOUSE_EXTENSION_OLD DeviceExtension)
+{
+ LARGE_INTEGER Millisecond_Timeout;
+
+ Millisecond_Timeout.QuadPart = -10000L;
+
+ /* setup */
+ DeviceExtension->RepliesExpected = 0;
+ DeviceExtension->ack = 0;
+
+ /* Enable the PS/2 mouse port */
+ i8042Write(DeviceExtension->PortDeviceExtension, DeviceExtension->PortDeviceExtension->ControlPort, CONTROLLER_COMMAND_MOUSE_ENABLE);
+
+ if(TestMouse(DeviceExtension))
{
- /* 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("Detected Mouse\n");
+
+ if(SendCommand(DeviceExtension, NULL, PSMOUSE_CMD_ENABLE))
+ DPRINT1("Failed to enable mouse!\n");
+
+ /* Enable controller interrupts */
+ i8042Write(DeviceExtension->PortDeviceExtension, DeviceExtension->PortDeviceExtension->ControlPort, KBD_WRITE_MODE);
+ i8042Write(DeviceExtension->PortDeviceExtension, DeviceExtension->PortDeviceExtension->DataPort, MOUSE_INTERRUPTS_ON);
}
-
- DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
- return Ok;
+ return TRUE;
+}
+
+static NTSTATUS OldInitialization(
+ IN PPORT_DEVICE_EXTENSION PortDeviceExtension)
+{
+ I8042_MOUSE_EXTENSION_OLD DeviceExtension;
+
+ RtlZeroMemory(&DeviceExtension, sizeof(I8042_MOUSE_EXTENSION_OLD));
+ DeviceExtension.PortDeviceExtension = PortDeviceExtension;
+ SetupMouse(&DeviceExtension);
+ return STATUS_SUCCESS;
}
--- /dev/null
+/*
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/pnp.c
+ * PURPOSE: IRP_MJ_PNP operations
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+/* 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
+i8042ChangeMode(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR FlagsToDisable,
+ IN UCHAR FlagsToEnable)
+{
+ UCHAR Value;
+ NTSTATUS Status;
+
+ if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_READ_MODE))
+ {
+ DPRINT1("Can't read i8042 mode\n");
+ return FALSE;
+ }
+
+ Status = i8042ReadDataWait(DeviceExtension, &Value);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("No response after read i8042 mode\n");
+ return FALSE;
+ }
+
+ Value &= ~FlagsToDisable;
+ Value |= FlagsToEnable;
+
+ if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE))
+ {
+ DPRINT1("Can't set i8042 mode\n");
+ return FALSE;
+ }
+
+ if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
+ {
+ DPRINT1("Can't send i8042 mode\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static NTSTATUS
+i8042BasicDetect(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS Status;
+ UCHAR Value = 0;
+
+ i8042Flush(DeviceExtension);
+
+ if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST))
+ {
+ DPRINT1("Writing CTRL_SELF_TEST command failed\n");
+ return STATUS_IO_TIMEOUT;
+ }
+
+ Status = i8042ReadDataWait(DeviceExtension, &Value);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ if (Value != 0x55)
+ {
+ DPRINT1("Got 0x%02x instead of 0x55\n", Value);
+ return STATUS_IO_DEVICE_ERROR;
+ }
+
+ /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
+ if (!i8042ChangeMode(DeviceExtension, CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB, CCB_KBD_DISAB | CCB_MOUSE_DISAB))
+ return STATUS_IO_DEVICE_ERROR;
+
+ /*
+ * We used to send a KBD_LINE_TEST (0xAB) 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.
+ */
+ DeviceExtension->Flags |= KEYBOARD_PRESENT;
+
+ if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST))
+ {
+ Status = i8042ReadDataWait(DeviceExtension, &Value);
+ if (NT_SUCCESS(Status) && Value == 0)
+ DeviceExtension->Flags |= MOUSE_PRESENT;
+ }
+
+ if (IsFirstStageSetup())
+ /* Ignore the mouse */
+ DeviceExtension->Flags &= ~MOUSE_PRESENT;
+
+ return STATUS_SUCCESS;
+}
+
+static BOOLEAN
+i8042DetectKeyboard(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS Status;
+
+ if (!i8042ChangeMode(DeviceExtension, 0, CCB_KBD_DISAB))
+ return FALSE;
+
+ i8042Flush(DeviceExtension);
+
+ /* Set LEDs (that is not fatal if some error occurs) */
+ Status = i8042SynchWritePort(DeviceExtension, 0, KBD_CMD_SET_LEDS, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ Status = i8042SynchWritePort(DeviceExtension, 0, 0, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Can't finish SET_LEDS (0x%08lx)\n", Status);
+ return FALSE;
+ }
+ }
+ else
+ {
+ DPRINT("Warning: can't write SET_LEDS (0x%08lx)\n", Status);
+ }
+
+ /* Turn on translation */
+ if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE))
+ return FALSE;
+
+ return TRUE;
+}
+
+static BOOLEAN
+i8042DetectMouse(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ BOOLEAN Ok = FALSE;
+ NTSTATUS Status;
+ UCHAR Value;
+ UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA, 0x00 };
+ UCHAR ReplyByte;
+
+ i8042Flush(DeviceExtension);
+
+ if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_WRITE_MOUSE)
+ ||!i8042Write(DeviceExtension, DeviceExtension->DataPort, MOU_CMD_RESET))
+ {
+ DPRINT1("Failed to write reset command to mouse\n");
+ goto cleanup;
+ }
+
+ for (ReplyByte = 0;
+ ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]);
+ ReplyByte++)
+ {
+ Status = i8042ReadDataWait(DeviceExtension, &Value);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("No ACK after mouse reset, status 0x%08lx\n", Status);
+ goto cleanup;
+ }
+ else if (Value != ExpectedReply[ReplyByte])
+ {
+ DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
+ Value, ExpectedReply[ReplyByte]);
+ goto cleanup;
+ }
+ }
+
+ Ok = TRUE;
+
+cleanup:
+ 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(DeviceExtension);
+ i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST);
+ i8042ReadDataWait(DeviceExtension, &Value);
+ i8042Flush(DeviceExtension);
+ }
+
+ DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
+
+ return Ok;
+}
+
+static NTSTATUS
+i8042ConnectKeyboardInterrupt(
+ IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
+{
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ KIRQL DirqlMax;
+ NTSTATUS Status;
+
+ DPRINT("i8042ConnectKeyboardInterrupt()\n");
+
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+ DirqlMax = MAX(
+ PortDeviceExtension->KeyboardInterrupt.Dirql,
+ PortDeviceExtension->MouseInterrupt.Dirql);
+
+ DPRINT("KeyboardInterrupt.Vector %lu\n",
+ PortDeviceExtension->KeyboardInterrupt.Vector);
+ DPRINT("KeyboardInterrupt.Dirql %lu\n",
+ PortDeviceExtension->KeyboardInterrupt.Dirql);
+ DPRINT("KeyboardInterrupt.DirqlMax %lu\n",
+ DirqlMax);
+ DPRINT("KeyboardInterrupt.InterruptMode %s\n",
+ PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
+ DPRINT("KeyboardInterrupt.ShareInterrupt %s\n",
+ PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no");
+ DPRINT("KeyboardInterrupt.Affinity 0x%lx\n",
+ PortDeviceExtension->KeyboardInterrupt.Affinity);
+ Status = IoConnectInterrupt(
+ &PortDeviceExtension->KeyboardInterrupt.Object,
+ i8042KbdInterruptService,
+ DeviceExtension, &PortDeviceExtension->SpinLock,
+ PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax,
+ PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt,
+ PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoConnectInterrupt() failed with status 0x%08x\n", Status);
+ return Status;
+ }
+
+ if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql)
+ PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
+ PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED;
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+i8042ConnectMouseInterrupt(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension)
+{
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ KIRQL DirqlMax;
+ NTSTATUS Status;
+
+ DPRINT("i8042ConnectMouseInterrupt()\n");
+
+ Status = i8042MouInitialize(DeviceExtension);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
+ DirqlMax = MAX(
+ PortDeviceExtension->KeyboardInterrupt.Dirql,
+ PortDeviceExtension->MouseInterrupt.Dirql);
+
+ DPRINT("MouseInterrupt.Vector %lu\n",
+ PortDeviceExtension->MouseInterrupt.Vector);
+ DPRINT("MouseInterrupt.Dirql %lu\n",
+ PortDeviceExtension->MouseInterrupt.Dirql);
+ DPRINT("MouseInterrupt.DirqlMax %lu\n",
+ DirqlMax);
+ DPRINT("MouseInterrupt.InterruptMode %s\n",
+ PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
+ DPRINT("MouseInterrupt.ShareInterrupt %s\n",
+ PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no");
+ DPRINT("MouseInterrupt.Affinity 0x%lx\n",
+ PortDeviceExtension->MouseInterrupt.Affinity);
+ Status = IoConnectInterrupt(
+ &PortDeviceExtension->MouseInterrupt.Object,
+ i8042MouInterruptService,
+ DeviceExtension, &PortDeviceExtension->SpinLock,
+ PortDeviceExtension->MouseInterrupt.Vector, PortDeviceExtension->MouseInterrupt.Dirql, DirqlMax,
+ PortDeviceExtension->MouseInterrupt.InterruptMode, PortDeviceExtension->MouseInterrupt.ShareInterrupt,
+ PortDeviceExtension->MouseInterrupt.Affinity, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoConnectInterrupt() failed with status 0x%08x\n", Status);
+ goto cleanup;
+ }
+
+ if (DirqlMax == PortDeviceExtension->MouseInterrupt.Dirql)
+ PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->MouseInterrupt.Object;
+
+ PortDeviceExtension->Flags |= MOUSE_INITIALIZED;
+ Status = STATUS_SUCCESS;
+
+cleanup:
+ if (!NT_SUCCESS(Status))
+ {
+ PortDeviceExtension->Flags &= ~MOUSE_INITIALIZED;
+ if (PortDeviceExtension->MouseInterrupt.Object)
+ {
+ IoDisconnectInterrupt(PortDeviceExtension->MouseInterrupt.Object);
+ PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
+ }
+ }
+ return Status;
+}
+
+static NTSTATUS
+EnableInterrupts(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR FlagsToDisable = 0;
+ UCHAR FlagsToEnable = 0;
+
+ /* Select the devices we have */
+ if (DeviceExtension->Flags & KEYBOARD_PRESENT)
+ {
+ FlagsToDisable |= CCB_KBD_DISAB;
+ FlagsToEnable |= CCB_KBD_INT_ENAB;
+ }
+ if (DeviceExtension->Flags & MOUSE_PRESENT)
+ {
+ FlagsToDisable |= CCB_MOUSE_DISAB;
+ FlagsToEnable |= CCB_MOUSE_INT_ENAB;
+ }
+ if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable))
+ return STATUS_UNSUCCESSFUL;
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+StartProcedure(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ NTSTATUS Status;
+
+ if (DeviceExtension->DataPort == 0)
+ {
+ /* Unable to do something at the moment */
+ return STATUS_SUCCESS;
+ }
+
+ if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT)))
+ {
+ /* Try to detect them */
+ DPRINT("Check if the controller is really a i8042\n");
+ Status = i8042BasicDetect(DeviceExtension);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("i8042BasicDetect() failed with status 0x%08lx\n", Status);
+ return STATUS_UNSUCCESSFUL;
+ }
+ DPRINT("Detecting keyboard\n");
+ if (!i8042DetectKeyboard(DeviceExtension))
+ return STATUS_UNSUCCESSFUL;
+ DPRINT("Detecting mouse\n");
+ if (!i8042DetectMouse(DeviceExtension))
+ return STATUS_UNSUCCESSFUL;
+ DPRINT("Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO");
+ DPRINT("Mouse present : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO");
+ }
+
+ /* Connect interrupts */
+ if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
+ DeviceExtension->Flags & KEYBOARD_CONNECTED &&
+ DeviceExtension->Flags & KEYBOARD_STARTED &&
+ !(DeviceExtension->Flags & (MOUSE_PRESENT | KEYBOARD_INITIALIZED)))
+ {
+ /* No mouse, and the keyboard is ready */
+ Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
+ if (NT_SUCCESS(Status))
+ {
+ DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
+ Status = EnableInterrupts(DeviceExtension);
+ }
+ }
+ else if (DeviceExtension->Flags & MOUSE_PRESENT &&
+ DeviceExtension->Flags & MOUSE_CONNECTED &&
+ DeviceExtension->Flags & MOUSE_STARTED &&
+ !(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_INITIALIZED)))
+ {
+ /* No keyboard, and the mouse is ready */
+ Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
+ if (NT_SUCCESS(Status))
+ {
+ DeviceExtension->Flags |= MOUSE_INITIALIZED;
+ Status = EnableInterrupts(DeviceExtension);
+ }
+ }
+ else if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
+ DeviceExtension->Flags & KEYBOARD_CONNECTED &&
+ DeviceExtension->Flags & KEYBOARD_STARTED &&
+ DeviceExtension->Flags & MOUSE_PRESENT &&
+ DeviceExtension->Flags & MOUSE_CONNECTED &&
+ DeviceExtension->Flags & MOUSE_STARTED &&
+ !(DeviceExtension->Flags & (KEYBOARD_INITIALIZED | MOUSE_INITIALIZED)))
+ {
+ /* The keyboard and mouse are ready */
+ Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
+ if (NT_SUCCESS(Status))
+ {
+ DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
+ Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
+ if (NT_SUCCESS(Status))
+ {
+ DeviceExtension->Flags |= MOUSE_INITIALIZED;
+ Status = EnableInterrupts(DeviceExtension);
+ }
+ }
+ }
+ else
+ {
+ /* Nothing to do */
+ Status = STATUS_SUCCESS;
+ }
+
+ return Status;
+}
+
+static NTSTATUS
+i8042PnpStartDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PCM_RESOURCE_LIST AllocatedResources,
+ IN PCM_RESOURCE_LIST AllocatedResourcesTranslated)
+{
+ PFDO_DEVICE_EXTENSION DeviceExtension;
+ PPORT_DEVICE_EXTENSION PortDeviceExtension;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor, ResourceDescriptorTranslated;
+ INTERRUPT_DATA InterruptData;
+ BOOLEAN FoundDataPort = FALSE;
+ BOOLEAN FoundControlPort = FALSE;
+ BOOLEAN FoundIrq = FALSE;
+ ULONG i;
+ NTSTATUS Status;
+
+ DPRINT("i8042PnpStartDevice(%p)\n", DeviceObject);
+ DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+ PortDeviceExtension = DeviceExtension->PortDeviceExtension;
+
+ ASSERT(DeviceExtension->PnpState == dsStopped);
+
+ if (!AllocatedResources)
+ {
+ DPRINT("No allocated resources sent to driver\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ if (AllocatedResources->Count != 1)
+ {
+ DPRINT("Wrong number of allocated resources sent to driver\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ if (AllocatedResources->List[0].PartialResourceList.Version != 1
+ || AllocatedResources->List[0].PartialResourceList.Revision != 1
+ || AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1
+ || AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1)
+ {
+ DPRINT("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
+ AllocatedResources->List[0].PartialResourceList.Version,
+ AllocatedResources->List[0].PartialResourceList.Revision,
+ AllocatedResourcesTranslated->List[0].PartialResourceList.Version,
+ AllocatedResourcesTranslated->List[0].PartialResourceList.Revision);
+ return STATUS_REVISION_MISMATCH;
+ }
+
+ /* Get Irq and optionally control port and data port */
+ for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
+ {
+ ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
+ ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
+ switch (ResourceDescriptor->Type)
+ {
+ case CmResourceTypePort:
+ {
+ if (ResourceDescriptor->u.Port.Length == 1)
+ {
+ /* We assume that the first ressource will
+ * be the control port and the second one
+ * will be the data port...
+ */
+ if (!FoundDataPort)
+ {
+ PortDeviceExtension->DataPort = (PUCHAR)ResourceDescriptor->u.Port.Start.u.LowPart;
+ DPRINT("Found data port: 0x%lx\n", PortDeviceExtension->DataPort);
+ FoundDataPort = TRUE;
+ }
+ else if (!FoundControlPort)
+ {
+ PortDeviceExtension->ControlPort = (PUCHAR)ResourceDescriptor->u.Port.Start.u.LowPart;
+ DPRINT("Found control port: 0x%lx\n", PortDeviceExtension->ControlPort);
+ FoundControlPort = TRUE;
+ }
+ else
+ {
+ DPRINT("Too much I/O ranges provided\n", ResourceDescriptor->u.Port.Length);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ DPRINT1("Invalid I/O range length: 0x%lx\n", ResourceDescriptor->u.Port.Length);
+ break;
+ }
+ case CmResourceTypeInterrupt:
+ {
+ if (FoundIrq)
+ return STATUS_INVALID_PARAMETER;
+ InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level;
+ InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector;
+ InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity;
+ if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
+ InterruptData.InterruptMode = Latched;
+ else
+ InterruptData.InterruptMode = LevelSensitive;
+ InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared);
+ DPRINT("Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Vector);
+ FoundIrq = TRUE;
+ break;
+ }
+ default:
+ DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
+ }
+ }
+
+ if (!FoundIrq)
+ {
+ DPRINT("Interrupt resource was not found in allocated resources list\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort))
+ {
+ DPRINT("Some required resources were not found in allocated resources list\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort))
+ {
+ DPRINT("Too much resources were provided in allocated resources list\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (DeviceExtension->Type)
+ {
+ case Keyboard:
+ {
+ RtlCopyMemory(
+ &PortDeviceExtension->KeyboardInterrupt,
+ &InterruptData,
+ sizeof(INTERRUPT_DATA));
+ PortDeviceExtension->Flags |= KEYBOARD_STARTED;
+ Status = StartProcedure(PortDeviceExtension);
+ break;
+ }
+ case Mouse:
+ {
+ RtlCopyMemory(
+ &PortDeviceExtension->MouseInterrupt,
+ &InterruptData,
+ sizeof(INTERRUPT_DATA));
+ PortDeviceExtension->Flags |= MOUSE_STARTED;
+ Status = StartProcedure(PortDeviceExtension);
+ break;
+ }
+ default:
+ {
+ DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
+ ASSERT(FALSE);
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ DeviceExtension->PnpState = dsStarted;
+
+ return Status;
+}
+
+NTSTATUS NTAPI
+i8042Pnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp)
+{
+ PIO_STACK_LOCATION Stack;
+ ULONG MinorFunction;
+ I8042_DEVICE_TYPE DeviceType;
+ ULONG_PTR Information = 0;
+ NTSTATUS Status;
+
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = Stack->MinorFunction;
+ DeviceType = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type;
+
+ switch (MinorFunction)
+ {
+ case IRP_MN_START_DEVICE: /* 0x0 */
+ {
+ DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
+
+ /* Call lower driver (if any) */
+ if (DeviceType != PhysicalDeviceObject)
+ {
+ Status = ForwardIrpAndWait(DeviceObject, Irp);
+ if (NT_SUCCESS(Status))
+ Status = i8042PnpStartDevice(
+ DeviceObject,
+ Stack->Parameters.StartDevice.AllocatedResources,
+ Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
+ }
+ else
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
+ {
+ switch (Stack->Parameters.QueryDeviceRelations.Type)
+ {
+ case BusRelations:
+ {
+ DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ case RemovalRelations:
+ {
+ DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ default:
+ DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
+ Stack->Parameters.QueryDeviceRelations.Type);
+ ASSERT(FALSE);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ break;
+ }
+ default:
+ {
+ DPRINT1("IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction);
+ ASSERT(FALSE);
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ }
+
+ Irp->IoStatus.Information = Information;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
/*
- * 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
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/ps2pp.c
+ * PURPOSE: ps2pp protocol handling
+ * PROGRAMMERS: Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ * Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ****************************************************************/
-#ifndef NDEBUG
+#include "i8042prt.h"
+
#define NDEBUG
-#endif
#include <debug.h>
-#include "i8042prt.h"
-
+/* FUNCTIONS *****************************************************************/
-VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input)
+VOID
+i8042MouHandlePs2pp(
+ IN PI8042_MOUSE_EXTENSION DeviceExtension,
+ IN 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
- */
+ PMOUSE_INPUT_DATA MouseInput;
+
+ MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->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 (DeviceExtension->MouseState)
+ {
+ case MouseIdle:
+ case XMovement:
+ DeviceExtension->MouseLogiBuffer[DeviceExtension->MouseState] = Input;
+ DeviceExtension->MouseState++;
+ break;
+
+ case YMovement:
+ DeviceExtension->MouseLogiBuffer[2] = Input;
+ DeviceExtension->MouseState = MouseIdle;
+
+ /* first check if it's a normal packet */
+
+ if (!(DeviceExtension->MouseLogiBuffer[0] & 0xC0))
+ {
+ DeviceExtension->MouseState = MouseIdle;
+ i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[0]);
+ i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[1]);
+ i8042MouHandle(DeviceExtension, DeviceExtension->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;
+ }
- 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;
+ /* sanity check */
+ if (((DeviceExtension->MouseLogiBuffer[0] & 0x48) != 0x48) ||
+ (((DeviceExtension->MouseLogiBuffer[1] & 0x0C) >> 2) !=
+ (DeviceExtension->MouseLogiBuffer[2] & 0x03)))
+ {
+ DPRINT1("Ps2pp packet fails sanity checks\n");
+ return;
+ }
+
+ /* Now get the packet type */
+ PktType = ((DeviceExtension->MouseLogiBuffer[0] & 0x30) >> 4) &
+ ((DeviceExtension->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 (DeviceExtension->MouseLogiBuffer[2] & 0x10)
+ MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+
+ if (DeviceExtension->MouseLogiBuffer[2] & 0x20)
+ MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+
+ if (DeviceExtension->MouseLogiBuffer[2] & 0x0F)
+ {
+ MouseInput->ButtonFlags |= MOUSE_WHEEL;
+ if (DeviceExtension->MouseLogiBuffer[2] & 0x08)
+ MouseInput->ButtonData = (DeviceExtension->MouseLogiBuffer[2] & 0x07) - 8;
+ else
+ MouseInput->ButtonData = DeviceExtension->MouseLogiBuffer[2] & 0x07;
+ }
+ i8042MouHandleButtons(
+ DeviceExtension,
+ MOUSE_BUTTON_4_DOWN | MOUSE_BUTTON_5_DOWN);
+ i8042MouQueuePacket(DeviceExtension);
+ return;
+ default:
+ /* These are for things that would probably
+ * be handled by logitechs own driver.
+ */
+ return;
}
- 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");
+ DPRINT1("Unexpected input state for ps2pp!\n");
}
}
--- /dev/null
+/*
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/readwrite.c
+ * PURPOSE: Read/write port functions
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+ Copyright Jason Filby (jasonfilby@yahoo.com)
+ Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS *****************************************************************/
+
+VOID
+i8042Flush(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension)
+{
+ UCHAR Ignore;
+
+ while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_OBF | MOU_OBF, &Ignore))) {
+ DPRINT("Data flushed\n"); /* drop */
+ }
+}
+
+VOID
+i8042IsrWritePort(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR Value,
+ IN UCHAR SelectCmd OPTIONAL)
+{
+ if (SelectCmd)
+ if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, SelectCmd))
+ return;
+
+ i8042Write(DeviceExtension, DeviceExtension->DataPort, Value);
+}
+
+/*
+ * FUNCTION: Read data from port 0x60
+ */
+NTSTATUS
+i8042ReadData(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR StatusFlags,
+ OUT PUCHAR Data)
+{
+ UCHAR PortStatus;
+ NTSTATUS Status;
+
+ Status = i8042ReadStatus(DeviceExtension, &PortStatus);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ // If data is available
+ if (PortStatus & StatusFlags)
+ {
+ *Data = READ_PORT_UCHAR(DeviceExtension->DataPort);
+ DPRINT("Read: 0x%02x (status: 0x%x)\n", Data[0], PortStatus);
+
+ // If the data is valid (not timeout, not parity error)
+ if ((PortStatus & KBD_PERR) == 0)
+ return STATUS_SUCCESS;
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+i8042ReadStatus(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR Status)
+{
+ ASSERT(DeviceExtension->ControlPort != NULL);
+ *Status = READ_PORT_UCHAR(DeviceExtension->ControlPort);
+ return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Read data from data port
+ */
+NTSTATUS
+i8042ReadDataWait(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ OUT PUCHAR Data)
+{
+ ULONG Counter;
+ NTSTATUS Status;
+
+ Counter = DeviceExtension->Settings.PollingIterations;
+
+ while (Counter--)
+ {
+ Status = i8042ReadKeyboardData(DeviceExtension, Data);
+
+ if (NT_SUCCESS(Status))
+ return Status;
+
+ KeStallExecutionProcessor(50);
+ }
+
+ /* Timed out */
+ 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.
+ */
+NTSTATUS NTAPI
+i8042SynchReadPort(
+ IN PVOID Context,
+ OUT PUCHAR Value,
+ IN BOOLEAN WaitForAck)
+{
+ PPORT_DEVICE_EXTENSION DeviceExtension;
+
+ DeviceExtension = (PPORT_DEVICE_EXTENSION)Context;
+
+ return i8042ReadDataWait(DeviceExtension, Value);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS NTAPI
+i8042SynchWritePort(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN UCHAR Port,
+ IN UCHAR Value,
+ IN BOOLEAN WaitForAck)
+{
+ NTSTATUS Status;
+ UCHAR Ack;
+ ULONG ResendIterations;
+
+ ResendIterations = DeviceExtension->Settings.ResendIterations + 1;
+
+ do
+ {
+ if (Port)
+ if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Port))
+ {
+ DPRINT1("Failed to write Port\n");
+ return STATUS_IO_TIMEOUT;
+ }
+
+ if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
+ {
+ DPRINT1("Failed to write Value\n");
+ return STATUS_IO_TIMEOUT;
+ }
+
+ if (WaitForAck)
+ {
+ Status = i8042ReadDataWait(DeviceExtension, &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%02x\n", Ack);
+ return STATUS_UNEXPECTED_IO_ERROR;
+ }
+ }
+ else
+ {
+ return STATUS_SUCCESS;
+ }
+ DPRINT("Reiterating\n");
+ ResendIterations--;
+ } while (ResendIterations);
+
+ return STATUS_IO_TIMEOUT;
+}
+
+/*
+ * FUNCTION: Write data to a port, waiting first for it to become ready
+ */
+BOOLEAN
+i8042Write(
+ IN PPORT_DEVICE_EXTENSION DeviceExtension,
+ IN PUCHAR addr,
+ IN UCHAR data)
+{
+ ULONG ResendIterations;
+
+ ASSERT(addr);
+ ASSERT(DeviceExtension->ControlPort != NULL);
+
+ ResendIterations = DeviceExtension->Settings.ResendIterations;
+
+ while ((KBD_IBF & READ_PORT_UCHAR(DeviceExtension->ControlPort)) &&
+ (ResendIterations--))
+ {
+ KeStallExecutionProcessor(50);
+ }
+
+ if (ResendIterations)
+ {
+ WRITE_PORT_UCHAR(addr, data);
+ DPRINT("Sent 0x%x to port 0x%x\n", data, addr);
+ return TRUE;
+ }
+ return FALSE;
+}
/*
- * 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
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/i8042prt.c
+ * PURPOSE: Reading the registry
+ * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
+ Copyright Jason Filby (jasonfilby@yahoo.com)
+ Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
+ Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
-/* INCLUDES ****************************************************************/
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
-#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)
-
+NTSTATUS
+ReadRegistryEntries(
+ IN PUNICODE_STRING RegistryPath,
+ OUT PI8042_SETTINGS Settings)
{
- RTL_QUERY_REGISTRY_TABLE Parameters[19];
-
+ UNICODE_STRING ParametersRegistryKey;
+ RTL_QUERY_REGISTRY_TABLE Parameters[16];
NTSTATUS Status;
- ULONG DefaultHeadless = 0;
- ULONG DefaultCrashScroll = 0;
- ULONG DefaultCrashSysRq = 0;
- ULONG DefaultReportResetErrors = 0;
+ ULONG DefaultKeyboardDataQueueSize = 0x64;
+ UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardPort");
+ ULONG DefaultMouseDataQueueSize = 0x64;
+ ULONG DefaultMouseResolution = 3;
+ ULONG DefaultMouseSynchIn100ns = 20000000;
+ ULONG DefaultNumberOfButtons = 2;
+ UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerPort");
ULONG DefaultPollStatusIterations = 1;
- ULONG DefaultResendIterations = 3;
- ULONG DefaultPollingIterations = 12000;
- ULONG DefaultPollingIterationsMaximum = 12000;
- ULONG DefaultKeyboardDataQueueSize = 100;
- ULONG DefaultOverrideKeyboardType = 0;
+ ULONG DefaultOverrideKeyboardType = 4;
ULONG DefaultOverrideKeyboardSubtype = 0;
- ULONG DefaultMouseDataQueueSize = 100;
- ULONG DefaultMouseResendStallTime = 1000;
- ULONG DefaultMouseSynchIn100ns = 20000000;
- ULONG DefaultMouseResolution = 3;
+ ULONG DefaultPollingIterations = 0x400;
+ ULONG DefaultPollingIterationsMaximum = 12000;
+ ULONG DefaultResendIterations = 0x3;
ULONG DefaultSampleRate = 60;
- ULONG DefaultNumberOfButtons = 2;
- ULONG DefaultEnableWheelDetection = 1;
+ ULONG DefaultCrashOnCtrlScroll;
+
+ /* Default value for CrashOnCtrlScroll depends if we're
+ * running a debug build or a normal build.
+ */
+#ifdef DBG
+ DefaultCrashOnCtrlScroll = 1;
+#else
+ DefaultCrashOnCtrlScroll = 0;
+#endif
+
+ ParametersRegistryKey.Length = 0;
+ ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
+ ParametersRegistryKey.Buffer = ExAllocatePool(PagedPool, ParametersRegistryKey.MaximumLength);
+ if (!ParametersRegistryKey.Buffer)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
+ RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
+ ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
RtlZeroMemory(Parameters, sizeof(Parameters));
- Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- Parameters[0].Name = L"Headless";
- Parameters[0].EntryContext = &DevExt->Settings.Headless;
+ Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[0].Name = L"KeyboardDataQueueSize";
+ Parameters[0].EntryContext = &Settings->KeyboardDataQueueSize;
Parameters[0].DefaultType = REG_DWORD;
- Parameters[0].DefaultData = &DefaultHeadless;
+ Parameters[0].DefaultData = &DefaultKeyboardDataQueueSize;
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[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[1].Name = L"KeyboardDeviceBaseName";
+ Parameters[1].EntryContext = &Settings->KeyboardDeviceBaseName;
+ Parameters[1].DefaultType = REG_SZ;
+ Parameters[1].DefaultData = &DefaultKeyboardDeviceBaseName;
+ Parameters[1].DefaultLength = 0;
- Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
- Parameters[2].Name = L"BreakOnSysRq";
- Parameters[2].EntryContext = &DevExt->Settings.CrashSysRq;
+ Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[2].Name = L"MouseDataQueueSize";
+ Parameters[2].EntryContext = &Settings->MouseDataQueueSize;
Parameters[2].DefaultType = REG_DWORD;
- Parameters[2].DefaultData = &DefaultCrashSysRq;
+ Parameters[2].DefaultData = &DefaultMouseDataQueueSize;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[3].Name = L"MouseResolution";
+ Parameters[3].EntryContext = &Settings->MouseResolution;
Parameters[3].DefaultType = REG_DWORD;
- Parameters[3].DefaultData = &DefaultReportResetErrors;
+ Parameters[3].DefaultData = &DefaultMouseResolution;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[4].Name = L"MouseSynchIn100ns";
+ Parameters[4].EntryContext = &Settings->MouseSynchIn100ns;
Parameters[4].DefaultType = REG_DWORD;
- Parameters[4].DefaultData = &DefaultPollStatusIterations;
+ Parameters[4].DefaultData = &DefaultMouseSynchIn100ns;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[5].Name = L"NumberOfButtons";
+ Parameters[5].EntryContext = &Settings->NumberOfButtons;
Parameters[5].DefaultType = REG_DWORD;
- Parameters[5].DefaultData = &DefaultResendIterations;
+ Parameters[5].DefaultData = &DefaultNumberOfButtons;
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[6].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[6].Name = L"PointerDeviceBaseName";
+ Parameters[6].EntryContext = &Settings->PointerDeviceBaseName;
+ Parameters[6].DefaultType = REG_SZ;
+ Parameters[6].DefaultData = &DefaultPointerDeviceBaseName;
+ Parameters[6].DefaultLength = 0;
- Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
- Parameters[7].Name = L"PollingIterationsMaximum";
- Parameters[7].EntryContext = &DevExt->Settings.PollingIterationsMaximum;
+ Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[7].Name = L"PollStatusIterations";
+ Parameters[7].EntryContext = &Settings->PollStatusIterations;
Parameters[7].DefaultType = REG_DWORD;
- Parameters[7].DefaultData = &DefaultPollingIterationsMaximum;
+ Parameters[7].DefaultData = &DefaultPollStatusIterations;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[8].Name = L"OverrideKeyboardType";
+ Parameters[8].EntryContext = &Settings->OverrideKeyboardType;
Parameters[8].DefaultType = REG_DWORD;
- Parameters[8].DefaultData = &DefaultKeyboardDataQueueSize;
+ Parameters[8].DefaultData = &DefaultOverrideKeyboardType;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[9].Name = L"OverrideKeyboardSubtype";
+ Parameters[9].EntryContext = &Settings->OverrideKeyboardSubtype;
Parameters[9].DefaultType = REG_DWORD;
- Parameters[9].DefaultData = &DefaultOverrideKeyboardType;
+ Parameters[9].DefaultData = &DefaultOverrideKeyboardSubtype;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[10].Name = L"PollingIterations";
+ Parameters[10].EntryContext = &Settings->PollingIterations;
Parameters[10].DefaultType = REG_DWORD;
- Parameters[10].DefaultData = &DefaultOverrideKeyboardSubtype;
+ Parameters[10].DefaultData = &DefaultPollingIterations;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[11].Name = L"PollingIterationsMaximum";
+ Parameters[11].EntryContext = &Settings->PollingIterationsMaximum;
Parameters[11].DefaultType = REG_DWORD;
- Parameters[11].DefaultData = &DefaultMouseDataQueueSize;
+ Parameters[11].DefaultData = &DefaultPollingIterationsMaximum;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[12].Name = L"ResendIterations";
+ Parameters[12].EntryContext = &Settings->ResendIterations;
Parameters[12].DefaultType = REG_DWORD;
- Parameters[12].DefaultData = &DefaultMouseResendStallTime;
+ Parameters[12].DefaultData = &DefaultResendIterations;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[13].Name = L"SampleRate";
+ Parameters[13].EntryContext = &Settings->SampleRate;
Parameters[13].DefaultType = REG_DWORD;
- Parameters[13].DefaultData = &DefaultMouseSynchIn100ns;
+ Parameters[13].DefaultData = &DefaultSampleRate;
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].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
+ Parameters[14].Name = L"CrashOnCtrlScroll";
+ Parameters[14].EntryContext = &Settings->CrashOnCtrlScroll;
Parameters[14].DefaultType = REG_DWORD;
- Parameters[14].DefaultData = &DefaultMouseResolution;
+ Parameters[14].DefaultData = &DefaultCrashOnCtrlScroll;
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++;
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ParametersRegistryKey.Buffer,
+ Parameters,
+ NULL,
+ NULL);
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Check values */
+ if (Settings->KeyboardDataQueueSize < 1)
+ Settings->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
+ if (Settings->MouseDataQueueSize < 1)
+ Settings->MouseDataQueueSize = DefaultMouseDataQueueSize;
+ if (Settings->NumberOfButtons < 1)
+ Settings->NumberOfButtons = DefaultNumberOfButtons;
+ if (Settings->PollingIterations < 0x400)
+ Settings->PollingIterations = DefaultPollingIterations;
+ if (Settings->PollingIterationsMaximum < 0x400)
+ Settings->PollingIterationsMaximum = DefaultPollingIterationsMaximum;
+ if (Settings->ResendIterations < 1)
+ Settings->ResendIterations = DefaultResendIterations;
+ }
+ else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ /* Registry path doesn't exist. Set defaults */
+ Settings->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
+ Settings->MouseDataQueueSize = DefaultMouseDataQueueSize;
+ Settings->MouseResolution = DefaultMouseResolution;
+ Settings->MouseSynchIn100ns = DefaultMouseSynchIn100ns;
+ Settings->NumberOfButtons = DefaultNumberOfButtons;
+ Settings->PollStatusIterations = DefaultPollStatusIterations;
+ Settings->OverrideKeyboardType = DefaultOverrideKeyboardType;
+ Settings->OverrideKeyboardSubtype = DefaultOverrideKeyboardSubtype;
+ Settings->PollingIterations = DefaultPollingIterations;
+ Settings->PollingIterationsMaximum = DefaultPollingIterationsMaximum;
+ Settings->ResendIterations = DefaultResendIterations;
+ Settings->SampleRate = DefaultSampleRate;
+ Settings->CrashOnCtrlScroll = DefaultCrashOnCtrlScroll;
+ Status = RtlDuplicateUnicodeString(
+ RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+ &DefaultKeyboardDeviceBaseName,
+ &Settings->KeyboardDeviceBaseName);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
+ }
+ else
+ {
+ Status = RtlDuplicateUnicodeString(
+ RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+ &DefaultPointerDeviceBaseName,
+ &Settings->PointerDeviceBaseName);
+ if (!NT_SUCCESS(Status))
+ DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
}
- DPRINT1 ("Manually set defaults\n");
-
}
- if (DevExt->Settings.MouseResolution > 3)
- DevExt->Settings.MouseResolution = 3;
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("KeyboardDataQueueSize : 0x%lx\n", Settings->KeyboardDataQueueSize);
+ DPRINT("KeyboardDeviceBaseName : %wZ\n", &Settings->KeyboardDeviceBaseName);
+ DPRINT("MouseDataQueueSize : 0x%lx\n", Settings->MouseDataQueueSize);
+ DPRINT("MouseResolution : 0x%lx\n", Settings->MouseResolution);
+ DPRINT("MouseSynchIn100ns : %lu\n", Settings->MouseSynchIn100ns);
+ DPRINT("NumberOfButtons : 0x%lx\n", Settings->NumberOfButtons);
+ DPRINT("PointerDeviceBaseName : %wZ\n", &Settings->PointerDeviceBaseName);
+ DPRINT("PollStatusIterations : 0x%lx\n", Settings->PollStatusIterations);
+ DPRINT("OverrideKeyboardType : 0x%lx\n", Settings->OverrideKeyboardType);
+ DPRINT("OverrideKeyboardSubtype : 0x%lx\n", Settings->OverrideKeyboardSubtype);
+ DPRINT("PollingIterations : 0x%lx\n", Settings->PollingIterations);
+ DPRINT("PollingIterationsMaximum : %lu\n", Settings->PollingIterationsMaximum);
+ DPRINT("ResendIterations : 0x%lx\n", Settings->ResendIterations);
+ DPRINT("SampleRate : %lu\n", Settings->SampleRate);
+ }
- DPRINT("Done reading registry\n");
+ return Status;
}
--- /dev/null
+/*
+ * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/input/i8042prt/setup.c
+ * PURPOSE: Create a legacy PDO during ReactOS installation
+ * PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
+ */
+
+/* NOTE:
+ * All this file is a big hack and should be removed one day...
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "i8042prt.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+#define KEYBOARD_DATA_PORT 0x60
+#define KEYBOARD_CONTROL_PORT 0x64
+#define KEYBOARD_IRQ 1
+
+/* FUNCTIONS *****************************************************************/
+
+BOOLEAN
+IsFirstStageSetup(
+ VOID)
+{
+ UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\Setup");
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hSetupKey = (HANDLE)NULL;
+ NTSTATUS Status;
+ BOOLEAN ret = TRUE;
+
+ InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = ZwOpenKey(&hSetupKey, KEY_QUERY_VALUE, &ObjectAttributes);
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ if (hSetupKey != (HANDLE)NULL)
+ ZwClose(hSetupKey);
+ DPRINT("IsFirstStageSetup() returns %s\n", ret ? "YES" : "NO");
+ return ret;
+}
+
+static VOID NTAPI
+SendStartDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PVOID Context,
+ IN ULONG Count)
+{
+ PDEVICE_OBJECT Pdo;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PCM_RESOURCE_LIST AllocatedResourcesTranslated = NULL;
+ PDEVICE_OBJECT TopDeviceObject = NULL;
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PIRP Irp;
+ PIO_STACK_LOCATION Stack;
+ ULONG ResourceListSize;
+ NTSTATUS Status;
+
+ Pdo = (PDEVICE_OBJECT)Context;
+ DPRINT("SendStartDevice(%p)\n", Pdo);
+
+ /* Create default resource list */
+ ResourceListSize = sizeof(CM_RESOURCE_LIST) + 3 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+ AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
+ if (!AllocatedResources)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+ AllocatedResources->Count = 1;
+ AllocatedResources->List[0].PartialResourceList.Version = 1;
+ AllocatedResources->List[0].PartialResourceList.Revision = 1;
+ AllocatedResources->List[0].PartialResourceList.Count = 3;
+ /* Data port */
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].Flags = 0; /* FIXME */
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.u.HighPart = 0;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.u.LowPart = KEYBOARD_DATA_PORT;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = 1;
+ /* Control port */
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].Type = CmResourceTypePort;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].ShareDisposition = CmResourceShareDeviceExclusive;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].Flags = 0; /* FIXME */
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Start.u.HighPart = 0;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Start.u.LowPart = KEYBOARD_CONTROL_PORT;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Length = 1;
+ /* Interrupt */
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].Type = CmResourceTypeInterrupt;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].ShareDisposition = CmResourceShareDeviceExclusive;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level = 0;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector = KEYBOARD_IRQ;
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Affinity = (KAFFINITY)-1;
+
+ /* Create default resource list translated */
+ AllocatedResourcesTranslated = ExAllocatePool(PagedPool, ResourceListSize);
+ if (!AllocatedResources)
+ {
+ DPRINT("ExAllocatePool() failed\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+ RtlCopyMemory(AllocatedResourcesTranslated, AllocatedResources, ResourceListSize);
+ AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector = HalGetInterruptVector(
+ Internal, 0,
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level,
+ AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector,
+ (PKIRQL)&AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level,
+ &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Affinity);
+
+ /* Send IRP_MN_START_DEVICE */
+ TopDeviceObject = IoGetAttachedDeviceReference(Pdo);
+ KeInitializeEvent(
+ &Event,
+ NotificationEvent,
+ FALSE);
+ Irp = IoBuildSynchronousFsdRequest(
+ IRP_MJ_PNP,
+ TopDeviceObject,
+ NULL,
+ 0,
+ NULL,
+ &Event,
+ &IoStatusBlock);
+ Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+ Irp->IoStatus.Information = 0;
+ Stack = IoGetNextIrpStackLocation(Irp);
+ Stack->MinorFunction = IRP_MN_START_DEVICE;
+ Stack->Parameters.StartDevice.AllocatedResources = AllocatedResources;
+ Stack->Parameters.StartDevice.AllocatedResourcesTranslated = AllocatedResourcesTranslated;
+ Status = IoCallDriver(TopDeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(
+ &Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ Status = IoStatusBlock.Status;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoCallDriver() failed with status 0x%08lx\n", Status);
+ goto cleanup;
+ }
+
+cleanup:
+ if (TopDeviceObject)
+ ObDereferenceObject(TopDeviceObject);
+ if (AllocatedResources)
+ ExFreePool(AllocatedResources);
+ if (AllocatedResourcesTranslated)
+ ExFreePool(AllocatedResourcesTranslated);
+}
+
+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;
+}
+
+NTSTATUS
+i8042AddLegacyKeyboard(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath)
+{
+ UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPort8042");
+ PI8042_DEVICE_TYPE DeviceExtension = NULL;
+ PDEVICE_OBJECT Pdo = NULL;
+ NTSTATUS Status;
+
+ DPRINT("i8042AddLegacyKeyboard()\n");
+
+ /* Create a named PDO */
+ Status = IoCreateDevice(
+ DriverObject,
+ sizeof(I8042_DEVICE_TYPE),
+ &KeyboardName,
+ FILE_DEVICE_8042_PORT,
+ FILE_DEVICE_SECURE_OPEN,
+ TRUE,
+ &Pdo);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
+ goto cleanup;
+ }
+
+ /* Initialize device extension */
+ DeviceExtension = (PI8042_DEVICE_TYPE)Pdo->DeviceExtension;
+ RtlZeroMemory(DeviceExtension, sizeof(I8042_DEVICE_TYPE));
+ *DeviceExtension = PhysicalDeviceObject;
+ Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ /* Add FDO at the top of the PDO */
+ Status = i8042AddDevice(DriverObject, Pdo);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("i8042AddDevice() failed with status 0x%08lx\n", Status);
+ goto cleanup;
+ }
+
+ /* We will send the IRP_MN_START_DEVICE later, once kbdclass is loaded */
+ AddRegistryEntry(L"KeyboardPort", &KeyboardName, RegistryPath->Buffer);
+ IoRegisterBootDriverReinitialization(
+ DriverObject,
+ SendStartDevice,
+ Pdo);
+
+ Status = STATUS_SUCCESS;
+
+cleanup:
+ if (!NT_SUCCESS(Status))
+ {
+ if (Pdo)
+ IoDeleteDevice(Pdo);
+ }
+ return Status;
+}