DEVICE_DRIVERS = beep blue debugout null serial bootvid
# Kernel mode input drivers
-INPUT_DRIVERS = keyboard mouclass psaux sermouse
+INPUT_DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
# Kernel mode file system drivers
# cdfs ext2 fs_rec ms np vfat
/* Load keyboard driver */
+#if 0
if (!LoadDriver(SourcePath, "keyboard.sys"))
return;
+#endif
+ if (!LoadDriver(SourcePath, "i8042prt.sys"))
+ return;
+ if (!LoadDriver(SourcePath, "kbdclass.sys"))
+ return;
/* Load screen driver */
if (!LoadDriver(SourcePath, "blue.sys"))
;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x00000001
; Keyboard driver
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
+
+; 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","ImagePath",0x00020000,"system32\drivers\i8042prt.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Start",0x00010001,0x00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Type",0x00010001,0x00000001
+
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","SampleRate",0x00010001,0x00000060
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","BreakOnSysRq",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
; Serial port enumerator
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Type",0x00010001,0x00000010
; PS/2 mouse port driver
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
; RPC service
HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001,0x00000001
class2.sys = 3
disk.sys = 3
floppy.sys = 3
-keyboard.sys = 3
+;keyboard.sys = 3
+i8042prt.sys = 3
+kbdclass.sys = 3
l_intl.nls = 2
ntfs.sys = 3
ntoskrnl.exe = 2
[Mouse]
;<id> = <user friendly name>,<spare>,<service key name>
-msps2 = "Microsoft PS2 Mouse",,psaux
+i8042ps2 = "PS2 Mouse",,i8042prt
+;msps2 = "Microsoft PS2 Mouse",,psaux
msser = "Microsoft Serial Mouse",,sermouse
mswhs = "Microsoft Serial Wheel Mouse",,sermouse
none = "No Mouse"
[Map.Mouse]
;<id> = <pnp id string>
-msps2 = "MICROSOFT PS2 MOUSE"
+i8042ps2 = "MICROSOFT PS2 MOUSE"
+;msps2 = "MICROSOFT PS2 MOUSE"
msser = "MICROSOFT SERIAL MOUSE"
mswhs = "MICROSOFT MOUSE WITH WHEEL"
none = "NO MOUSE"
include $(PATH_TO_TOP)/rules.mak
-DRIVERS = keyboard mouclass psaux sermouse
+DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
all: $(DRIVERS)
--- /dev/null
+Intel 8042 port driver
+
+This directory contains a driver for Intels 8042 and compatible controllers.
+It is based on the information in the DDK documentation on MSDN. It is intended
+to be compatible with keyboard and mouse drivers written for Windows. It is
+not based on the i8042prt example driver that's included with the DDK.
+
+The directory contains these files:
+
+i8042prt.c: Main controller functionality, things shared by keyboards and mice
+
+keyboard.c: keyboard functionality: detection, interrupt handling
+
+mouse.c: mouse functionality: detection, interrupt handling, packet parsing for
+ standard ps2 and microsoft mice
+
+ps2pp.c: logitech ps2++ mouse packat parsing (basic)
+
+registry.c: registry reading
+
+makefile, i8042prt.rc: obvious
+
+
+Some parts of the driver make little sense. This is because it implements
+an interface that has evolved over a long time, and because the ps/2
+'standard' is really awful.
+
+Things to add:
+
+- Better AT (before ps2) keyboard handling
+- SiS keyboard controller detection
+- Mouse identification
+- General robustness: reset mouse if things go wrong
+- Handling all registry settings
+- ACPI
+- Make it work more like a WDM driver
+
+Things not to add:
+
+- Other mouse protocols, touchpad handling etc. : Write a filter driver instead
+- Keyboard lights handling: Should be in win32k
+- Keyboard scancode translation: Should be in win32k
+
+Things requiring work elsewhere:
+
+- Debugger interface (TAB + key):
+ Currently this interface wants translated keycodes, which are not
+ implemented by this driver. As it just uses a giant switch with
+ hardcoded cases, this should not be hard to fix.
+
+- Class drivers:
+ I wrote a keyboard class driver, which does keycode translations. It
+ should not do this, win32k should get untranslated keycodes and do
+ the translation itself.
+
+ I changed the mouse class driver (mouclass) to work like Microsofts mouclass.
+ Unfortunately this means that the original psaux driver doesn't work
+ anymore (the same holds for the other mice drivers, probably).
+
+ The keyboard class driver passes on ioctls from win32k, so it can change
+ keyboard settings. As far as I could see, the mouse class driver does not
+ do this yet.
+
+ The class drivers should be able to handle reads for more than one packet
+ at a time (kbdclass should, mouclass does not). Win32k should send such
+ requests.
+
+
+I put a lot of work in making it work like Microsofts driver does, so third party drivers can work. Please keep it that way.
+
+
+Links:
+
+Here's a link describing most of the registry settings:
+
+http://www.microsoft.com/resources/documentation/Windows/2000/server/reskit/en-us/Default.asp?url=/resources/documentation/Windows/2000/server/reskit/en-us/regentry/31493.asp
+
+PS/2 protocol documentation:
+
+http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html
+
+It also contains a link to a description of the ps2++ protocol, which has
+since disappeared. Archive.org still has it.
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: drivers/input/i8042prt/i8042prt.c
+ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
+ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
+ * Jason Filby (jasonfilby@yahoo.com)
+ * Tinus
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Driver data
+ */
+#define I8042_TIMEOUT 500000
+
+#define I8042_MAX_COMMAND_LENGTH 16
+#define I8042_MAX_UPWARDS_STACK 5
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * FUNCTION: Write data to a port, waiting first for it to become ready
+ */
+BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
+{
+ ULONG ResendIterations = DevExt->Settings.PollingIterations;
+
+ while ((KBD_IBF & READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT)) &&
+ (ResendIterations--))
+ {
+ KeStallExecutionProcessor(50);
+ }
+
+ if (ResendIterations) {
+ WRITE_PORT_UCHAR((PUCHAR)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, BYTE 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(BYTE *Data)
+{
+ BYTE Status;
+ Status=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+
+ // If data is available
+ if ((Status & KBD_OBF)) {
+ Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
+
+ // If the data is valid (not timeout, not parity error)
+ if ((~Status) & (KBD_GTO | KBD_PERR))
+ return STATUS_SUCCESS;
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS I8042ReadStatus(BYTE *Status)
+{
+ Status[0]=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+ return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Read data from port 0x60
+ */
+NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data)
+{
+ ULONG Counter = DevExt->Settings.PollingIterations;
+ NTSTATUS Status;
+
+ while (Counter--) {
+ Status = I8042ReadData(Data);
+
+ if (STATUS_SUCCESS == Status)
+ return Status;
+
+ KeStallExecutionProcessor(50);
+ }
+ // Timed out
+ return STATUS_IO_TIMEOUT;
+}
+
+VOID I8042Flush()
+{
+ BYTE Ignore;
+
+ while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
+ ; /* drop */
+ }
+}
+
+VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
+ UCHAR Value,
+ UCHAR SelectCmd)
+{
+ if (SelectCmd)
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, SelectCmd))
+ return;
+
+ I8042Write(DevExt, I8042_DATA_PORT, Value);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
+ UCHAR Port,
+ UCHAR Value,
+ BOOLEAN WaitForAck)
+{
+ NTSTATUS Status;
+ UCHAR Ack;
+ UINT ResendIterations = DevExt->Settings.ResendIterations + 1;
+
+ do {
+ if (Port)
+ if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
+ return STATUS_TIMEOUT;
+
+ if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
+ return STATUS_TIMEOUT;
+
+ if (WaitForAck) {
+ Status = I8042ReadDataWait(DevExt, &Ack);
+ if (Status != STATUS_SUCCESS)
+ return Status;
+ if (Ack == KBD_ACK)
+ return STATUS_SUCCESS;
+ if (Ack != KBD_RESEND)
+ return STATUS_UNEXPECTED_IO_ERROR;
+ } else {
+ return STATUS_SUCCESS;
+ }
+ ResendIterations--;
+ } while (ResendIterations);
+ return STATUS_TIMEOUT;
+}
+
+/*
+ * This one reads a value from the port; You don't have to specify
+ * which one, it'll always be from the one you talked to, so one function
+ * is enough this time. Note how MSDN specifies the
+ * WaitForAck parameter to be ignored.
+ */
+static NTSTATUS STDCALL I8042SynchReadPort(PVOID Context,
+ PUCHAR Value,
+ BOOLEAN WaitForAck)
+{
+ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)Context;
+
+ return I8042ReadDataWait(DevExt, Value);
+}
+
+/* Write the current byte of the packet. Returns FALSE in case
+ * of problems.
+ */
+static BOOLEAN STDCALL I8042PacketWrite(PDEVICE_EXTENSION DevExt)
+{
+ UCHAR Port = DevExt->PacketPort;
+
+ if (Port) {
+ if (!I8042Write(DevExt,
+ I8042_CTRL_PORT,
+ Port)) {
+ /* something is really wrong! */
+ DPRINT1("Failed to send packet byte!\n");
+ return FALSE;
+ }
+ }
+
+ return I8042Write(DevExt,
+ I8042_DATA_PORT,
+ DevExt->Packet.Bytes[DevExt->Packet.CurrentByte]);
+}
+
+
+/*
+ * This function starts a packet. It must be called with the
+ * correct DIRQL.
+ */
+NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
+ PDEVICE_OBJECT Device,
+ PUCHAR Bytes,
+ ULONG ByteCount,
+ PIRP Irp)
+{
+ KIRQL Irql;
+ NTSTATUS Status;
+ PFDO_DEVICE_EXTENSION FdoDevExt = Device->DeviceExtension;
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+ DevExt->CurrentIrp = Irp;
+ DevExt->CurrentIrpDevice = Device;
+
+ if (Idle != DevExt->Packet.State) {
+ Status = STATUS_DEVICE_BUSY;
+ goto startpacketdone;
+ }
+
+ DevExt->Packet.Bytes = Bytes;
+ DevExt->Packet.CurrentByte = 0;
+ DevExt->Packet.ByteCount = ByteCount;
+ DevExt->Packet.State = SendingBytes;
+ DevExt->PacketResult = Status = STATUS_PENDING;
+
+ if (Mouse == FdoDevExt->Type)
+ DevExt->PacketPort = 0xD4;
+ else
+ DevExt->PacketPort = 0;
+
+ if (!I8042PacketWrite(DevExt)) {
+ Status = STATUS_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_TIMEOUT;
+ DevExt->PacketResends = 0;
+ return TRUE;
+ }
+ DevExt->Packet.CurrentByte--;
+ break;
+
+ case KBD_NACK:
+ DevExt->Packet.State = Idle;
+ DevExt->PacketComplete = TRUE;
+ DevExt->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
+ DevExt->PacketResends = 0;
+ return TRUE;
+
+ default:
+ DevExt->PacketResends = 0;
+ }
+
+ if (DevExt->Packet.CurrentByte >= DevExt->Packet.ByteCount) {
+ DevExt->Packet.State = Idle;
+ DevExt->PacketComplete = TRUE;
+ DevExt->PacketResult = STATUS_SUCCESS;
+ return TRUE;
+ }
+
+ if (!I8042PacketWrite(DevExt)) {
+ DevExt->Packet.State = Idle;
+ DevExt->PacketComplete = TRUE;
+ DevExt->PacketResult = STATUS_TIMEOUT;
+ return TRUE;
+ }
+ DevExt->Packet.CurrentByte++;
+
+ return TRUE;
+}
+
+VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
+{
+ BOOL FinishIrp = FALSE;
+ NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
+ KIRQL Irql;
+
+ /* If the interrupt happens before this is setup, the key
+ * was already in the buffer. Too bad! */
+ if (!DevExt->HighestDIRQLInterrupt)
+ return;
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+ if (Idle == DevExt->Packet.State &&
+ DevExt->PacketComplete) {
+ FinishIrp = TRUE;
+ Result = DevExt->PacketResult;
+ DevExt->PacketComplete = FALSE;
+ }
+
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt,
+ Irql);
+
+ if (!FinishIrp)
+ return;
+
+ if (DevExt->CurrentIrp) {
+ DevExt->CurrentIrp->IoStatus.Status = Result;
+ IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
+ IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
+ DevExt->CurrentIrp = NULL;
+ DevExt->CurrentIrpDevice = NULL;
+ }
+}
+
+VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
+ PVOID Context)
+{
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ PDEVICE_EXTENSION DevExt;
+ PFDO_DEVICE_EXTENSION FdoDevExt;
+ PIRP NewIrp;
+ PI8042_HOOK_WORKITEM WorkItemData = (PI8042_HOOK_WORKITEM)Context;
+
+ ULONG IoControlCode;
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ BOOLEAN IsKbd;
+
+ DPRINT("HookWorkItem\n");
+
+ FdoDevExt = (PFDO_DEVICE_EXTENSION)
+ DeviceObject->DeviceExtension;
+
+ DevExt = FdoDevExt->PortDevExt;
+
+ if (WorkItemData->Target == DevExt->KeyboardData.ClassDeviceObject) {
+ IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
+ InputBuffer = &DevExt->KeyboardHook;
+ InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
+ IsKbd = TRUE;
+ DPRINT ("is for keyboard.\n");
+ } else if (WorkItemData->Target == DevExt->MouseData.ClassDeviceObject){
+ IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
+ InputBuffer = &DevExt->MouseHook;
+ InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
+ IsKbd = FALSE;
+ DPRINT ("is for mouse.\n");
+ } else {
+ DPRINT1("I8042SendHookWorkItem: Can't find DeviceObject\n");
+ WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
+ goto hookworkitemdone;
+ }
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ NewIrp = IoBuildDeviceIoControlRequest(
+ IoControlCode,
+ WorkItemData->Target,
+ InputBuffer,
+ InputBufferLength,
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatus);
+
+ if (!NewIrp) {
+ DPRINT("IOCTL_INTERNAL_(device)_CONNECT: "
+ "Can't allocate IRP\n");
+ WorkItemData->Irp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ goto hookworkitemdone;
+ }
+
+ Status = IoCallDriver(
+ WorkItemData->Target,
+ NewIrp);
+
+ if (STATUS_PENDING == Status)
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ if (IsKbd) {
+ /* Call the hooked initialization if it exists */
+ if (DevExt->KeyboardHook.InitializationRoutine) {
+ Status = DevExt->KeyboardHook.InitializationRoutine(
+ DevExt->KeyboardHook.Context,
+ DevExt,
+ I8042SynchReadPort,
+ I8042SynchWritePortKbd,
+ FALSE);
+ if (Status != STATUS_SUCCESS) {
+ WorkItemData->Irp->IoStatus.Status = Status;
+ goto hookworkitemdone;
+ }
+ }
+ /* TODO: Now would be the right time to enable the interrupt */
+
+ DevExt->KeyboardClaimed = TRUE;
+ } else {
+ /* Mouse doesn't have this, but we need to send a
+ * reset to start the detection.
+ */
+ KIRQL Irql;
+
+ Irql = KeAcquireInterruptSpinLock(
+ DevExt->HighestDIRQLInterrupt);
+
+ I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
+ I8042Write(DevExt, I8042_DATA_PORT, 0xFF);
+
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+ }
+
+ WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
+
+hookworkitemdone:
+ WorkItemData->Irp->IoStatus.Information = 0;
+ IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
+
+ IoFreeWorkItem(WorkItemData->WorkItem);
+ ExFreePool(WorkItemData);
+ DPRINT("HookWorkItem done\n");
+}
+
+VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ if (!I8042StartIoKbd(DeviceObject, Irp)) {
+ DPRINT1("Unhandled StartIo!\n");
+ }
+}
+
+NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+
+ DPRINT("InternalDeviceControl\n");
+
+ switch (FdoDevExt->Type) {
+ case Keyboard:
+ Status = I8042InternalDeviceControlKbd(DeviceObject, Irp);
+ break;
+ case Mouse:
+ Status = I8042InternalDeviceControlMouse(DeviceObject, Irp);
+ break;
+ }
+
+ if (Status == STATUS_INVALID_DEVICE_REQUEST) {
+ DPRINT1("Invalid internal device request!\n");
+ }
+
+ if (Status != STATUS_PENDING)
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS Status;
+
+ DPRINT ("I8042CreateDispatch\n");
+
+ Status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
+{
+ NTSTATUS Status;
+ UCHAR Value;
+ UINT Counter;
+
+ I8042Flush();
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST))
+ return STATUS_TIMEOUT;
+
+ // Wait longer?
+ Counter = 3;
+ do {
+ Status = I8042ReadDataWait(DevExt, &Value);
+ } while ((Counter--) && (STATUS_TIMEOUT == Status));
+
+ if (Status != STATUS_SUCCESS)
+ 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_LINE_TEST))
+ return STATUS_TIMEOUT;
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS)
+ return Status;
+
+ if (Value == 0) {
+ DevExt->KeyboardExists = TRUE;
+ } else {
+ DevExt->KeyboardExists = FALSE;
+ }
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
+ return STATUS_TIMEOUT;
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS)
+ return Status;
+
+ if (Value == 0) {
+ DevExt->MouseExists = TRUE;
+ } else {
+ DevExt->MouseExists = FALSE;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
+{
+ NTSTATUS Status;
+
+ Status = I8042BasicDetect(DevExt);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT1("Basic keyboard detection failed: %x\n", Status);
+ return Status;
+ }
+
+ if (!DevExt->KeyboardExists) {
+ DPRINT("Keyboard not detected\n")
+ if (DevExt->Settings.Headless)
+ /* Act as if it exists regardless */
+ DevExt->KeyboardExists = TRUE;
+ } else {
+ DPRINT("Keyboard detected\n");
+ DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
+ }
+
+ if (DevExt->KeyboardExists) {
+ I8042KeyboardEnable(DevExt);
+ I8042KeyboardEnableInterrupt(DevExt);
+ }
+
+ if (DevExt->MouseExists)
+ I8042MouseEnable(DevExt);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT Pdo)
+{
+ UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\KeyboardClass0");
+ UNICODE_STRING MouseName = ROS_STRING_INITIALIZER(L"\\Device\\PointerClass0");
+ ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
+ KIRQL DirqlKeyboard = 0;
+ KIRQL DirqlMouse = 0;
+ KIRQL DirqlMax;
+ KAFFINITY Affinity;
+ NTSTATUS Status;
+ PDEVICE_EXTENSION DevExt;
+ PFDO_DEVICE_EXTENSION FdoDevExt;
+ PDEVICE_OBJECT Fdo;
+
+ DPRINT("I8042AddDevice\n");
+
+ IoCreateDevice(DriverObject,
+ sizeof(DEVICE_EXTENSION),
+ NULL,
+ FILE_DEVICE_8042_PORT,
+ FILE_DEVICE_SECURE_OPEN,
+ TRUE,
+ &Fdo);
+
+ IoAttachDeviceToDeviceStack(Fdo, Pdo);
+
+ DevExt = Fdo->DeviceExtension;
+
+ RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
+
+ I8042ReadRegistry(DriverObject, DevExt);
+
+ KeInitializeSpinLock(&DevExt->SpinLock);
+ InitializeListHead(&DevExt->BusDevices);
+
+ KeInitializeDpc(&DevExt->DpcKbd,
+ I8042DpcRoutineKbd,
+ DevExt);
+
+ KeInitializeDpc(&DevExt->DpcMouse,
+ I8042DpcRoutineMouse,
+ DevExt);
+
+ KeInitializeDpc(&DevExt->DpcMouseTimeout,
+ I8042DpcRoutineMouseTimeout,
+ DevExt);
+
+ KeInitializeTimer(&DevExt->TimerMouseTimeout);
+
+ Status = I8042Initialize(DevExt);
+ if (STATUS_SUCCESS != Status) {
+ 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);
+
+ FdoDevExt = Fdo->DeviceExtension;
+
+ RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
+
+ FdoDevExt->PortDevExt = DevExt;
+ FdoDevExt->Type = Keyboard;
+ FdoDevExt->DeviceObject = Fdo;
+
+ Fdo->Flags |= DO_BUFFERED_IO;
+
+ DevExt->DebugWorkItem = IoAllocateWorkItem(Fdo);
+ DevExt->KeyboardObject = Fdo;
+
+ DevExt->KeyboardBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ DevExt->KeyboardAttributes.InputDataQueueLength *
+ sizeof(KEYBOARD_INPUT_DATA),
+ TAG_I8042);
+
+ if (!DevExt->KeyboardBuffer) {
+ DPRINT1("No memory for keyboardbuffer\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
+ }
+
+ 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);
+
+ FdoDevExt = Fdo->DeviceExtension;
+
+ RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
+
+ FdoDevExt->PortDevExt = DevExt;
+ FdoDevExt->Type = Mouse;
+ FdoDevExt->DeviceObject = Fdo;
+
+ Fdo->Flags |= DO_BUFFERED_IO;
+ DevExt->MouseObject = Fdo;
+
+ DevExt->MouseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ DevExt->MouseAttributes.InputDataQueueLength *
+ sizeof(MOUSE_INPUT_DATA),
+ TAG_I8042);
+
+ if (!DevExt->MouseBuffer) {
+ ExFreePool(DevExt->KeyboardBuffer);
+ DPRINT1("No memory for mouse buffer\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
+ }
+
+ if (DirqlKeyboard > DirqlMouse)
+ DirqlMax = DirqlKeyboard;
+ else
+ DirqlMax = DirqlMouse;
+
+ if (DevExt->KeyboardExists) {
+ Status = IoConnectInterrupt(&DevExt->KeyboardInterruptObject,
+ I8042InterruptServiceKbd,
+ (PVOID)DevExt,
+ &DevExt->SpinLock,
+ MappedIrqKeyboard,
+ DirqlKeyboard,
+ DirqlMax,
+ LevelSensitive,
+ FALSE,
+ Affinity,
+ FALSE);
+
+ DPRINT("Keyboard Irq Status: %x\n", Status);
+ }
+
+ if (DevExt->MouseExists) {
+ Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
+ I8042InterruptServiceMouse,
+ (PVOID)DevExt,
+ &DevExt->SpinLock,
+ MappedIrqMouse,
+ DirqlMouse,
+ DirqlMax,
+ LevelSensitive,
+ FALSE,
+ Affinity,
+ FALSE);
+
+ DPRINT("Mouse Irq Status: %x\n", Status);
+ }
+
+ if (DirqlKeyboard > DirqlMouse)
+ DevExt->HighestDIRQLInterrupt = DevExt->KeyboardInterruptObject;
+ else
+ DevExt->HighestDIRQLInterrupt = DevExt->MouseInterruptObject;
+
+ DPRINT("I8042AddDevice done\n");
+
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Module entry point
+ */
+{
+ DPRINT("I8042 Driver 0.0.1\n");
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ I8042InternalDeviceControl;
+
+ DriverObject->DriverStartIo = I8042StartIo;
+ DriverObject->DriverExtension->AddDevice = I8042AddDevice;
+
+ return(STATUS_SUCCESS);
+}
+
--- /dev/null
+#ifndef _I8042DRV_H
+#define _I8042DRV_H
+#include <ddk/ntddk.h>
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define KEYBOARD_IRQ 1
+#define MOUSE_IRQ 12
+#define KBD_BUFFER_SIZE 32
+
+// should be in ntdd8042.h
+
+typedef VOID DDKAPI
+(*KEYBOARD_CLASS_SERVICE_CALLBACK) (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PKEYBOARD_INPUT_DATA InputDataStart,
+ IN PKEYBOARD_INPUT_DATA InputDataEnd,
+ IN OUT PULONG InputDataConsumed
+);
+
+/* I'm not actually sure if this is in the ddk, would seem logical */
+typedef VOID DDKAPI
+(*MOUSE_CLASS_SERVICE_CALLBACK) (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PMOUSE_INPUT_DATA InputDataStart,
+ IN PMOUSE_INPUT_DATA InputDataEnd,
+ IN OUT PULONG InputDataConsumed
+);
+
+typedef struct _CONNECT_DATA {
+ PDEVICE_OBJECT ClassDeviceObject;
+ PVOID ClassService;
+} CONNECT_DATA, *PCONNECT_DATA;
+
+#define IOCTL_INTERNAL_KEYBOARD_CONNECT \
+ CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#define IOCTL_INTERNAL_MOUSE_CONNECT \
+ CTL_CODE(FILE_DEVICE_MOUSE, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+/* For some bizarre reason, these are different from the defines in
+ * w32api. I'm quite sure these are correct though, needs to be checked
+ * against the ddk
+ */
+#define KEYBOARD_SCROLL_LOCK_ON 0x01
+#define KEYBOARD_NUM_LOCK_ON 0x02
+#define KEYBOARD_CAPS_LOCK_ON 0x04
+
+/*-----------------------------------------------------
+ * DeviceExtension
+ * --------------------------------------------------*/
+typedef struct _COMMAND_CONTEXT
+{
+ int NumInput;
+ int CurInput;
+ UCHAR * Input;
+ int NumOutput;
+ int CurOutput;
+ UCHAR * Output;
+ NTSTATUS Status;
+
+ BOOLEAN GotAck;
+ KEVENT Event;
+
+ PVOID DevExt;
+} COMMAND_CONTEXT, *PCOMMAND_CONTEXT;
+
+typedef enum _MOUSE_TIMEOUT_STATE
+{
+ NoChange,
+ TimeoutStart,
+ TimeoutCancel
+} MOUSE_TIMEOUT_STATE, *PMOUSE_TIMEOUT_STATE;
+
+/* TODO: part of this should be in the _ATTRIBUTES structs instead */
+typedef struct _I8042_SETTINGS
+{
+ DWORD Headless; /* done */
+ DWORD CrashScroll;
+ DWORD CrashSysRq; /* done */
+ DWORD ReportResetErrors;
+ DWORD PollStatusIterations; /* done */
+ DWORD ResendIterations; /* done */
+ DWORD PollingIterations;
+ DWORD PollingIterationsMaximum;
+ DWORD OverrideKeyboardType;
+ DWORD OverrideKeyboardSubtype;
+ DWORD MouseResendStallTime;
+ DWORD MouseSynchIn100ns;
+ DWORD MouseResolution;
+ DWORD NumberOfButtons;
+ DWORD EnableWheelDetection;
+} I8042_SETTINGS, *PI8042_SETTINGS;
+
+typedef enum _I8042_MOUSE_TYPE
+{
+ GenericPS2,
+ Intellimouse,
+ IntellimouseExplorer,
+ Ps2pp
+} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
+
+typedef enum _I8042_DEVICE_TYPE
+{
+ Keyboard,
+ Mouse
+} I8042_DEVICE_TYPE, *PI8042_DEVICE_TYPE;
+
+typedef struct _I8042_DEVICE
+{
+ LIST_ENTRY ListEntry;
+ PDEVICE_OBJECT Pdo;
+} I8042_DEVICE, *PI8042_DEVICE;
+
+typedef struct _DEVICE_EXTENSION
+{
+ PDEVICE_OBJECT KeyboardObject;
+ PDEVICE_OBJECT MouseObject;
+
+ CONNECT_DATA KeyboardData;
+ CONNECT_DATA MouseData;
+
+ BOOLEAN KeyboardExists;
+ BOOLEAN KeyboardIsAT;
+ BOOLEAN MouseExists;
+
+ BOOLEAN KeyboardClaimed;
+ BOOLEAN MouseClaimed;
+
+ ULONG BusNumber;
+ LIST_ENTRY BusDevices;
+
+ INTERNAL_I8042_START_INFORMATION KeyboardStartInformation;
+ INTERNAL_I8042_START_INFORMATION MouseStartInformation;
+
+ INTERNAL_I8042_HOOK_KEYBOARD KeyboardHook;
+ INTERNAL_I8042_HOOK_MOUSE MouseHook;
+
+ PKINTERRUPT KeyboardInterruptObject;
+ PKINTERRUPT MouseInterruptObject;
+ PKINTERRUPT HighestDIRQLInterrupt;
+ KSPIN_LOCK SpinLock;
+ KDPC DpcKbd;
+ KDPC DpcMouse;
+
+ KTIMER TimerMouseTimeout;
+ KDPC DpcMouseTimeout;
+ MOUSE_TIMEOUT_STATE MouseTimeoutState;
+ BOOLEAN MouseTimeoutActive;
+
+ KEYBOARD_ATTRIBUTES KeyboardAttributes;
+ KEYBOARD_INDICATOR_PARAMETERS KeyboardIndicators;
+ KEYBOARD_TYPEMATIC_PARAMETERS KeyboardTypematic;
+
+ BOOLEAN WantAck;
+ BOOLEAN WantOutput;
+ BOOLEAN SignalEvent;
+
+ KEYBOARD_SCAN_STATE KeyboardScanState;
+ BOOLEAN KeyComplete;
+ KEYBOARD_INPUT_DATA *KeyboardBuffer;
+ ULONG KeysInBuffer;
+
+ MOUSE_ATTRIBUTES MouseAttributes;
+
+ MOUSE_STATE MouseState;
+ BOOLEAN MouseComplete;
+ MOUSE_RESET_SUBSTATE MouseResetState;
+ MOUSE_INPUT_DATA *MouseBuffer;
+ ULONG MouseInBuffer;
+ USHORT MouseButtonState;
+
+ UCHAR MouseLogiBuffer[3];
+ UCHAR MouseLogitechID;
+ I8042_MOUSE_TYPE MouseType;
+
+ OUTPUT_PACKET Packet;
+ UINT PacketResends;
+ BOOLEAN PacketComplete;
+ NTSTATUS PacketResult;
+ UCHAR PacketBuffer[16];
+ UCHAR PacketPort;
+
+ PIRP CurrentIrp;
+ PDEVICE_OBJECT CurrentIrpDevice;
+
+ /* registry config values */
+ I8042_SETTINGS Settings;
+
+ /* Debugger stuff */
+ BOOLEAN TabPressed;
+ ULONG DebugKey;
+ PIO_WORKITEM DebugWorkItem;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+typedef struct _FDO_DEVICE_EXTENSION
+{
+ PDEVICE_EXTENSION PortDevExt;
+ I8042_DEVICE_TYPE Type;
+ PDEVICE_OBJECT DeviceObject;
+
+ LIST_ENTRY BusDevices;
+} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
+
+typedef struct _I8042_HOOK_WORKITEM
+{
+ PIO_WORKITEM WorkItem;
+ PDEVICE_OBJECT Target;
+ PIRP Irp;
+} I8042_HOOK_WORKITEM, *PI8042_HOOK_WORKITEM;
+
+/*
+ * Some defines
+ */
+#define TAG_I8042 TAG('8', '0', '4', '2')
+
+#define KBD_WRAP_MASK 0x1F
+
+#define disable() __asm__("cli\n\t")
+#define enable() __asm__("sti\n\t")
+
+#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 0x60
+#define I8042_CTRL_PORT 0x64
+
+
+/*
+ * Controller commands
+ */
+
+#define KBD_READ_MODE 0x20
+#define KBD_WRITE_MODE 0x60
+#define KBD_SELF_TEST 0xAA
+#define KBD_LINE_TEST 0xAB
+#define KBD_CTRL_ENABLE 0xAE
+
+#define MOUSE_LINE_TEST 0xA9
+#define MOUSE_CTRL_ENABLE 0xA8
+
+#define KBD_READ_OUTPUT_PORT 0xD0
+#define KBD_WRITE_OUTPUT_PORT 0xD1
+
+/*
+ * Keyboard commands
+ */
+
+#define KBD_SET_LEDS 0xED
+#define KBD_GET_ID 0xF2
+#define KBD_ENABLE 0xF4
+#define KBD_DISABLE 0xF5
+#define KBD_RESET 0xFF
+
+
+/*
+ * Keyboard responces
+ */
+
+#define KBD_BATCC 0xAA
+#define KBD_ACK 0xFA
+#define KBD_NACK 0xFC
+#define KBD_RESEND 0xFE
+
+/*
+ * Controller status register bits
+ */
+
+#define KBD_OBF 0x01
+#define KBD_IBF 0x02
+#define KBD_AUX 0x10
+#define KBD_GTO 0x40
+#define KBD_PERR 0x80
+
+
+/*
+ * LED bits
+ */
+
+#define KBD_LED_SCROLL 0x01
+#define KBD_LED_NUM 0x02
+#define KBD_LED_CAPS 0x04
+
+/*
+ * Mouse responses
+ */
+#define MOUSE_ACK 0xFA
+#define MOUSE_ERROR 0xFC
+#define MOUSE_NACK 0xFE
+
+/* i8042prt.c */
+NTSTATUS I8042ReadData(BYTE *Data);
+
+NTSTATUS I8042ReadStatus(BYTE *Status);
+
+NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data);
+
+VOID I8042Flush();
+
+VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
+ UCHAR Value,
+ UCHAR SelectCmd);
+
+NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
+ UCHAR Port,
+ UCHAR Value,
+ BOOLEAN WaitForAck);
+
+NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
+ PDEVICE_OBJECT Device,
+ PUCHAR Bytes,
+ ULONG ByteCount,
+ PIRP Irp);
+
+BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
+ UCHAR Output);
+
+VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt);
+
+VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
+ PVOID Context);
+
+BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data);
+
+/* keyboard.c */
+VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
+ UCHAR Value);
+
+NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
+ UCHAR Value,
+ BOOLEAN WaitForAck);
+
+BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
+ VOID * Context);
+
+VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+
+BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt);
+
+BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt);
+
+BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt);
+
+/* registry.c */
+VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
+ PDEVICE_EXTENSION DevExt);
+
+/* mouse.c */
+VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2);
+
+BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
+ VOID *Context);
+
+NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp);
+
+VOID STDCALL I8042QueueMousePacket(PVOID Context);
+
+VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
+ USHORT Mask);
+
+VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
+ BYTE Output);
+
+BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt);
+BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt);
+
+/* ps2pp.c */
+VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, BYTE Input);
+
+#endif // _KEYBOARD_H_
--- /dev/null
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "I8042 Port Device Driver\0"
+#define REACTOS_STR_INTERNAL_NAME "i8042prt\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "i8042prt.sys\0"
+#include <reactos/version.rc>
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: drivers/input/i8042prt/keyboard.c
+ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
+ * keyboard specifics
+ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
+ * Jason Filby (jasonfilby@yahoo.com)
+ * Tinus
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* GLOBALS *******************************************************************/
+
+static BYTE TypematicTable[] = {
+ 0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /* 0-9 */
+ 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
+ 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };
+
+typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
+ USHORT NumberOfIndicatorKeys;
+ INDICATOR_LIST IndicatorList[3];
+} LOCAL_KEYBOARD_INDICATOR_TRANSLATION, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION;
+
+static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, {
+ {0x3A, KEYBOARD_CAPS_LOCK_ON},
+ {0x45, KEYBOARD_NUM_LOCK_ON},
+ {0x46, KEYBOARD_SCROLL_LOCK_ON}}};
+
+static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
+ PVOID Context);
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * These functions are callbacks for filter driver custom interrupt
+ * service routines.
+ */
+VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
+ UCHAR Value)
+{
+ I8042IsrWritePort(Context, Value, 0);
+}
+
+static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
+{
+ PDEVICE_OBJECT DeviceObject = Context;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+ DevExt->KeyComplete = TRUE;
+ DevExt->KeysInBuffer++;
+ if (DevExt->KeysInBuffer >
+ DevExt->KeyboardAttributes.InputDataQueueLength) {
+ DPRINT1("Keyboard buffer overflow\n");
+ DevExt->KeysInBuffer--;
+ }
+
+ DPRINT("Irq completes key\n");
+ KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
+ UCHAR Value,
+ BOOLEAN WaitForAck)
+{
+ return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
+ 0,
+ Value,
+ WaitForAck);
+}
+
+BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
+ VOID * Context)
+{
+ BYTE Output;
+ BYTE PortStatus;
+ NTSTATUS Status;
+ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
+ BOOLEAN HookContinue = FALSE, HookReturn;
+ UINT Iterations = 0;
+
+ KEYBOARD_INPUT_DATA *InputData =
+ DevExt->KeyboardBuffer + DevExt->KeysInBuffer;
+
+ do {
+ Status = I8042ReadStatus(&PortStatus);
+ DPRINT("PortStatus: %x\n", PortStatus);
+ Status = I8042ReadData(&Output);
+ Iterations++;
+ if (STATUS_SUCCESS == Status)
+ break;
+ KeStallExecutionProcessor(1);
+ } while (Iterations < DevExt->Settings.PollStatusIterations);
+
+ if (STATUS_SUCCESS != Status) {
+ DPRINT1("Spurious I8042 interrupt\n");
+ return FALSE;
+ }
+
+ DPRINT("Got: %x\n", Output);
+
+ if (DevExt->KeyboardHook.IsrRoutine) {
+ HookReturn = DevExt->KeyboardHook.IsrRoutine(
+ DevExt->KeyboardHook.Context,
+ InputData,
+ &DevExt->Packet,
+ PortStatus,
+ &Output,
+ &HookContinue,
+ &DevExt->KeyboardScanState);
+
+ if (!HookContinue)
+ return HookReturn;
+ }
+
+ if (I8042PacketIsr(DevExt, Output)) {
+ if (DevExt->PacketComplete) {
+ DPRINT("Packet complete\n");
+ KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+ }
+ DPRINT("Irq eaten by packet\n");
+ return TRUE;
+ }
+
+ DPRINT("Irq is keyboard input\n");
+
+ if (Normal == DevExt->KeyboardScanState) {
+ switch (Output) {
+ case 0xe0:
+ DevExt->KeyboardScanState = GotE0;
+ return TRUE;
+ case 0xe1:
+ DevExt->KeyboardScanState = GotE1;
+ return TRUE;
+ default:
+ ;/* continue */
+ }
+ }
+
+ InputData->Flags = 0;
+
+ switch (DevExt->KeyboardScanState) {
+ case GotE0:
+ InputData->Flags |= KEY_E0;
+ break;
+ case GotE1:
+ InputData->Flags |= KEY_E1;
+ break;
+ default:
+ ;
+ }
+ DevExt->KeyboardScanState = Normal;
+
+ if (Output & 0x80)
+ InputData->Flags |= KEY_BREAK;
+ else
+ InputData->Flags |= KEY_MAKE;
+
+ InputData->MakeCode = Output & 0x7f;
+
+ I8042QueueKeyboardPacket(DevExt->KeyboardObject);
+
+ return TRUE;
+}
+
+VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+ ULONG KeysTransferred = 0;
+ ULONG KeysInBufferCopy;
+ KIRQL Irql;
+
+ I8042PacketDpc(DevExt);
+
+ if (!DevExt->KeyComplete)
+ return;
+
+ /* We got the interrupt as it was being enabled, too bad */
+ if (!DevExt->HighestDIRQLInterrupt)
+ return;
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+ DevExt->KeyComplete = FALSE;
+ KeysInBufferCopy = DevExt->KeysInBuffer;
+
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+
+ /* Test for TAB (debugging) */
+ if (DevExt->Settings.CrashSysRq) {
+ PKEYBOARD_INPUT_DATA InputData = DevExt->KeyboardBuffer +
+ KeysInBufferCopy - 1;
+ if (InputData->MakeCode == 0x0F) {
+ DPRINT("Tab!\n");
+ DevExt->TabPressed = !(InputData->Flags & KEY_BREAK);
+ } else if (DevExt->TabPressed) {
+ DPRINT ("Queueing work item %x\n", DevExt->DebugWorkItem);
+ DevExt->DebugKey = InputData->MakeCode;
+ DevExt->TabPressed = FALSE;
+
+ IoQueueWorkItem(DevExt->DebugWorkItem,
+ &(I8042DebugWorkItem),
+ DelayedWorkQueue,
+ DevExt);
+ }
+ }
+
+ DPRINT ("Send a key\n");
+
+ if (!DevExt->KeyboardData.ClassService)
+ return;
+
+ ((KEYBOARD_CLASS_SERVICE_CALLBACK) DevExt->KeyboardData.ClassService)(
+ DevExt->KeyboardData.ClassDeviceObject,
+ DevExt->KeyboardBuffer,
+ DevExt->KeyboardBuffer + KeysInBufferCopy,
+ &KeysTransferred);
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+ DevExt->KeysInBuffer -= KeysTransferred;
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+}
+
+/* You have to send the rate/delay in a somewhat awkward format */
+static USHORT I8042GetTypematicByte(USHORT Rate, USHORT Delay)
+{
+ USHORT ret;
+
+ if (Rate < 3) {
+ ret = 0x0;
+ } else if (Rate > 26) {
+ ret = 0x1F;
+ } else {
+ ret = TypematicTable[Rate];
+ }
+
+ if (Delay < 375) {
+ ;
+ } else if (Delay < 625) {
+ ret |= 0x20;
+ } else if (Delay < 875) {
+ ret |= 0x40;
+ } else {
+ ret |= 0x60;
+ }
+ return ret;
+}
+/*
+ * Process the keyboard internal device requests
+ * returns FALSE if it doesn't understand the
+ * call so someone else can handle it.
+ */
+BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PIO_STACK_LOCATION Stk;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+ Stk = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+ case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
+ I8042StartPacket(
+ DevExt,
+ DeviceObject,
+ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+ Stk->Parameters.DeviceIoControl.InputBufferLength,
+ Irp);
+ break;
+
+ case IOCTL_KEYBOARD_SET_INDICATORS:
+ DevExt->PacketBuffer[0] = 0xED;
+ DevExt->PacketBuffer[1] = 0;
+ if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
+ DevExt->PacketBuffer[1] |= 0x04;
+
+ if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
+ DevExt->PacketBuffer[1] |= 0x02;
+
+ if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
+ DevExt->PacketBuffer[1] |= 0x01;
+
+ I8042StartPacket(DevExt,
+ DeviceObject,
+ DevExt->PacketBuffer,
+ 2,
+ Irp);
+ break;
+ case IOCTL_KEYBOARD_SET_TYPEMATIC:
+ DevExt->PacketBuffer[0] = 0xF3;
+ DevExt->PacketBuffer[1] = I8042GetTypematicByte(
+ DevExt->KeyboardTypematic.Rate,
+ DevExt->KeyboardTypematic.Delay);
+
+ I8042StartPacket(DevExt,
+ DeviceObject,
+ DevExt->PacketBuffer,
+ 2,
+ Irp);
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Runs the keyboard IOCTL_INTERNAL dispatch.
+ * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
+ * so someone else can have a try at it.
+ */
+NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PIO_STACK_LOCATION Stk;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+ DPRINT("InternalDeviceControl\n");
+
+ Irp->IoStatus.Information = 0;
+ Stk = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_INTERNAL_KEYBOARD_CONNECT:
+ DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(CONNECT_DATA)) {
+ DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ goto intcontfailure;
+ }
+
+ if (!DevExt->KeyboardExists) {
+ Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+ goto intcontfailure;
+ }
+
+ if (DevExt->KeyboardClaimed) {
+ DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
+ "Keyboard is already claimed\n");
+ Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
+ goto intcontfailure;
+ }
+
+ memcpy(&DevExt->KeyboardData,
+ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+ sizeof(CONNECT_DATA));
+ DevExt->KeyboardHook.IsrWritePort = I8042IsrWritePortKbd;
+ DevExt->KeyboardHook.QueueKeyboardPacket =
+ I8042QueueKeyboardPacket;
+ DevExt->KeyboardHook.CallContext = DevExt;
+
+ {
+ PIO_WORKITEM WorkItem;
+ PI8042_HOOK_WORKITEM WorkItemData;
+
+ WorkItem = IoAllocateWorkItem(DeviceObject);
+ if (!WorkItem) {
+ DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
+ "Can't allocate work item\n");
+ Irp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ goto intcontfailure;
+ }
+
+ WorkItemData = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(I8042_HOOK_WORKITEM),
+ TAG_I8042);
+ if (!WorkItemData) {
+ DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
+ "Can't allocate work item data\n");
+ Irp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoFreeWorkItem(WorkItem);
+ goto intcontfailure;
+ }
+ WorkItemData->WorkItem = WorkItem;
+ WorkItemData->Target =
+ DevExt->KeyboardData.ClassDeviceObject;
+ WorkItemData->Irp = Irp;
+
+ IoMarkIrpPending(Irp);
+ IoQueueWorkItem(WorkItem,
+ I8042SendHookWorkItem,
+ DelayedWorkQueue,
+ WorkItemData);
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ }
+
+ break;
+ case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
+ DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ goto intcontfailure;
+ }
+ if (!DevExt->KeyboardInterruptObject) {
+ Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+ goto intcontfailure;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+ break;
+ case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
+ DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
+ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof(KEYBOARD_ATTRIBUTES)) {
+ DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+ memcpy(Irp->AssociatedIrp.SystemBuffer,
+ &DevExt->KeyboardAttributes,
+ sizeof(KEYBOARD_ATTRIBUTES));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ case IOCTL_KEYBOARD_QUERY_INDICATORS:
+ DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
+ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
+ DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+ memcpy(Irp->AssociatedIrp.SystemBuffer,
+ &DevExt->KeyboardIndicators,
+ sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
+ DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
+ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
+ DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+ memcpy(Irp->AssociatedIrp.SystemBuffer,
+ &DevExt->KeyboardTypematic,
+ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ case IOCTL_KEYBOARD_SET_INDICATORS:
+ DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
+ DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+
+ memcpy(&DevExt->KeyboardIndicators,
+ Irp->AssociatedIrp.SystemBuffer,
+ sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+
+ DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+ break;
+ case IOCTL_KEYBOARD_SET_TYPEMATIC:
+ DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
+ DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+
+ memcpy(&DevExt->KeyboardTypematic,
+ Irp->AssociatedIrp.SystemBuffer,
+ sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+ break;
+ case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+ /* We should check the UnitID, but it's kind of pointless as
+ * all keyboards are supposed to have the same one
+ */
+ if (Stk->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) {
+ DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
+ "invalid buffer size (expected)\n");
+ /* It's to query the buffer size */
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+ Irp->IoStatus.Information =
+ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
+
+ memcpy(Irp->AssociatedIrp.SystemBuffer,
+ &IndicatorTranslation,
+ sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
+ /* Nothing to do here */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ default:
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+intcontfailure:
+ return Irp->IoStatus.Status;
+}
+
+BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
+{
+ DPRINT("Enabling keyboard\n");
+ if (STATUS_SUCCESS != I8042SynchWritePort(DevExt,
+ 0,
+ KBD_ENABLE,
+ TRUE)) {
+ DPRINT("Can't enable keyboard\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
+{
+ UCHAR Value;
+ NTSTATUS Status;
+
+ DPRINT("Enabling keyboard interrupt\n");
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+ DPRINT1("Can't read i8042 mode\n");
+ return FALSE;
+ }
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT1("No response after read i8042 mode\n");
+ return FALSE;
+ }
+
+ Value &= ~(0x10); // don't disable keyboard
+ Value |= 0x01; // enable keyboard interrupts
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+ DPRINT1("Can't set i8042 mode\n");
+ return FALSE;
+ }
+
+ if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+ DPRINT1("Can't send i8042 mode\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
+{
+ NTSTATUS Status;
+ UCHAR Value;
+ UINT RetryCount = 10;
+
+ DPRINT("Detecting keyboard\n");
+
+ do {
+ Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
+ } while (STATUS_TIMEOUT == Status && RetryCount--);
+
+ if (Status != STATUS_SUCCESS) {
+ DPRINT("Can't write GET_ID (%x)\n", Status);
+ return FALSE;
+ }
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS) {
+ 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;
+ }
+
+ DPRINT("Keyboard ID: %x", Value);
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT("Partial ID\n");
+ return FALSE;
+ }
+
+ DPRINT ("%x\n", Value);
+
+detectsetleds:
+ Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT("Can't write SET_LEDS (%x)\n", Status);
+ return FALSE;
+ }
+ Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT("Can't finish SET_LEDS (%x)\n", Status);
+ return FALSE;
+ }
+
+ // Turn on translation
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+ DPRINT1("Can't read i8042 mode\n");
+ return FALSE;
+ }
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT1("No response after read i8042 mode\n");
+ return FALSE;
+ }
+
+ Value |= 0x40; // enable keyboard translation
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+ DPRINT1("Can't set i8042 mode\n");
+ return FALSE;
+ }
+
+ if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+ DPRINT1("Can't send i8042 mode\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* debug stuff */
+VOID STDCALL
+KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2);
+
+static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
+ PVOID Context)
+{
+ ULONG Key;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+ Key = InterlockedExchange(&DevExt->DebugKey, 0);
+ DPRINT("Debug key: %x\n", Key);
+
+ if (!Key)
+ return;
+
+ KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
+}
--- /dev/null
+# $Id: makefile 12852 2005-01-06 13:58:04Z mf $
+
+PATH_TO_TOP = ../../..
+
+TARGET_BOOTSTRAP = yes
+
+TARGET_TYPE = driver
+
+TARGET_NAME = i8042prt
+
+TARGET_CFLAGS = -Wall -Werror -D__USE_W32API
+
+TARGET_OBJECTS = $(TARGET_NAME).o keyboard.o registry.o mouse.o ps2pp.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: drivers/input/i8042prt/mouse.c
+ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
+ * mouse specifics
+ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
+ * Jason Filby (jasonfilby@yahoo.com)
+ * Tinus
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/*
+ * These functions are callbacks for filter driver custom interrupt
+ * service routines.
+ */
+VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
+ UCHAR Value)
+{
+ I8042IsrWritePort(Context, Value, 0xD4);
+}
+
+NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
+ UCHAR Value,
+ BOOLEAN WaitForAck)
+{
+ return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
+ 0xD4,
+ Value,
+ WaitForAck);
+}
+
+/*
+ * 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)
+ */
+BOOLEAN STDCALL I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt,
+ UCHAR Status,
+ PUCHAR Input,
+ PBOOLEAN ToReturn)
+{
+ BOOLEAN HookReturn, HookContinue;
+
+ HookContinue = FALSE;
+
+ if (DevExt->MouseHook.IsrRoutine) {
+ HookReturn = DevExt->MouseHook.IsrRoutine(
+ DevExt->MouseHook.Context,
+ DevExt->MouseBuffer + DevExt->MouseInBuffer,
+ &DevExt->Packet,
+ Status,
+ Input,
+ &HookContinue,
+ &DevExt->MouseState,
+ &DevExt->MouseResetState);
+
+ if (!HookContinue) {
+ *ToReturn = HookReturn;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
+ UCHAR Status,
+ PUCHAR Value)
+{
+ BOOLEAN ToReturn;
+
+ if (I8042MouseCallIsrHook(DevExt, Status, Value, &ToReturn))
+ return ToReturn;
+
+ if (MouseResetting != DevExt->MouseState) {
+ return FALSE;
+ }
+ DevExt->MouseTimeoutState = TimeoutStart;
+
+ switch (DevExt->MouseResetState) {
+ case 1100: /* the first ack, drop it. */
+ DevExt->MouseResetState = ExpectingReset;
+ return TRUE;
+ /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
+ * FC00 if not.
+ */
+ case ExpectingReset:
+ if (0xAA == *Value) {
+ DevExt->MouseResetState++;
+ } else {
+ DevExt->MouseExists = FALSE;
+ DevExt->MouseState = MouseIdle;
+ DPRINT("Mouse returned bad reset reply: "
+ "%x (expected aa)\n", *Value);
+ }
+ return TRUE;
+ case ExpectingResetId:
+ if (0x00 == *Value) {
+ DevExt->MouseResetState++;
+ DevExt->MouseType = GenericPS2;
+ I8042IsrWritePortMouse(DevExt, 0xF2);
+ } else {
+ DevExt->MouseExists = FALSE;
+ DevExt->MouseState = MouseIdle;
+ DPRINT1("Mouse returned bad reset reply part two: "
+ "%x (expected 0)\n", Value);
+ }
+ return TRUE;
+ case ExpectingGetDeviceIdACK:
+ if (MOUSE_ACK == *Value) {
+ DevExt->MouseResetState++;
+ } else if (MOUSE_NACK == *Value ||
+ MOUSE_ERROR == *Value) {
+ DevExt->MouseResetState++;
+ /* Act as if 00 (normal mouse) was received */
+ DPRINT("Mouse doesn't support 0xd2, "
+ "(returns %x, expected %x), faking.\n",
+ *Value, MOUSE_ACK);
+ *Value = 0;
+ I8042MouseResetIsr(DevExt, Status, Value);
+ }
+ return TRUE;
+ case ExpectingGetDeviceIdValue:
+ switch (*Value) {
+ case 0x02:
+ DevExt->MouseAttributes.MouseIdentifier =
+ BALLPOINT_I8042_HARDWARE;
+ break;
+ case 0x03:
+ case 0x04:
+ DevExt->MouseAttributes.MouseIdentifier =
+ WHEELMOUSE_I8042_HARDWARE;
+ break;
+ default:
+ DevExt->MouseAttributes.MouseIdentifier =
+ MOUSE_I8042_HARDWARE;
+ }
+ DevExt->MouseResetState++;
+ I8042IsrWritePortMouse(DevExt, 0xE8);
+ return TRUE;
+ case ExpectingSetResolutionDefaultACK:
+ DevExt->MouseResetState++;
+ I8042IsrWritePortMouse(DevExt, 0x00);
+ return TRUE;
+ case ExpectingSetResolutionDefaultValueACK:
+ DevExt->MouseResetState = ExpectingSetScaling1to1ACK;
+ I8042IsrWritePortMouse(DevExt, 0xE6);
+ return TRUE;
+ case ExpectingSetScaling1to1ACK:
+ case ExpectingSetScaling1to1ACK2:
+ DevExt->MouseResetState++;
+ I8042IsrWritePortMouse(DevExt, 0xE6);
+ return TRUE;
+ case ExpectingSetScaling1to1ACK3:
+ DevExt->MouseResetState++;
+ I8042IsrWritePortMouse(DevExt, 0xE9);
+ return TRUE;
+ case ExpectingReadMouseStatusACK:
+ DevExt->MouseResetState++;
+ return TRUE;
+ case ExpectingReadMouseStatusByte1:
+ DevExt->MouseLogiBuffer[0] = *Value;
+ DevExt->MouseResetState++;
+ return TRUE;
+ case ExpectingReadMouseStatusByte2:
+ DevExt->MouseLogiBuffer[1] = *Value;
+ DevExt->MouseResetState++;
+ return TRUE;
+ case ExpectingReadMouseStatusByte3:
+ DevExt->MouseLogiBuffer[2] = *Value;
+ /* Now MouseLogiBuffer is a set of info. If the second
+ * byte is 0, the mouse didn't understand the magic
+ * code. Otherwise, it it a Logitech and the second byte
+ * is the number of buttons, bit 7 of the first byte tells
+ * if it understands special E7 commands, the rest is an ID.
+ */
+ if (DevExt->MouseLogiBuffer[1]) {
+ DevExt->MouseAttributes.NumberOfButtons =
+ DevExt->MouseLogiBuffer[1];
+ /* For some reason the ID is the wrong way around */
+ DevExt->MouseLogitechID =
+ ((DevExt->MouseLogiBuffer[0] >> 4) & 0x07) |
+ ((DevExt->MouseLogiBuffer[0] << 3) & 0x78);
+ DevExt->MouseType = Ps2pp;
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState = ExpectingSetSamplingRateACK;
+ return TRUE;
+ /* TODO: Go through EnableWheel and Enable5Buttons */
+ }
+ DevExt->MouseResetState = EnableWheel;
+ I8042MouseResetIsr(DevExt, Status, Value);
+ return TRUE;
+ case EnableWheel:
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState = 1001;
+ return TRUE;
+ case 1001:
+ I8042IsrWritePortMouse(DevExt, 0xc8);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1002:
+ case 1004:
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1003:
+ I8042IsrWritePortMouse(DevExt, 0x64);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1005:
+ I8042IsrWritePortMouse(DevExt, 0x50);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1006:
+ I8042IsrWritePortMouse(DevExt, 0xf2);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1007:
+ /* Ignore ACK */
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1008:
+ /* Now if the value == 3, it's either an Intellimouse
+ * or Intellimouse Explorer. */
+ if (0x03 == *Value) {
+ DevExt->MouseAttributes.NumberOfButtons = 3;
+ DevExt->MouseAttributes.MouseIdentifier =
+ WHEELMOUSE_I8042_HARDWARE;
+ DevExt->MouseType = Intellimouse;
+ DevExt->MouseResetState = Enable5Buttons;
+ I8042MouseResetIsr(DevExt, Status, Value);
+ return TRUE;
+ } /* Else, just set the default settings and be done */
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState = ExpectingSetSamplingRateACK;
+ return TRUE;
+ case Enable5Buttons:
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState = 1021;
+ return TRUE;
+ case 1022:
+ case 1024:
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1021:
+ case 1023:
+ I8042IsrWritePortMouse(DevExt, 0xc8);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1025:
+ I8042IsrWritePortMouse(DevExt, 0x50);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1026:
+ I8042IsrWritePortMouse(DevExt, 0xf2);
+ DevExt->MouseResetState++;
+ return TRUE;
+ case 1027:
+ if (0x04 == *Value) {
+ DevExt->MouseAttributes.NumberOfButtons = 5;
+ DevExt->MouseAttributes.MouseIdentifier =
+ WHEELMOUSE_I8042_HARDWARE;
+ DevExt->MouseType = IntellimouseExplorer;
+ }
+ I8042IsrWritePortMouse(DevExt, 0xf3);
+ DevExt->MouseResetState = ExpectingSetSamplingRateACK;
+ return TRUE;
+ case ExpectingSetSamplingRateACK:
+ I8042IsrWritePortMouse(DevExt,
+ 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, 0x03);
+ DevExt->MouseResetState = ExpectingFinalResolutionValueACK;
+ return TRUE;
+ case ExpectingFinalResolutionValueACK:
+ I8042IsrWritePortMouse(DevExt, 0xf4);
+ DevExt->MouseResetState = ExpectingEnableACK;
+ return TRUE;
+ case ExpectingEnableACK:
+ DevExt->MouseState = MouseIdle;
+ DevExt->MouseTimeoutState = TimeoutCancel;
+ DPRINT("Mouse type = %d\n", DevExt->MouseType);
+ return TRUE;
+ default:
+ if (DevExt->MouseResetState < 100 ||
+ DevExt->MouseResetState > 999)
+ DPRINT1("MouseResetState went out of range: %d\n",
+ DevExt->MouseResetState);
+ return FALSE;
+ }
+}
+
+/*
+ * Prepare for reading the next packet and queue the dpc for handling
+ * this one.
+ *
+ * Context is the device object.
+ */
+VOID STDCALL I8042QueueMousePacket(PVOID Context)
+{
+ PDEVICE_OBJECT DeviceObject = Context;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+ DevExt->MouseComplete = TRUE;
+ DevExt->MouseInBuffer++;
+ if (DevExt->MouseInBuffer >
+ DevExt->MouseAttributes.InputDataQueueLength) {
+ DPRINT1("Mouse buffer overflow\n");
+ DevExt->MouseInBuffer--;
+ }
+
+ DPRINT("Irq completes mouse packet\n");
+ KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
+}
+
+/*
+ * Updates ButtonFlags according to RawButtons and a saved state;
+ * Only takes in account the bits that are set in Mask
+ */
+VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
+ USHORT Mask)
+{
+ PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
+ DevExt->MouseInBuffer;
+ USHORT NewButtonData = MouseInput->RawButtons & Mask;
+ USHORT ButtonDiff = (NewButtonData ^ DevExt->MouseButtonState) & Mask;
+
+ /* Note that the defines are such:
+ * MOUSE_LEFT_BUTTON_DOWN 1
+ * MOUSE_LEFT_BUTTON_UP 2
+ */
+ MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) |
+ (((~(NewButtonData)) << 1) &
+ (ButtonDiff << 1)) |
+ (MouseInput->RawButtons & 0xfc00);
+
+ DPRINT("Left raw/up/down: %d/%d/%d\n", MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
+ MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
+ MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
+
+ DevExt->MouseButtonState = (DevExt->MouseButtonState & ~Mask) |
+ (NewButtonData & Mask);
+}
+
+VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
+ BYTE 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;
+ }
+
+ if (DevExt->MouseType == IntellimouseExplorer) {
+ if (Output & 16)
+ MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+
+ if (Output & 32)
+ MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+ }
+ I8042MouseHandleButtons(DevExt, MOUSE_LEFT_BUTTON_DOWN |
+ MOUSE_RIGHT_BUTTON_DOWN |
+ MOUSE_MIDDLE_BUTTON_DOWN |
+ MOUSE_BUTTON_4_DOWN |
+ MOUSE_BUTTON_5_DOWN);
+ I8042QueueMousePacket(DevExt->MouseObject);
+ DevExt->MouseState = MouseIdle;
+ break;
+ default:
+ DPRINT1("Unexpected state!\n");
+ }
+}
+
+BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
+ VOID *Context)
+{
+ BYTE Output, PortStatus;
+ NTSTATUS Status;
+ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
+ UINT 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;
+ }
+
+ if (I8042MouseResetIsr(DevExt, PortStatus, &Output)) {
+ DPRINT("Handled by ResetIsr or hooked Isr\n");
+ if (NoChange != DevExt->MouseTimeoutState) {
+ KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
+ }
+ return TRUE;
+ }
+
+ if (DevExt->MouseType == Ps2pp)
+ I8042MouseHandlePs2pp(DevExt, Output);
+ else
+ I8042MouseHandle(DevExt, Output);
+
+ return TRUE;
+}
+
+VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+ ULONG MouseTransferred = 0;
+ ULONG MouseInBufferCopy;
+ KIRQL Irql;
+ LARGE_INTEGER Timeout;
+
+ switch (DevExt->MouseTimeoutState) {
+ case TimeoutStart:
+ DevExt->MouseTimeoutState = NoChange;
+ if (DevExt->MouseTimeoutActive &&
+ !KeCancelTimer(&DevExt->TimerMouseTimeout)) {
+ /* The timer fired already, give up */
+ DevExt->MouseTimeoutActive = FALSE;
+ return;
+ }
+
+ Timeout.QuadPart = -15000000;
+ /* 1.5 seconds, should be enough */
+
+ KeSetTimer(&DevExt->TimerMouseTimeout,
+ Timeout,
+ &DevExt->DpcMouseTimeout);
+ DevExt->MouseTimeoutActive = TRUE;
+ return;
+ case TimeoutCancel:
+ DevExt->MouseTimeoutState = NoChange;
+ KeCancelTimer(&DevExt->TimerMouseTimeout);
+ DevExt->MouseTimeoutActive = FALSE;
+ default:
+ /* nothing, don't want a warning */ ;
+ }
+
+ /* Should be unlikely */
+ if (!DevExt->MouseComplete)
+ return;
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+ DevExt->MouseComplete = FALSE;
+ MouseInBufferCopy = DevExt->MouseInBuffer;
+
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+
+ DPRINT ("Send a mouse packet\n");
+
+ if (!DevExt->MouseData.ClassService)
+ return;
+
+ ((MOUSE_CLASS_SERVICE_CALLBACK) DevExt->MouseData.ClassService)(
+ DevExt->MouseData.ClassDeviceObject,
+ DevExt->MouseBuffer,
+ DevExt->MouseBuffer + MouseInBufferCopy,
+ &MouseTransferred);
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+ DevExt->MouseInBuffer -= MouseTransferred;
+ if (DevExt->MouseInBuffer)
+ RtlMoveMemory(DevExt->MouseBuffer,
+ DevExt->MouseBuffer+MouseTransferred,
+ DevExt->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
+
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+}
+
+/* This timer DPC will be called when the mouse reset times out.
+ * I'll just send the 'disable mouse port' command to the controller
+ * and say the mouse doesn't exist.
+ */
+VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
+ KIRQL Irql;
+
+ Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+ DPRINT1("Mouse initialization timeout! (substate %x) "
+ "Disabling mouse.\n",
+ DevExt->MouseResetState);
+
+ if (!I8042MouseDisable(DevExt)) {
+ DPRINT1("Failed to disable mouse.\n");
+ }
+
+ DevExt->MouseExists = FALSE;
+
+ KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+}
+
+/*
+ * Process the mouse internal device requests
+ * returns FALSE if it doesn't understand the
+ * call so someone else can handle it.
+ */
+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;
+}
+
+/*
+ * Runs the mouse IOCTL_INTERNAL dispatch.
+ * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
+ * so someone else can have a try at it.
+ */
+NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PIO_STACK_LOCATION Stk;
+ PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+ PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+ DPRINT("InternalDeviceControl\n");
+
+ Irp->IoStatus.Information = 0;
+ Stk = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_INTERNAL_MOUSE_CONNECT:
+ DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(CONNECT_DATA)) {
+ DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ goto intcontfailure;
+ }
+
+ if (!DevExt->MouseExists) {
+ Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+ goto intcontfailure;
+ }
+
+ if (DevExt->MouseClaimed) {
+ DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
+ "Mouse is already claimed\n");
+ Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
+ goto intcontfailure;
+ }
+
+ memcpy(&DevExt->MouseData,
+ Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+ sizeof(CONNECT_DATA));
+ DevExt->MouseHook.IsrWritePort = I8042IsrWritePortMouse;
+ DevExt->MouseHook.QueueMousePacket =
+ I8042QueueMousePacket;
+ DevExt->MouseHook.CallContext = DevExt;
+
+ {
+ PIO_WORKITEM WorkItem;
+ PI8042_HOOK_WORKITEM WorkItemData;
+
+ WorkItem = IoAllocateWorkItem(DeviceObject);
+ if (!WorkItem) {
+ DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
+ "Can't allocate work item\n");
+ Irp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ goto intcontfailure;
+ }
+
+ WorkItemData = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(I8042_HOOK_WORKITEM),
+ TAG_I8042);
+ if (!WorkItemData) {
+ DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
+ "Can't allocate work item data\n");
+ Irp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoFreeWorkItem(WorkItem);
+ goto intcontfailure;
+ }
+ WorkItemData->WorkItem = WorkItem;
+ WorkItemData->Target =
+ DevExt->MouseData.ClassDeviceObject;
+ WorkItemData->Irp = Irp;
+
+ IoMarkIrpPending(Irp);
+ DevExt->MouseState = MouseResetting;
+ DevExt->MouseResetState = 1100;
+ IoQueueWorkItem(WorkItem,
+ I8042SendHookWorkItem,
+ DelayedWorkQueue,
+ WorkItemData);
+
+ Irp->IoStatus.Status = STATUS_PENDING;
+ }
+
+ break;
+ case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
+ DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
+ Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+ goto intcontfailure;
+ }
+ if (!DevExt->MouseInterruptObject) {
+ Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+ goto intcontfailure;
+ }
+
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject, Irp, NULL, NULL);
+ Irp->IoStatus.Status = STATUS_PENDING;
+
+ break;
+ case IOCTL_MOUSE_QUERY_ATTRIBUTES:
+ DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
+ if (Stk->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(MOUSE_ATTRIBUTES)) {
+ DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
+ "invalid buffer size\n");
+ Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+ goto intcontfailure;
+ }
+ memcpy(Irp->AssociatedIrp.SystemBuffer,
+ &DevExt->MouseAttributes,
+ sizeof(MOUSE_ATTRIBUTES));
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ default:
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+intcontfailure:
+ return Irp->IoStatus.Status;
+}
+
+BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
+{
+ UCHAR Value;
+ NTSTATUS Status;
+
+ DPRINT("Enabling mouse\n");
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+ DPRINT1("Can't read i8042 mode\n");
+ return FALSE;
+ }
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT1("No response after read i8042 mode\n");
+ return FALSE;
+ }
+
+ Value &= ~(0x20); // don't disable mouse
+ Value |= 0x02; // enable mouse interrupts
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+ DPRINT1("Can't set i8042 mode\n");
+ return FALSE;
+ }
+
+ if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+ DPRINT1("Can't send i8042 mode\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
+{
+ UCHAR Value;
+ NTSTATUS Status;
+
+ DPRINT("Disabling mouse\n");
+
+ I8042Flush(); /* Just to be (kind of) sure */
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+ DPRINT1("Can't read i8042 mode\n");
+ return FALSE;
+ }
+
+ Status = I8042ReadDataWait(DevExt, &Value);
+ if (Status != STATUS_SUCCESS) {
+ DPRINT1("No response after read i8042 mode\n");
+ return FALSE;
+ }
+
+ Value |= 0x20; // don't disable mouse
+ Value &= ~(0x02); // enable mouse interrupts
+
+ if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+ DPRINT1("Can't set i8042 mode\n");
+ return FALSE;
+ }
+
+ if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+ DPRINT1("Can't send i8042 mode\n");
+ return FALSE;
+ }
+
+ I8042Flush();
+ /* Just to be (kind of) sure; if the mouse would
+ * say something while we are disabling it, these bytes would
+ * block the keyboard.
+ */
+
+ return TRUE;
+}
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: drivers/input/i8042prt/ps2pp.c
+ * PURPOSE: i8042prt driver
+ * ps2pp protocol handling
+ * PROGRAMMER: Tinus
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+
+VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, BYTE Input)
+{
+ UCHAR PktType;
+ PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
+ DevExt->MouseInBuffer;
+
+/* First, collect 3 bytes for a packet
+ * We can detect out-of-sync only by checking
+ * the whole packet anyway.
+ *
+ * If bit 7 and 8 of the first byte are 0, its
+ * a normal packet.
+ *
+ * Otherwise, the packet is different, like this:
+ * 1: E 1 b3 b2 x x x x
+ * 2: x x b1 b0 x1 x0 1 0
+ * 3: x x x x x x x1 x0
+ *
+ * b3-0 form a code that specifies the packet type:
+ *
+ * 0 Device Type
+ * 1 Rollers and buttons
+ * 2 Reserved
+ * 3 Reserved
+ * 4 Device ID
+ * 5 Channel & Battery
+ * 6 Wireless notifications
+ * 7 Reserved
+ * 8 ShortID LSB (ShortID is a number that is supposed to differentiate
+ * 9 ShortID MSB between your mouse and your neighbours')
+ * 10 Reserved
+ * 11 Mouse capabilities
+ * 12 Remote control LSB
+ * 13 Remote control MSB
+ * 14 Reserved
+ * 15 Extended packet
+ */
+
+ switch (DevExt->MouseState) {
+ case MouseIdle:
+ case XMovement:
+ DevExt->MouseLogiBuffer[DevExt->MouseState] = Input;
+ DevExt->MouseState++;
+ break;
+
+ case YMovement:
+ DevExt->MouseLogiBuffer[2] = Input;
+ DevExt->MouseState = MouseIdle;
+
+ /* first check if it's a normal packet */
+
+ if (!(DevExt->MouseLogiBuffer[0] & 0xC0)) {
+ DevExt->MouseState = MouseIdle;
+ I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[0]);
+ I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[1]);
+ I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[2]);
+ /* We could care about wether MouseState really
+ * advances, but we don't need to because we're
+ * only doing three bytes anyway, so the packet
+ * will never complete if it's broken.
+ */
+ return;
+ }
+
+ /* sanity check */
+
+ if (((DevExt->MouseLogiBuffer[0] & 0x48) != 0x48) ||
+ (((DevExt->MouseLogiBuffer[1] & 0x0C) >> 2) !=
+ (DevExt->MouseLogiBuffer[2] & 0x03))) {
+ DPRINT1("Ps2pp packet fails sanity checks\n");
+ return;
+ }
+
+ /* Now get the packet type */
+
+ PktType = ((DevExt->MouseLogiBuffer[0] & 0x30) >> 4) &
+ ((DevExt->MouseLogiBuffer[1] & 0x30) >> 6);
+
+ switch (PktType) {
+ case 0:
+ /* The packet contains the device ID, but we
+ * already read that in the initialization
+ * sequence. Ignore it.
+ */
+ return;
+ case 1:
+ RtlZeroMemory(MouseInput, sizeof(MOUSE_INPUT_DATA));
+ if (DevExt->MouseLogiBuffer[2] & 0x10)
+ MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+
+ if (DevExt->MouseLogiBuffer[2] & 0x20)
+ MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+
+ if (DevExt->MouseLogiBuffer[2] & 0x0F) {
+ MouseInput->ButtonFlags |= MOUSE_WHEEL;
+ if (DevExt->MouseLogiBuffer[2] & 0x08)
+ MouseInput->ButtonData =
+ (DevExt->MouseLogiBuffer[2] & 0x07) -
+ 8;
+ else
+ MouseInput->ButtonData =
+ DevExt->MouseLogiBuffer[2] & 0x07;
+ }
+ I8042MouseHandleButtons(DevExt, MOUSE_BUTTON_4_DOWN |
+ MOUSE_BUTTON_5_DOWN);
+ I8042QueueMousePacket(
+ DevExt->MouseObject);
+ return;
+ default:
+ /* These are for things that would probably
+ * be handled by logitechs own driver.
+ */
+ return;
+ }
+ default:
+ DPRINT1("Unexpected input state for ps2pp!\n");
+ }
+}
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: drivers/input/i8042prt/registry.c
+ * PURPOSE: i8042 (ps/2 keyboard-mouse controller) driver
+ * Reading the registry
+ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
+ * Jason Filby (jasonfilby@yahoo.com)
+ * Tinus
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * Read the registry keys associated with this device. The RegistryPath
+ * var is a hack. This should be more like what microsoft does, but I
+ * don't know exactly what they do except that it's a hack too...
+ */
+VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
+ PDEVICE_EXTENSION DevExt)
+
+{
+ RTL_QUERY_REGISTRY_TABLE Parameters[18];
+ UNICODE_STRING ParametersPath;
+
+ PWSTR RegistryPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\i8042Prt\\Parameters";
+
+ NTSTATUS Status;
+
+ DWORD DefaultHeadless = 0;
+ DWORD DefaultCrashScroll = 0;
+ DWORD DefaultCrashSysRq = 0;
+ DWORD DefaultReportResetErrors = 0;
+ DWORD DefaultPollStatusIterations = 1;
+ DWORD DefaultResendIterations = 3;
+ DWORD DefaultPollingIterations = 12000;
+ DWORD DefaultPollingIterationsMaximum = 12000;
+ DWORD DefaultKeyboardDataQueueSize = 100;
+ DWORD DefaultOverrideKeyboardType = 0;
+ DWORD DefaultOverrideKeyboardSubtype = 0;
+ DWORD DefaultMouseDataQueueSize = 100;
+ DWORD DefaultMouseResendStallTime = 1000;
+ DWORD DefaultMouseSynchIn100ns = 20000000;
+ DWORD DefaultMouseResolution = 3;
+ DWORD DefaultSampleRate = 60;
+ DWORD DefaultNumberOfButtons = 2;
+ DWORD DefaultEnableWheelDetection = 1;
+
+ RtlInitUnicodeString(&ParametersPath, NULL);
+ ParametersPath.MaximumLength = (wcslen(RegistryPath) *
+ sizeof(WCHAR)) +
+ sizeof(UNICODE_NULL);
+
+ ParametersPath.Buffer = ExAllocatePoolWithTag(PagedPool,
+ ParametersPath.MaximumLength,
+ TAG_I8042);
+
+ if (!ParametersPath.Buffer) {
+ DPRINT1("No buffer space for reading registry\n");
+ return;
+ }
+
+ RtlZeroMemory(ParametersPath.Buffer, ParametersPath.MaximumLength);
+ RtlAppendUnicodeToString(&ParametersPath, RegistryPath);
+
+ RtlZeroMemory(Parameters, sizeof(Parameters));
+
+ Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[0].Name = L"Headless";
+ Parameters[0].EntryContext = &DevExt->Settings.Headless;
+ Parameters[0].DefaultType = REG_DWORD;
+ Parameters[0].DefaultData = &DefaultHeadless;
+ Parameters[0].DefaultLength = sizeof(ULONG);
+
+ Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[1].Name = L"CrashOnCtrlScroll";
+ Parameters[1].EntryContext = &DevExt->Settings.CrashScroll;
+ Parameters[1].DefaultType = REG_DWORD;
+ Parameters[1].DefaultData = &DefaultCrashScroll;
+ Parameters[1].DefaultLength = sizeof(ULONG);
+
+ Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[2].Name = L"BreakOnSysRq";
+ Parameters[2].EntryContext = &DevExt->Settings.CrashSysRq;
+ Parameters[2].DefaultType = REG_DWORD;
+ Parameters[2].DefaultData = &DefaultCrashSysRq;
+ Parameters[2].DefaultLength = sizeof(ULONG);
+
+ Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[3].Name = L"ReportResetErrors";
+ Parameters[3].EntryContext = &DevExt->Settings.ReportResetErrors;
+ Parameters[3].DefaultType = REG_DWORD;
+ Parameters[3].DefaultData = &DefaultReportResetErrors;
+ Parameters[3].DefaultLength = sizeof(ULONG);
+
+ Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[4].Name = L"PollStatusIterations";
+ Parameters[4].EntryContext = &DevExt->Settings.PollStatusIterations;
+ Parameters[4].DefaultType = REG_DWORD;
+ Parameters[4].DefaultData = &DefaultPollStatusIterations;
+ Parameters[4].DefaultLength = sizeof(ULONG);
+
+ Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[5].Name = L"ResendIterations";
+ Parameters[5].EntryContext = &DevExt->Settings.ResendIterations;
+ Parameters[5].DefaultType = REG_DWORD;
+ Parameters[5].DefaultData = &DefaultResendIterations;
+ Parameters[5].DefaultLength = sizeof(ULONG);
+
+ Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[6].Name = L"PollingIterations";
+ Parameters[6].EntryContext = &DevExt->Settings.PollingIterations;
+ Parameters[6].DefaultType = REG_DWORD;
+ Parameters[6].DefaultData = &DefaultPollingIterations;
+ Parameters[6].DefaultLength = sizeof(ULONG);
+
+ Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[7].Name = L"PollingIterationsMaximum";
+ Parameters[7].EntryContext = &DevExt->Settings.PollingIterationsMaximum;
+ Parameters[7].DefaultType = REG_DWORD;
+ Parameters[7].DefaultData = &DefaultPollingIterationsMaximum;
+ Parameters[7].DefaultLength = sizeof(ULONG);
+
+ Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[8].Name = L"KeyboardDataQueueSize";
+ Parameters[8].EntryContext =
+ &DevExt->KeyboardAttributes.InputDataQueueLength;
+ Parameters[8].DefaultType = REG_DWORD;
+ Parameters[8].DefaultData = &DefaultKeyboardDataQueueSize;
+ Parameters[8].DefaultLength = sizeof(ULONG);
+
+ Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[9].Name = L"OverrideKeyboardType";
+ Parameters[9].EntryContext = &DevExt->Settings.OverrideKeyboardType;
+ Parameters[9].DefaultType = REG_DWORD;
+ Parameters[9].DefaultData = &DefaultOverrideKeyboardType;
+ Parameters[9].DefaultLength = sizeof(ULONG);
+
+ Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[10].Name = L"OverrideKeyboardSubtype";
+ Parameters[10].EntryContext = &DevExt->Settings.OverrideKeyboardSubtype;
+ Parameters[10].DefaultType = REG_DWORD;
+ Parameters[10].DefaultData = &DefaultOverrideKeyboardSubtype;
+ Parameters[10].DefaultLength = sizeof(ULONG);
+
+ Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[11].Name = L"MouseDataQueueSize";
+ Parameters[11].EntryContext =
+ &DevExt->MouseAttributes.InputDataQueueLength;
+ Parameters[11].DefaultType = REG_DWORD;
+ Parameters[11].DefaultData = &DefaultMouseDataQueueSize;
+ Parameters[11].DefaultLength = sizeof(ULONG);
+
+ Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[12].Name = L"MouseResendStallTime";
+ Parameters[12].EntryContext = &DevExt->Settings.MouseResendStallTime;
+ Parameters[12].DefaultType = REG_DWORD;
+ Parameters[12].DefaultData = &DefaultMouseResendStallTime;
+ Parameters[12].DefaultLength = sizeof(ULONG);
+
+ Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[13].Name = L"MouseSynchIn100ns";
+ Parameters[13].EntryContext = &DevExt->Settings.MouseSynchIn100ns;
+ Parameters[13].DefaultType = REG_DWORD;
+ Parameters[13].DefaultData = &DefaultMouseSynchIn100ns;
+ Parameters[13].DefaultLength = sizeof(ULONG);
+
+ Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[14].Name = L"MouseResolution";
+ Parameters[14].EntryContext = &DevExt->Settings.MouseResolution;
+ Parameters[14].DefaultType = REG_DWORD;
+ Parameters[14].DefaultData = &DefaultMouseResolution;
+ Parameters[14].DefaultLength = sizeof(ULONG);
+
+ Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[14].Name = L"SampleRate";
+ Parameters[14].EntryContext = &DevExt->MouseAttributes.SampleRate;
+ Parameters[14].DefaultType = REG_DWORD;
+ Parameters[14].DefaultData = &DefaultSampleRate;
+ Parameters[14].DefaultLength = sizeof(ULONG);
+
+ Parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[15].Name = L"NumberOfButtons";
+ Parameters[15].EntryContext = &DevExt->Settings.NumberOfButtons;
+ Parameters[15].DefaultType = REG_DWORD;
+ Parameters[15].DefaultData = &DefaultNumberOfButtons;
+ Parameters[15].DefaultLength = sizeof(ULONG);
+
+ Parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Parameters[16].Name = L"EnableWheelDetection";
+ Parameters[16].EntryContext = &DevExt->Settings.EnableWheelDetection;
+ Parameters[16].DefaultType = REG_DWORD;
+ Parameters[16].DefaultData = &DefaultEnableWheelDetection;
+ Parameters[16].DefaultLength = sizeof(ULONG);
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE |
+ RTL_REGISTRY_OPTIONAL,
+ ParametersPath.Buffer,
+ Parameters,
+ NULL,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ DPRINT1 ("Can't read registry: %x\n", 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;
+ while (Current->Name) {
+ *((DWORD *)Current->EntryContext) =
+ *((DWORD *)Current->DefaultData);
+ Current++;
+ }
+ DPRINT1 ("Manually set defaults\n");
+
+ }
+ ExFreePool(ParametersPath.Buffer);
+ DPRINT("Done reading registry\n");
+}
+
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * FILE: drivers/input/kbdclass/kbdclass.c
+ * PURPOSE: Keyboard class driver
+ * PROGRAMMER: Victor Kirhenshtein (sauros@iname.com)
+ * Jason Filby (jasonfilby@yahoo.com)
+ * Tinus_
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "kbdclass.h"
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Driver data
+ */
+
+static BOOLEAN AlreadyOpened = FALSE;
+
+static VOID STDCALL KbdCopyKeys(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+ ULONG NrToRead = stk->Parameters.Read.Length /
+ sizeof(KEYBOARD_INPUT_DATA);
+ ULONG NrRead = Irp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
+ KEYBOARD_INPUT_DATA *Rec =
+ (KEYBOARD_INPUT_DATA *)Irp->AssociatedIrp.SystemBuffer;
+
+ while (DevExt->KeysInBuffer &&
+ NrRead < NrToRead) {
+ memcpy(&Rec[NrRead],
+ &DevExt->KbdBuffer[DevExt->BufHead],
+ sizeof(KEYBOARD_INPUT_DATA));
+
+ if (++DevExt->BufHead >= KBD_BUFFER_SIZE)
+ DevExt->BufHead = 0;
+
+ DevExt->KeysInBuffer--;
+ NrRead++;
+ }
+ Irp->IoStatus.Information = NrRead * sizeof(KEYBOARD_INPUT_DATA);
+
+ if (NrRead < NrToRead) {
+ Irp->IoStatus.Status = STATUS_PENDING;
+ DPRINT("Pending... (NrRead %d, NrToRead %d\n", NrRead, NrToRead);
+ } else {
+ DPRINT("Send scancode: %x\n", ((KEYBOARD_INPUT_DATA*)Irp->AssociatedIrp.SystemBuffer)->MakeCode);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ IoStartNextPacket (DeviceObject, FALSE);
+ DPRINT("Success!\n");
+ }
+}
+
+static VOID STDCALL KbdClassServiceCallback (
+ PDEVICE_OBJECT DeviceObject,
+ PKEYBOARD_INPUT_DATA InputDataStart,
+ PKEYBOARD_INPUT_DATA InputDataEnd,
+ PULONG InputDataConsumed)
+{
+ PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+ PKEYBOARD_INPUT_DATA CurrentInput = InputDataStart;
+
+ DPRINT("ServiceCallback called\n");
+
+ while (DevExt->KeysInBuffer < KBD_BUFFER_SIZE &&
+ CurrentInput < InputDataEnd) {
+ memcpy(&DevExt->KbdBuffer[DevExt->BufTail],
+ CurrentInput,
+ sizeof(KEYBOARD_INPUT_DATA));
+
+ if (++DevExt->BufTail >= KBD_BUFFER_SIZE)
+ DevExt->BufTail = 0;
+ DevExt->KeysInBuffer++;
+
+ CurrentInput++;
+ InputDataConsumed[0]++;
+ }
+
+ if (CurrentInput < InputDataStart)
+ /* Copy the rest to the beginning, perhaps the keyboard
+ * can buffer it for us */
+ memmove(InputDataStart,
+ CurrentInput,
+ ((char *)InputDataEnd - (char *)CurrentInput));
+
+ if (DeviceObject->CurrentIrp) {
+ PIRP Irp = DeviceObject->CurrentIrp;
+ PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+ if (stk->MajorFunction == IRP_MJ_READ)
+ KbdCopyKeys(DeviceObject, Irp);
+ }
+}
+
+VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ /* We only do this for read irps */
+ DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
+ KbdCopyKeys(DeviceObject, Irp);
+}
+
+
+/*
+ * These are just passed down the stack but we must change the IOCTL to be
+ * INTERNAL. MSDN says there might be more...
+ */
+NTSTATUS STDCALL KbdDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION Stk = IoGetCurrentIrpStackLocation(Irp);
+ PIO_STACK_LOCATION NextStk = IoGetNextIrpStackLocation(Irp);
+
+ DPRINT ("KbdDeviceControl %x\n", Stk->Parameters.DeviceIoControl.IoControlCode);
+
+ switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+ case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
+ case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+ case IOCTL_KEYBOARD_QUERY_INDICATORS:
+ case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
+ case IOCTL_KEYBOARD_SET_INDICATORS:
+ case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ NextStk->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+ return IoCallDriver(DevExt->I8042Device, Irp);
+ default:
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+}
+
+static NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject,
+ PIRP Irp)
+{
+ PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+
+ DPRINT ("KbdInternalDeviceControl\n");
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(DevExt->I8042Device, Irp);
+}
+
+static NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS Status;
+
+ DPRINT("DeviceObject %x\n",DeviceObject);
+ DPRINT("Irp %x\n",Irp);
+
+ DPRINT("Dispatch: stk->MajorFunction %d\n", stk->MajorFunction);
+ DPRINT("AlreadyOpened %d\n",AlreadyOpened);
+
+ switch (stk->MajorFunction) {
+ case IRP_MJ_CREATE:
+ if (AlreadyOpened == TRUE) {
+ CHECKPOINT;
+ Status = STATUS_UNSUCCESSFUL;
+ DPRINT1("Keyboard is already open\n");
+ } else {
+ CHECKPOINT;
+ Status = STATUS_SUCCESS;
+ AlreadyOpened = TRUE;
+ }
+ break;
+
+ case IRP_MJ_CLOSE:
+ Status = STATUS_SUCCESS;
+ AlreadyOpened = FALSE;
+ break;
+
+ case IRP_MJ_READ:
+ DPRINT("Queueing packet\n");
+ IoMarkIrpPending(Irp);
+ IoStartPacket(DeviceObject,Irp,NULL,NULL);
+ return(STATUS_PENDING);
+
+ default:
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp,IO_NO_INCREMENT);
+ DPRINT("Status %d\n",Status);
+ return(Status);
+}
+
+static VOID STDCALL KbdClassSendConnect(PDEVICE_EXTENSION DevExt)
+{
+ CONNECT_DATA ConnectData;
+ KEVENT Event;
+ IO_STATUS_BLOCK IoStatus;
+ NTSTATUS Status;
+ PIRP Irp;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ ConnectData.ClassDeviceObject = DevExt->DeviceObject;
+ ConnectData.ClassService = KbdClassServiceCallback;
+
+ Irp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_KEYBOARD_CONNECT,
+ DevExt->I8042Device,
+ &ConnectData,
+ sizeof(CONNECT_DATA),
+ NULL,
+ 0,
+ TRUE,
+ &Event,
+ &IoStatus);
+
+ if (!Irp)
+ return;
+
+ Status = IoCallDriver(
+ DevExt->I8042Device,
+ Irp);
+ DPRINT("SendConnect status: %x\n", Status);
+
+ if (STATUS_PENDING ==Status)
+ KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ DPRINT("SendConnect done\n");
+}
+
+NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Module entry point
+ */
+{
+ PDEVICE_OBJECT DeviceObject;
+ PDEVICE_EXTENSION DevExt;
+ PFILE_OBJECT I8042File;
+ NTSTATUS Status;
+ UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\Keyboard");
+ UNICODE_STRING SymlinkName = ROS_STRING_INITIALIZER(L"\\??\\Keyboard");
+ UNICODE_STRING I8042Name = ROS_STRING_INITIALIZER(L"\\Device\\KeyboardClass0");
+
+ DPRINT("Keyboard Class Driver 0.0.1\n");
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdDispatch;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdDispatch;
+ DriverObject->MajorFunction[IRP_MJ_READ] = KbdDispatch;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ KbdInternalDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdDeviceControl;
+
+ DriverObject->DriverStartIo = KbdStartIo;
+
+ IoCreateDevice(DriverObject,
+ sizeof(DEVICE_EXTENSION),
+ &DeviceName,
+ FILE_DEVICE_KEYBOARD,
+ 0,
+ TRUE,
+ &DeviceObject);
+
+ RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
+ DevExt = DeviceObject->DeviceExtension;
+ DevExt->DeviceObject = DeviceObject;
+
+ Status = IoGetDeviceObjectPointer(&I8042Name,
+ FILE_READ_DATA,
+ &I8042File,
+ &DevExt->I8042Device);
+
+ if (STATUS_SUCCESS != Status) {
+ DPRINT("Failed to open device: %x\n", Status);
+ return Status;
+ }
+
+ ObReferenceObject(DevExt->I8042Device);
+ ObDereferenceObject(I8042File);
+
+ DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
+
+ DeviceObject->StackSize = 1 + DevExt->I8042Device->StackSize;
+
+ IoCreateSymbolicLink(&SymlinkName, &DeviceName);
+
+ KbdClassSendConnect(DevExt);
+
+ return(STATUS_SUCCESS);
+}
--- /dev/null
+#ifndef _KEYBOARD_H_
+#define _KEYBOARD_H_
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define KBD_BUFFER_SIZE 32
+#define KBD_WRAP_MASK 0x1F
+
+/*-----------------------------------------------------
+ * DeviceExtension
+ * --------------------------------------------------*/
+typedef struct _DEVICE_EXTENSION
+{
+ PDEVICE_OBJECT I8042Device;
+ PDEVICE_OBJECT DeviceObject;
+
+ KEYBOARD_INPUT_DATA KbdBuffer[KBD_BUFFER_SIZE];
+ int BufHead,BufTail;
+ int KeysInBuffer;
+
+ BOOLEAN AlreadyOpened;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+typedef struct _CONNECT_DATA {
+ PDEVICE_OBJECT ClassDeviceObject;
+ PVOID ClassService;
+} CONNECT_DATA, *PCONNECT_DATA;
+
+/*
+ * Some defines
+ */
+
+#define IOCTL_INTERNAL_KEYBOARD_CONNECT \
+ CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#define KEYBOARD_IRQ 1
+
+#define disable() __asm__("cli\n\t")
+#define enable() __asm__("sti\n\t")
+
+#define ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
+#define CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
+
+
+/*
+ * Keyboard controller ports
+ */
+
+#define KBD_DATA_PORT 0x60
+#define KBD_CTRL_PORT 0x64
+
+
+/*
+ * Controller commands
+ */
+
+#define KBD_READ_MODE 0x20
+#define KBD_WRITE_MODE 0x60
+#define KBD_SELF_TEST 0xAA
+#define KBD_LINE_TEST 0xAB
+#define KBD_CTRL_ENABLE 0xAE
+
+/*
+ * Keyboard commands
+ */
+
+#define KBD_ENABLE 0xF4
+#define KBD_DISABLE 0xF5
+#define KBD_RESET 0xFF
+
+
+/*
+ * Keyboard responces
+ */
+
+#define KBD_ACK 0xFA
+#define KBD_BATCC 0xAA
+
+
+/*
+ * Controller status register bits
+ */
+
+#define KBD_OBF 0x01
+#define KBD_IBF 0x02
+#define KBD_GTO 0x40
+#define KBD_PERR 0x80
+
+
+/*
+ * LED bits
+ */
+
+#define KBD_LED_SCROLL 0x01
+#define KBD_LED_NUM 0x02
+#define KBD_LED_CAPS 0x04
+
+#endif // _KEYBOARD_H_
--- /dev/null
+/* $Id: keyboard.rc 12852 2005-01-06 13:58:04Z mf $ */
+
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "Keyboard Device Driver\0"
+#define REACTOS_STR_INTERNAL_NAME "keyboard\0"
+#define REACTOS_STR_ORIGINAL_FILENAME "keyboard.sys\0"
+#include <reactos/version.rc>
--- /dev/null
+# $Id: makefile 12852 2005-01-06 13:58:04Z mf $
+
+PATH_TO_TOP = ../../..
+
+TARGET_BOOTSTRAP = yes
+
+TARGET_TYPE = driver
+
+TARGET_NAME = kbdclass
+
+TARGET_CFLAGS = -Wall -Werror -D__USE_W32API
+
+TARGET_OBJECTS = $(TARGET_NAME).o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
BOOLEAN MouseClassCallBack(
PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
- PMOUSE_INPUT_DATA MouseDataEnd, PULONG InputCount)
+ PMOUSE_INPUT_DATA MouseDataEnd, PULONG ConsumedCount)
{
PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
PIRP Irp;
KIRQL OldIrql;
PIO_STACK_LOCATION Stack;
- ULONG SafeInputCount = *InputCount;
+ ULONG InputCount = MouseDataEnd - MouseDataStart;
ULONG ReadSize;
DPRINT("Entering MouseClassCallBack\n");
- if (ClassDeviceExtension->ReadIsPending == TRUE)
+ /* A filter driver might have consumed all the data already; I'm
+ * not sure if they are supposed to move the packets when they
+ * consume them though.
+ */
+ if (ClassDeviceExtension->ReadIsPending == TRUE &&
+ InputCount)
{
Irp = ClassDeviceObject->CurrentIrp;
ClassDeviceObject->CurrentIrp = NULL;
/* Skip the packet we just sent away */
MouseDataStart++;
- SafeInputCount--;
+ (*ConsumedCount)++;
+ InputCount--;
}
/* If we have data from the port driver and a higher service to send the data to */
- if (SafeInputCount != 0)
+ if (InputCount != 0)
{
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
- if (ClassDeviceExtension->InputCount + SafeInputCount > MOUSE_BUFFER_SIZE)
+ if (ClassDeviceExtension->InputCount + InputCount > MOUSE_BUFFER_SIZE)
{
ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
} else {
- ReadSize = SafeInputCount;
+ ReadSize = InputCount;
}
/*
ClassDeviceExtension->InputCount += ReadSize;
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
+ (*ConsumedCount) += ReadSize;
} else {
DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount);
}
//
// Write function
//
- //UNIMPLEMENTED IN PI8042_ISR_WRITE_PORT IsrWritePort;
+ IN PI8042_ISR_WRITE_PORT IsrWritePort;
//
// Queue the current packet (ie the one passed into the isr callback hook)
// to be reported to the class driver
//
- //UNIMPLEMENTED IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
+ IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
//
// Context for IsrWritePort, QueueKeyboardPacket
//
- //UNIMPLEMENTED IN PVOID CallContext;
+ IN PVOID CallContext;
} INTERNAL_I8042_HOOK_KEYBOARD, *PINTERNAL_I8042_HOOK_KEYBOARD;
/* KD Internal Debug Services */
typedef enum _KDP_DEBUG_SERVICE
{
- DumpNonPagedPool = 0,
- ManualBugCheck,
- DumpNonPagedPoolStats,
- DumpNewNonPagedPool,
- DumpNewNonPagedPoolStats,
- DumpAllThreads,
- DumpUserThreads,
- KdSpare1,
- KdSpare2,
- KdSpare3,
- EnterDebugger
+ DumpNonPagedPool = 0x1e, /* a */
+ ManualBugCheck = 0x30, /* b */
+ DumpNonPagedPoolStats = 0x2e, /* c */
+ DumpNewNonPagedPool = 0x20, /* d */
+ DumpNewNonPagedPoolStats = 0x12, /* e */
+ DumpAllThreads = 0x21, /* f */
+ DumpUserThreads = 0x22, /* g */
+ KdSpare1 = 0x23, /* h */
+ KdSpare2 = 0x17, /* i */
+ KdSpare3 = 0x24, /* j */
+ EnterDebugger = 0x25 /* k */
} KDP_DEBUG_SERVICE;
/* Dispatch Table for Wrapper Functions */
NULL,
INSERT_LAST,
L"Options",
- L"/DEBUGPORT=SCREEN /NOGUIBOOT");
+ L"/DEBUGPORT=COM1 /NOGUIBOOT");
/* Save the ini file */
IniCacheSave(IniCache, IniPath);
#include "precomp.h"
#include <ddk/ntddblue.h>
+#include <ddk/ntddkbd.h>
#include "usetup.h"
#include "console.h"
+#include "keytrans.h"
#define NDEBUG
#include <debug.h>
{
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
+ KEYBOARD_INPUT_DATA InputData;
Buffer->EventType = KEY_EVENT;
Status = NtReadFile(StdInput,
NULL,
NULL,
&Iosb,
- &Buffer->Event.KeyEvent,
+ &InputData,
+// &Buffer->Event.KeyEvent,
sizeof(KEY_EVENT_RECORD),
NULL,
0);
+ if (NT_SUCCESS(Status))
+ {
+ Status = IntTranslateKey(&InputData, &Buffer->Event.KeyEvent);
+ }
+
return(Status);
}
--- /dev/null
+/*
+ * ReactOS kernel
+ * Copyright (C) 2002 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS text-mode setup
+ * FILE: subsys/system/usetup/keytrans.c
+ * PURPOSE: Console support functions: keyboard translation
+ * PROGRAMMER: Tinus
+ *
+ * NB: Hardcoded to US keyboard
+ */
+#define NDEBUG
+#include <debug.h>
+
+#include "precomp.h"
+#include <ddk/ntddblue.h>
+#include <ddk/ntddkbd.h>
+#include <windows.h>
+
+static WORD KeyTable[] = {
+/* 0x00 */
+ 0x00, VK_ESCAPE, 0x31, 0x32,
+ 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x30,
+ VK_OEM_MINUS, VK_OEM_PLUS, VK_BACK, VK_TAB,
+/* 0x10 */
+ 0x51, 0x57, 0x45, 0x52,
+ 0x54, 0x59, 0x55, 0x49,
+ 0x4f, 0x50, VK_OEM_4, VK_OEM_6,
+ VK_RETURN, VK_CONTROL, 0x41, 0x53,
+/* 0x20 */
+ 0x44, 0x46, 0x47, 0x48,
+ 0x4a, 0x4b, 0x4c, VK_OEM_1,
+ VK_OEM_7, 0xc0, VK_LSHIFT, VK_OEM_5,
+ 0x5a, 0x58, 0x43, 0x56,
+/* 0x30 */
+ 0x42, 0x4e, 0x4d, VK_OEM_COMMA,
+ VK_OEM_PERIOD, VK_OEM_2, VK_RSHIFT, VK_MULTIPLY,
+ VK_LMENU, VK_SPACE, VK_CAPITAL, VK_F1,
+ VK_F2, VK_F3, VK_F4, VK_F5,
+/* 0x40 */
+ VK_F6, VK_F7, VK_F8, VK_F9,
+ VK_F10, VK_NUMLOCK, VK_SCROLL, VK_NUMPAD7,
+ VK_NUMPAD8, VK_NUMPAD9, VK_SUBTRACT, VK_NUMPAD4,
+ VK_NUMPAD5, VK_NUMPAD6, VK_ADD, VK_NUMPAD1,
+/* 0x50 */
+ VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD0, VK_SEPARATOR,
+ 0, 0, 0, VK_F11,
+ VK_F12, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x60 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x70 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static WORD KeyTableEnhanced[] = {
+/* 0x00 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x10 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ VK_RETURN, VK_RCONTROL, 0, 0,
+/* 0x20 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x30 */
+ 0, 0, 0, 0,
+ 0, VK_DIVIDE, 0, VK_SNAPSHOT,
+ VK_RMENU, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x40 */
+ 0, 0, 0, 0,
+ 0, 0, 0, VK_HOME,
+ VK_UP, VK_PRIOR, 0, VK_LEFT,
+ 0, VK_RIGHT, 0, VK_END,
+/* 0x50 */
+ VK_DOWN, VK_NEXT, VK_INSERT, VK_DELETE,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x60 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+/* 0x70 */
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+typedef struct _SCANTOASCII {
+ USHORT ScanCode;
+ USHORT Enhanced;
+ UCHAR Normal;
+ UCHAR Shift;
+ UCHAR NumLock;
+} SCANTOASCII, *PSCANTOASCII;
+
+SCANTOASCII ScanToAscii[] = {
+{ 0x1e, 0, 'a', 'A', 0 },
+{ 0x30, 0, 'b', 'B', 0 },
+{ 0x2e, 0, 'c', 'C', 0 },
+{ 0x20, 0, 'd', 'D', 0 },
+{ 0x12, 0, 'e', 'E', 0 },
+{ 0x21, 0, 'f', 'F', 0 },
+{ 0x22, 0, 'g', 'G', 0 },
+{ 0x23, 0, 'h', 'H', 0 },
+{ 0x17, 0, 'i', 'I', 0 },
+{ 0x24, 0, 'j', 'J', 0 },
+{ 0x25, 0, 'k', 'K', 0 },
+{ 0x26, 0, 'l', 'L', 0 },
+{ 0x32, 0, 'm', 'M', 0 },
+{ 0x31, 0, 'n', 'N', 0 },
+{ 0x18, 0, 'o', 'O', 0 },
+{ 0x19, 0, 'p', 'P', 0 },
+{ 0x10, 0, 'q', 'Q', 0 },
+{ 0x13, 0, 'r', 'R', 0 },
+{ 0x1f, 0, 's', 'S', 0 },
+{ 0x14, 0, 't', 'T', 0 },
+{ 0x16, 0, 'u', 'U', 0 },
+{ 0x2f, 0, 'v', 'V', 0 },
+{ 0x11, 0, 'w', 'W', 0 },
+{ 0x2d, 0, 'x', 'X', 0 },
+{ 0x15, 0, 'y', 'Y', 0 },
+{ 0x2c, 0, 'z', 'Z', 0 },
+
+{ 0x02, 0, '1', '!', 0 },
+{ 0x03, 0, '2', '@', 0 },
+{ 0x04, 0, '3', '#', 0 },
+{ 0x05, 0, '4', '$', 0 },
+{ 0x06, 0, '5', '%', 0 },
+{ 0x07, 0, '6', '^', 0 },
+{ 0x08, 0, '7', '&', 0 },
+{ 0x09, 0, '8', '*', 0 },
+{ 0x0a, 0, '9', '(', 0 },
+{ 0x0b, 0, '0', ')', 0 },
+
+{ 0x29, 0, '\'', '~', 0 },
+{ 0x0c, 0, '-', '_', 0 },
+{ 0x0d, 0, '=', '+', 0 },
+{ 0x1a, 0, '[', '{', 0 },
+{ 0x1b, 0, ']', '}', 0 },
+{ 0x2b, 0, '\\', '|', 0 },
+{ 0x27, 0, ';', ':', 0 },
+{ 0x28, 0, '\'', '"', 0 },
+{ 0x33, 0, ',', '<', 0 },
+{ 0x34, 0, '.', '>', 0 },
+{ 0x35, 0, '/', '?', 0 },
+
+{ 0x4f, 0, 0, 0, '1' },
+{ 0x50, 0, 0, 0, '2' },
+{ 0x51, 0, 0, 0, '3' },
+{ 0x4b, 0, 0, 0, '4' },
+{ 0x4c, 0, 0, 0, '5' },
+{ 0x4d, 0, 0, 0, '6' },
+{ 0x47, 0, 0, 0, '7' },
+{ 0x48, 0, 0, 0, '8' },
+{ 0x49, 0, 0, 0, '9' },
+{ 0x52, 0, 0, 0, '0' },
+
+{ 0x4a, 0, '-', '-', 0 },
+{ 0x4e, 0, '+', '+', 0 },
+{ 0x37, 0, '*', '*', 0 },
+{ 0x35, 1, '/', '/', 0 },
+{ 0x53, 0, 0, 0, '.' },
+
+{ 0x39, 0, ' ', ' ', 0 },
+
+{ 0x1c, 0, '\r', '\r', 0 },
+{ 0x1c, 1, '\r', '\r', 0 },
+{ 0x0e, 0, 0x08, 0x08, 0 }, /* backspace */
+
+{ 0, 0, 0, 0, 0 }
+};
+
+
+static void
+IntUpdateControlKeyState(LPDWORD State, PKEYBOARD_INPUT_DATA InputData)
+{
+ DWORD Value = 0;
+
+ if (InputData->Flags & KEY_E1) /* Only the pause key has E1 */
+ return;
+
+ if (!(InputData->Flags & KEY_E0)) {
+ switch (InputData->MakeCode) {
+ case 0x2a:
+ case 0x36:
+ Value = SHIFT_PRESSED;
+ break;
+
+ case 0x1d:
+ Value = LEFT_CTRL_PRESSED;
+ break;
+
+ case 0x38:
+ Value = LEFT_ALT_PRESSED;
+ break;
+
+ default:
+ return;
+ }
+ } else {
+ switch (InputData->MakeCode) {
+ case 0x1d:
+ Value = RIGHT_CTRL_PRESSED;
+ break;
+
+ case 0x38:
+ Value = RIGHT_ALT_PRESSED;
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ if (InputData->Flags & KEY_BREAK)
+ *State &= ~Value;
+ else
+ *State |= Value;
+}
+
+static DWORD
+IntVKFromKbdInput(PKEYBOARD_INPUT_DATA InputData, DWORD KeyState)
+{
+ if (!(KeyState & ENHANCED_KEY)) {
+ DPRINT("Not enhanced, using %x\n", InputData->MakeCode & 0x7f);
+ return KeyTable[InputData->MakeCode & 0x7f];
+ }
+
+ DPRINT("Enhanced, using %x\n", InputData->MakeCode & 0x7f);
+ return KeyTableEnhanced[InputData->MakeCode & 0x7f];
+}
+
+static UCHAR
+IntAsciiFromInput(PKEYBOARD_INPUT_DATA InputData, DWORD KeyState)
+{
+ UINT Counter = 0;
+ USHORT Enhanced = 0;
+
+ if (KeyState & ENHANCED_KEY) Enhanced = 1;
+
+ while (ScanToAscii[Counter].ScanCode != 0) {
+ if ((ScanToAscii[Counter].ScanCode == InputData->MakeCode) &&
+ (ScanToAscii[Counter].Enhanced == Enhanced)) {
+ if (ScanToAscii[Counter].NumLock) {
+ if ((KeyState & NUMLOCK_ON) &&
+ !(KeyState & SHIFT_PRESSED)) {
+ return ScanToAscii[Counter].NumLock;
+ } else {
+ return ScanToAscii[Counter].Normal;
+ }
+ }
+ if (KeyState & SHIFT_PRESSED)
+ return ScanToAscii[Counter].Shift;
+
+ return ScanToAscii[Counter].Normal;
+ }
+ Counter++;
+ }
+
+ return 0;
+}
+
+/* This is going to be quick and messy. The usetup app runs in native mode
+ * so it cannot use the translation routines in win32k which means it'll have
+ * to be done here too.
+ *
+ * Only the bKeyDown, AsciiChar and wVirtualKeyCode members are used
+ * in the app so I'll just fill the others with somewhat sane values
+ */
+NTSTATUS
+IntTranslateKey(PKEYBOARD_INPUT_DATA InputData, KEY_EVENT_RECORD *Event)
+{
+ static DWORD dwControlKeyState;
+
+ RtlZeroMemory(Event, sizeof(KEY_EVENT_RECORD));
+
+ if (!(InputData->Flags & KEY_BREAK))
+ Event->bKeyDown = TRUE;
+ else
+ Event->bKeyDown = FALSE;
+
+ Event->wRepeatCount = 1;
+ Event->wVirtualScanCode = InputData->MakeCode;
+
+ DPRINT("Translating: %x\n", InputData->MakeCode);
+
+ IntUpdateControlKeyState(&dwControlKeyState, InputData);
+ Event->dwControlKeyState = dwControlKeyState;
+
+ if (InputData->Flags & KEY_E0)
+ Event->dwControlKeyState |= ENHANCED_KEY;
+
+ Event->wVirtualKeyCode = IntVKFromKbdInput(InputData,
+ Event->dwControlKeyState);
+
+ DPRINT("Result: %x\n", Event->wVirtualKeyCode);
+
+ if (Event->bKeyDown) {
+ Event->uChar.AsciiChar =
+ IntAsciiFromInput(InputData,
+ Event->dwControlKeyState);
+ DPRINT("Char: %x\n", Event->uChar.AsciiChar);
+ } else {
+ Event->uChar.AsciiChar = 0;
+ }
+
+ return STATUS_SUCCESS;
+}
--- /dev/null
+/*
+ * ReactOS kernel
+ * Copyright (C) 2003 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* $Id: keytrans.h 12852 2005-01-06 13:58:04Z mf $
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS text-mode setup
+ * FILE: subsys/system/usetup/keytrans.h
+ * PURPOSE: Keyboard translation functionality
+ * PROGRAMMER: Tinus
+ */
+
+#ifndef __KEYTRANS_H__
+#define __KEYTRANS_H__
+
+NTSTATUS
+IntTranslateKey(PKEYBOARD_INPUT_DATA InputData, KEY_EVENT_RECORD *Event);
+
+#endif /* __KEYTRANS_H__ */
+
+/* EOF */
TARGET_OBJECTS = bootsup.o cabinet.o console.o drivesup.o filequeue.o \
filesup.o format.o fslist.o genlist.o infcache.o \
inicache.o partlist.o progress.o registry.o settings.o \
- usetup.o
+ usetup.o keytrans.o
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk
-# EOF
\ No newline at end of file
+# EOF
nInBufferSize,
lpOutBuffer,
nOutBufferSize, FALSE, &Event, &Iosb);
+ DPRINT1("IRP: %x\n", Irp);
Status = IoCallDriver(DeviceObject, Irp);
/* ntuser */
#define TAG_MOUSE TAG('M', 'O', 'U', 'S') /* mouse */
+#define TAG_KEYBOARD TAG('K', 'B', 'D', ' ') /* keyboard */
#define TAG_ACCEL TAG('A', 'C', 'C', 'L') /* accelerator */
#define TAG_HOOK TAG('W', 'N', 'H', 'K') /* hook */
#define TAG_HOTKEY TAG('H', 'O', 'T', 'K') /* hotkey */
#include <w32k.h>
#include <rosrtl/string.h>
+#include <ddk/ntddkbd.h>
/* GLOBALS *******************************************************************/
}
}
+/* Returns a value that indicates if the key is a modifier key, and
+ * which one.
+ */
+STATIC UINT STDCALL
+IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
+{
+ if (InputData->Flags & KEY_E1)
+ return 0;
+
+ if (!(InputData->Flags & KEY_E0))
+ {
+ switch (InputData->MakeCode)
+ {
+ case 0x2a: /* left shift */
+ case 0x36: /* right shift */
+ return MOD_SHIFT;
+
+ case 0x1d: /* left control */
+ return MOD_CONTROL;
+
+ case 0x38: /* left alt */
+ return MOD_ALT;
+
+ default:
+ return 0;
+ }
+ }
+ else
+ {
+ switch (InputData->MakeCode)
+ {
+ case 0x1d: /* right control */
+ return MOD_CONTROL;
+
+ case 0x38: /* right alt */
+ return MOD_ALT;
+
+ case 0x5b: /* left gui (windows) */
+ case 0x5c: /* right gui (windows) */
+ return MOD_WIN;
+
+ default:
+ return 0;
+ }
+ }
+}
+
+/* Asks the keyboard driver to send a small table that shows which
+ * lights should connect with which scancodes
+ */
+STATIC NTSTATUS STDCALL
+IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
+ PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
+{
+ NTSTATUS Status;
+ DWORD Size = 0;
+ IO_STATUS_BLOCK Block;
+ PKEYBOARD_INDICATOR_TRANSLATION Ret;
+
+ Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
+
+ Ret = ExAllocatePoolWithTag(PagedPool,
+ Size,
+ TAG_KEYBOARD);
+
+ while (Ret)
+ {
+ Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
+ NULL,
+ NULL,
+ NULL,
+ &Block,
+ IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
+ NULL, 0,
+ Ret, Size);
+
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ break;
+
+ ExFreePool(Ret);
+
+ Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
+
+ Ret = ExAllocatePoolWithTag(PagedPool,
+ Size,
+ TAG_KEYBOARD);
+ }
+
+ if (!Ret)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ if (Status != STATUS_SUCCESS)
+ {
+ ExFreePool(Ret);
+ return Status;
+ }
+
+ *IndicatorTrans = Ret;
+ return Status;
+}
+
+/* Sends the keyboard commands to turn on/off the lights.
+ */
+STATIC NTSTATUS STDCALL
+IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
+ PKEYBOARD_INPUT_DATA KeyInput,
+ PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
+{
+ NTSTATUS Status;
+ UINT Count;
+ static KEYBOARD_INDICATOR_PARAMETERS Indicators;
+ IO_STATUS_BLOCK Block;
+
+ if (!IndicatorTrans)
+ return STATUS_NOT_SUPPORTED;
+
+ if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
+ return STATUS_SUCCESS;
+
+ for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
+ {
+ if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
+ {
+ Indicators.LedFlags ^=
+ IndicatorTrans->IndicatorList[Count].IndicatorFlags;
+
+ /* Update the lights on the hardware */
+
+ Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
+ NULL,
+ NULL,
+ NULL,
+ &Block,
+ IOCTL_KEYBOARD_SET_INDICATORS,
+ &Indicators, sizeof(Indicators),
+ NULL, 0);
+
+ return Status;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+STATIC VOID STDCALL
+IntKeyboardSendWinKeyMsg()
+{
+ PWINDOW_OBJECT Window;
+ MSG Mesg;
+ NTSTATUS Status;
+
+ Status = ObmReferenceObjectByHandle(InputWindowStation->HandleTable,
+ InputWindowStation->ShellWindow,
+ otWindow,
+ (PVOID *)&Window);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Couldn't find window to send Windows key message!\n");
+ return;
+ }
+
+ Mesg.hwnd = InputWindowStation->ShellWindow;
+ Mesg.message = WM_SYSCOMMAND;
+ Mesg.wParam = SC_TASKLIST;
+ Mesg.lParam = 0;
+
+ /* The QS_HOTKEY is just a guess */
+ MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
+
+ ObmDereferenceObject(Window);
+}
+
+STATIC VOID STDCALL
+IntKeyboardSendAltKeyMsg()
+{
+ MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
+}
+
STATIC VOID STDCALL
KeyboardThreadMain(PVOID StartContext)
{
MSG msg;
PUSER_MESSAGE_QUEUE FocusQueue;
struct _ETHREAD *FocusThread;
+
+ PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
+ UINT ModifierState = 0;
+ USHORT LastMakeCode = 0;
+ USHORT LastFlags = 0;
+ UINT RepeatCount = 0;
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
InitializeObjectAttributes(&KeyboardObjectAttributes,
return; //(Status);
}
+ IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
+ &IndicatorTrans);
+
for (;;)
{
/*
while (InputThreadsRunning)
{
KEY_EVENT_RECORD KeyEvent;
+ BOOLEAN NumKeys = 1;
+ KEYBOARD_INPUT_DATA KeyInput;
+ KEYBOARD_INPUT_DATA NextKeyInput;
LPARAM lParam = 0;
- UINT fsModifiers;
+ UINT fsModifiers, fsNextModifiers;
struct _ETHREAD *Thread;
HWND hWnd;
int id;
NULL,
NULL,
&Iosb,
- &KeyEvent,
- sizeof(KEY_EVENT_RECORD),
+ &KeyInput,
+ sizeof(KEYBOARD_INPUT_DATA),
NULL,
NULL);
- DPRINT( "KeyRaw: %s %04x\n",
- KeyEvent.bKeyDown ? "down" : "up",
- KeyEvent.wVirtualScanCode );
+ DPRINT("KeyRaw: %s %04x\n",
+ (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
+ KeyInput.MakeCode );
if (Status == STATUS_ALERTED && !InputThreadsRunning)
- {
- break;
- }
+ break;
+
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to read from keyboard.\n");
return; //(Status);
}
- DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
+ /* Update modifier state */
+ fsModifiers = IntKeyboardGetModifiers(&KeyInput);
- fsModifiers = 0;
- if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
- fsModifiers |= MOD_ALT;
+ if (fsModifiers)
+ {
+ if (KeyInput.Flags & KEY_BREAK)
+ {
+ ModifierState &= ~fsModifiers;
+ }
+ else
+ {
+ ModifierState |= fsModifiers;
- if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
- fsModifiers |= MOD_CONTROL;
+ if (ModifierState == fsModifiers &&
+ (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
+ {
+ /* First send out special notifications
+ * (For alt, the message that turns on accelerator
+ * display, not sure what for win. Both TODO though.)
+ */
- if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
- fsModifiers |= MOD_SHIFT;
+ /* Read the next key before sending this one */
+ do
+ {
+ Status = NtReadFile (KeyboardDeviceHandle,
+ NULL,
+ NULL,
+ NULL,
+ &Iosb,
+ &NextKeyInput,
+ sizeof(KEYBOARD_INPUT_DATA),
+ NULL,
+ NULL);
+ DPRINT("KeyRaw: %s %04x\n",
+ (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
+ NextKeyInput.MakeCode );
- /* FIXME: Support MOD_WIN */
+ if (Status == STATUS_ALERTED && !InputThreadsRunning)
+ goto KeyboardEscape;
- lParam = KeyEvent.wRepeatCount |
- ((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
-
- /* Bit 24 indicates if this is an extended key */
- if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
- {
- lParam |= (1 << 24);
- }
-
- if (fsModifiers & MOD_ALT)
- {
- /* Context mode. 1 if ALT if pressed while the key is pressed */
- lParam |= (1 << 29);
- }
+ } while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
+ NextKeyInput.MakeCode == KeyInput.MakeCode);
+ /* ^ Ignore repeats, they'll be KEY_MAKE and the same
+ * code. I'm not caring about the counting, not sure
+ * if that matters. I think not.
+ */
- if (! KeyEvent.bKeyDown)
- {
- /* Transition state. 1 for KEY_UP etc, 0 for KEY_DOWN */
- lParam |= (1 << 31);
- }
-
- if (GetHotKey(InputWindowStation,
- fsModifiers,
- KeyEvent.wVirtualKeyCode,
- &Thread,
- &hWnd,
- &id))
- {
- if (KeyEvent.bKeyDown)
- {
- DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
- MsqPostHotKeyMessage (Thread,
- hWnd,
- (WPARAM)id,
- MAKELPARAM((WORD)fsModifiers,
- (WORD)msg.wParam));
+ /* If the ModifierState is now empty again, send a
+ * special notification and eat both keypresses
+ */
+
+ fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
+
+ if (fsNextModifiers)
+ ModifierState ^= fsNextModifiers;
+
+ if (ModifierState == 0)
+ {
+ if (fsModifiers == MOD_WIN)
+ IntKeyboardSendWinKeyMsg();
+ else if (fsModifiers == MOD_ALT)
+ IntKeyboardSendAltKeyMsg();
+ continue;
+ }
+
+ NumKeys = 2;
+ }
}
- continue;
}
- /* Find the target thread whose locale is in effect */
- if (!IntGetScreenDC())
- {
- FocusQueue = W32kGetPrimitiveMessageQueue();
- }
- else
+ for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
+ NumKeys--)
{
- FocusQueue = IntGetFocusMessageQueue();
- }
+ lParam = 0;
- if (!FocusQueue) continue;
+ IntKeyboardUpdateLeds(KeyboardDeviceHandle,
+ &KeyInput,
+ IndicatorTrans);
- if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT))
- msg.message = WM_SYSKEYDOWN;
- else if(KeyEvent.bKeyDown)
- msg.message = WM_KEYDOWN;
- else if(fsModifiers & MOD_ALT)
- msg.message = WM_SYSKEYUP;
- else
- msg.message = WM_KEYUP;
+ /* While we are working, we set up lParam. The format is:
+ * 0-15: The number of times this key has autorepeated
+ * 16-23: The keyboard scancode
+ * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
+ * Note that E1 is only used for PAUSE (E1-1D-45) and
+ * E0-45 happens not to be anything.
+ * 29: Alt is pressed ('Context code')
+ * 30: Previous state, if the key was down before this message
+ * This is a cheap way to ignore autorepeat keys
+ * 31: 1 if the key is being pressed
+ */
- msg.wParam = KeyEvent.wVirtualKeyCode;
- msg.lParam = lParam;
- msg.hwnd = FocusQueue->FocusWindow;
+ /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
+ * and it's the same key as the last one, increase the repeat
+ * count.
+ */
- FocusThread = FocusQueue->Thread;
+ if (!(KeyInput.Flags & KEY_BREAK))
+ {
+ if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
+ (KeyInput.MakeCode == LastMakeCode))
+ {
+ RepeatCount++;
+ lParam |= (1 << 30);
+ }
+ else
+ {
+ RepeatCount = 0;
+ LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
+ LastMakeCode = KeyInput.MakeCode;
+ }
+ }
+ else
+ {
+ LastFlags = 0;
+ LastMakeCode = 0; /* Should never match */
+ lParam |= (1 << 30) | (1 << 31);
+ }
- if (FocusThread && FocusThread->Tcb.Win32Thread &&
- FocusThread->Tcb.Win32Thread->KeyboardLayout)
- {
+ lParam |= RepeatCount;
+
+ lParam |= (KeyInput.MakeCode & 0xff) << 16;
+
+ if (KeyInput.Flags & (KEY_E0 | KEY_E1))
+ lParam |= (1 << 24);
+
+ if (ModifierState & MOD_ALT)
+ {
+ lParam |= (1 << 29);
+
+ if (!(KeyInput.Flags & KEY_BREAK))
+ msg.message = WM_SYSKEYDOWN;
+ else
+ msg.message = WM_SYSKEYUP;
+ }
+ else
+ {
+ if (!(KeyInput.Flags & KEY_BREAK))
+ msg.message = WM_KEYDOWN;
+ else
+ msg.message = WM_KEYUP;
+ }
+
+ /* Find the target thread whose locale is in effect */
+ if (!IntGetScreenDC())
+ FocusQueue = W32kGetPrimitiveMessageQueue();
+ else
+ FocusQueue = IntGetFocusMessageQueue();
+
+ /* This might cause us to lose hot keys, which are important
+ * (ctrl-alt-del secure attention sequence). Not sure if it
+ * can happen though.
+ */
+ if (!FocusQueue) continue;
+
+ msg.lParam = lParam;
+ msg.hwnd = FocusQueue->FocusWindow;
+
+ FocusThread = FocusQueue->Thread;
+
+ if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
+ FocusThread->Tcb.Win32Thread->KeyboardLayout))
+ continue;
+
+ /* This function uses lParam to fill wParam according to the
+ * keyboard layout in use.
+ */
W32kKeyProcessMessage(&msg,
FocusThread->Tcb.Win32Thread->KeyboardLayout);
- }
- else
- continue;
+
+ if (GetHotKey(InputWindowStation,
+ ModifierState,
+ msg.wParam,
+ &Thread,
+ &hWnd,
+ &id))
+ {
+ if (KeyEvent.bKeyDown)
+ {
+ DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
+ MsqPostHotKeyMessage (Thread,
+ hWnd,
+ (WPARAM)id,
+ MAKELPARAM((WORD)ModifierState,
+ (WORD)msg.wParam));
+ }
+ continue; /* Eat key up motion too */
+ }
- /*
- * Post a keyboard message.
- */
- MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
+ /*
+ * Post a keyboard message.
+ */
+ MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
+ }
}
+
+KeyboardEscape:
DPRINT( "KeyboardInput Thread Stopped...\n" );
}
}
-
NTSTATUS STDCALL
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
{
MK_CFLAGS += -Os -Wno-strict-aliasing -ftracer -momit-leaf-frame-pointer
MK_CFLAGS += -mpreferred-stack-boundary=2
- CC_VERSION=$(word 1,$(shell gcc -dumpversion))
- ifeq ($(CC_VERSION),3.4.3)
+ #CC_VERSION=$(word 1,$(shell gcc -dumpversion))
+ #ifeq ($(CC_VERSION),3.4.3)
MK_CFLAGS += -funit-at-a-time -fweb
- endif
+ #endif
#
# Remove Symbols if no debugging is used at all
IN PVOID Context,
IN ULONG Count);
-typedef NTSTATUS
+typedef VOID
(DDKAPI *PDRIVER_STARTIO)(
IN struct _DEVICE_OBJECT *DeviceObject,
IN struct _IRP *Irp);
USHORT KeyboardFlags;
} CM_KEYBOARD_DEVICE_DATA, *PCM_KEYBOARD_DEVICE_DATA;
-#define KEYBOARD_INSERT_ON 0x80
-#define KEYBOARD_CAPS_LOCK_ON 0x40
-#define KEYBOARD_NUM_LOCK_ON 0x20
-#define KEYBOARD_SCROLL_LOCK_ON 0x10
-#define KEYBOARD_ALT_KEY_DOWN 0x08
-#define KEYBOARD_CTRL_KEY_DOWN 0x04
-#define KEYBOARD_LEFT_SHIFT_DOWN 0x02
-#define KEYBOARD_RIGHT_SHIFT_DOWN 0x01
+#define KEYBOARD_INSERT_ON 0x08
+#define KEYBOARD_CAPS_LOCK_ON 0x04
+#define KEYBOARD_NUM_LOCK_ON 0x02
+#define KEYBOARD_SCROLL_LOCK_ON 0x01
+#define KEYBOARD_ALT_KEY_DOWN 0x80
+#define KEYBOARD_CTRL_KEY_DOWN 0x40
+#define KEYBOARD_LEFT_SHIFT_DOWN 0x20
+#define KEYBOARD_RIGHT_SHIFT_DOWN 0x10
typedef struct _CM_MCA_POS_DATA {
USHORT AdapterId;