From a70444fab1dcabfed17d495ba0b50f649f5d4a0a Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 1 May 2005 20:38:29 +0000 Subject: [PATCH] i8042prt driver by tinus. svn path=/trunk/; revision=14926 --- reactos/Makefile | 2 +- .../boot/freeldr/freeldr/reactos/setupldr.c | 6 + reactos/bootdata/hivesys.inf | 39 +- reactos/bootdata/txtsetup.sif | 10 +- reactos/drivers/input/Makefile | 2 +- reactos/drivers/input/i8042prt/README.txt | 83 ++ reactos/drivers/input/i8042prt/i8042prt.c | 804 ++++++++++++++++ reactos/drivers/input/i8042prt/i8042prt.h | 392 ++++++++ reactos/drivers/input/i8042prt/i8042prt.rc | 5 + reactos/drivers/input/i8042prt/keyboard.c | 701 ++++++++++++++ reactos/drivers/input/i8042prt/makefile | 17 + reactos/drivers/input/i8042prt/mouse.c | 865 ++++++++++++++++++ reactos/drivers/input/i8042prt/ps2pp.c | 140 +++ reactos/drivers/input/i8042prt/registry.c | 237 +++++ reactos/drivers/input/kbdclass/kbdclass.c | 306 +++++++ reactos/drivers/input/kbdclass/kbdclass.h | 98 ++ reactos/drivers/input/kbdclass/kbdclass.rc | 7 + reactos/drivers/input/kbdclass/makefile | 17 + reactos/drivers/input/mouclass/mouclass.c | 21 +- reactos/include/ddk/ntdd8042.h | 6 +- reactos/ntoskrnl/include/internal/kd.h | 22 +- reactos/subsys/system/usetup/bootsup.c | 2 +- reactos/subsys/system/usetup/console.c | 11 +- reactos/subsys/system/usetup/keytrans.c | 342 +++++++ reactos/subsys/system/usetup/keytrans.h | 35 + reactos/subsys/system/usetup/makefile | 4 +- reactos/subsys/win32k/eng/device.c | 1 + reactos/subsys/win32k/include/tags.h | 1 + reactos/subsys/win32k/ntuser/input.c | 469 ++++++++-- reactos/tools/helper.mk | 6 +- reactos/w32api/include/ddk/winddk.h | 18 +- 31 files changed, 4527 insertions(+), 142 deletions(-) create mode 100644 reactos/drivers/input/i8042prt/README.txt create mode 100644 reactos/drivers/input/i8042prt/i8042prt.c create mode 100644 reactos/drivers/input/i8042prt/i8042prt.h create mode 100644 reactos/drivers/input/i8042prt/i8042prt.rc create mode 100644 reactos/drivers/input/i8042prt/keyboard.c create mode 100644 reactos/drivers/input/i8042prt/makefile create mode 100644 reactos/drivers/input/i8042prt/mouse.c create mode 100644 reactos/drivers/input/i8042prt/ps2pp.c create mode 100644 reactos/drivers/input/i8042prt/registry.c create mode 100644 reactos/drivers/input/kbdclass/kbdclass.c create mode 100644 reactos/drivers/input/kbdclass/kbdclass.h create mode 100644 reactos/drivers/input/kbdclass/kbdclass.rc create mode 100644 reactos/drivers/input/kbdclass/makefile create mode 100644 reactos/subsys/system/usetup/keytrans.c create mode 100644 reactos/subsys/system/usetup/keytrans.h diff --git a/reactos/Makefile b/reactos/Makefile index bf84236ff85..b13aaf4a77b 100644 --- a/reactos/Makefile +++ b/reactos/Makefile @@ -84,7 +84,7 @@ DRIVERS_LIB = bzip2 oskittcp ip csq 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 diff --git a/reactos/boot/freeldr/freeldr/reactos/setupldr.c b/reactos/boot/freeldr/freeldr/reactos/setupldr.c index 3571447ad37..692e735631f 100644 --- a/reactos/boot/freeldr/freeldr/reactos/setupldr.c +++ b/reactos/boot/freeldr/freeldr/reactos/setupldr.c @@ -558,8 +558,14 @@ for(;;); /* 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")) diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index 3c09dc06ca8..fd216c3464f 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -575,11 +575,28 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Type",0x00010001,0x00000008 ;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 @@ -840,12 +857,12 @@ HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Start",0x00010001,0x00000002 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 diff --git a/reactos/bootdata/txtsetup.sif b/reactos/bootdata/txtsetup.sif index a8789319e4e..3e06f270f56 100644 --- a/reactos/bootdata/txtsetup.sif +++ b/reactos/bootdata/txtsetup.sif @@ -22,7 +22,9 @@ cdrom.sys = 3 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 @@ -96,14 +98,16 @@ Default = "XT-, AT- or extended keyboard (83-105 keys)" [Mouse] ; = ,, -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] ; = -msps2 = "MICROSOFT PS2 MOUSE" +i8042ps2 = "MICROSOFT PS2 MOUSE" +;msps2 = "MICROSOFT PS2 MOUSE" msser = "MICROSOFT SERIAL MOUSE" mswhs = "MICROSOFT MOUSE WITH WHEEL" none = "NO MOUSE" diff --git a/reactos/drivers/input/Makefile b/reactos/drivers/input/Makefile index 5e4fd073a87..e306322e47d 100644 --- a/reactos/drivers/input/Makefile +++ b/reactos/drivers/input/Makefile @@ -6,7 +6,7 @@ PATH_TO_TOP = ../.. include $(PATH_TO_TOP)/rules.mak -DRIVERS = keyboard mouclass psaux sermouse +DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass all: $(DRIVERS) diff --git a/reactos/drivers/input/i8042prt/README.txt b/reactos/drivers/input/i8042prt/README.txt new file mode 100644 index 00000000000..a8f09ff5f59 --- /dev/null +++ b/reactos/drivers/input/i8042prt/README.txt @@ -0,0 +1,83 @@ +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. diff --git a/reactos/drivers/input/i8042prt/i8042prt.c b/reactos/drivers/input/i8042prt/i8042prt.c new file mode 100644 index 00000000000..83d4454beba --- /dev/null +++ b/reactos/drivers/input/i8042prt/i8042prt.c @@ -0,0 +1,804 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include + +#define NDEBUG +#include + +#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); +} + diff --git a/reactos/drivers/input/i8042prt/i8042prt.h b/reactos/drivers/input/i8042prt/i8042prt.h new file mode 100644 index 00000000000..6d155e200e9 --- /dev/null +++ b/reactos/drivers/input/i8042prt/i8042prt.h @@ -0,0 +1,392 @@ +#ifndef _I8042DRV_H +#define _I8042DRV_H +#include +#include +#include + +#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_ diff --git a/reactos/drivers/input/i8042prt/i8042prt.rc b/reactos/drivers/input/i8042prt/i8042prt.rc new file mode 100644 index 00000000000..6c44176265e --- /dev/null +++ b/reactos/drivers/input/i8042prt/i8042prt.rc @@ -0,0 +1,5 @@ +#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 diff --git a/reactos/drivers/input/i8042prt/keyboard.c b/reactos/drivers/input/i8042prt/keyboard.c new file mode 100644 index 00000000000..e81a6a14138 --- /dev/null +++ b/reactos/drivers/input/i8042prt/keyboard.c @@ -0,0 +1,701 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include + +#define NDEBUG +#include + +#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); +} diff --git a/reactos/drivers/input/i8042prt/makefile b/reactos/drivers/input/i8042prt/makefile new file mode 100644 index 00000000000..43537fd11cb --- /dev/null +++ b/reactos/drivers/input/i8042prt/makefile @@ -0,0 +1,17 @@ +# $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 diff --git a/reactos/drivers/input/i8042prt/mouse.c b/reactos/drivers/input/i8042prt/mouse.c new file mode 100644 index 00000000000..b044b0fc89a --- /dev/null +++ b/reactos/drivers/input/i8042prt/mouse.c @@ -0,0 +1,865 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include + +#define NDEBUG +#include + +#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; +} diff --git a/reactos/drivers/input/i8042prt/ps2pp.c b/reactos/drivers/input/i8042prt/ps2pp.c new file mode 100644 index 00000000000..cf03f1e4058 --- /dev/null +++ b/reactos/drivers/input/i8042prt/ps2pp.c @@ -0,0 +1,140 @@ +/* + * 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 + +#include +#include + +#define NDEBUG +#include + +#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"); + } +} diff --git a/reactos/drivers/input/i8042prt/registry.c b/reactos/drivers/input/i8042prt/registry.c new file mode 100644 index 00000000000..d71d99a6056 --- /dev/null +++ b/reactos/drivers/input/i8042prt/registry.c @@ -0,0 +1,237 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include + +#define NDEBUG +#include + +#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"); +} + diff --git a/reactos/drivers/input/kbdclass/kbdclass.c b/reactos/drivers/input/kbdclass/kbdclass.c new file mode 100644 index 00000000000..866275ae61f --- /dev/null +++ b/reactos/drivers/input/kbdclass/kbdclass.c @@ -0,0 +1,306 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include + +#define NDEBUG +#include + +#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); +} diff --git a/reactos/drivers/input/kbdclass/kbdclass.h b/reactos/drivers/input/kbdclass/kbdclass.h new file mode 100644 index 00000000000..a96273d610d --- /dev/null +++ b/reactos/drivers/input/kbdclass/kbdclass.h @@ -0,0 +1,98 @@ +#ifndef _KEYBOARD_H_ +#define _KEYBOARD_H_ +#include +#include + +#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_ diff --git a/reactos/drivers/input/kbdclass/kbdclass.rc b/reactos/drivers/input/kbdclass/kbdclass.rc new file mode 100644 index 00000000000..732b237e456 --- /dev/null +++ b/reactos/drivers/input/kbdclass/kbdclass.rc @@ -0,0 +1,7 @@ +/* $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 diff --git a/reactos/drivers/input/kbdclass/makefile b/reactos/drivers/input/kbdclass/makefile new file mode 100644 index 00000000000..82baae6e403 --- /dev/null +++ b/reactos/drivers/input/kbdclass/makefile @@ -0,0 +1,17 @@ +# $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 diff --git a/reactos/drivers/input/mouclass/mouclass.c b/reactos/drivers/input/mouclass/mouclass.c index 553b2fd082d..8882a57d812 100644 --- a/reactos/drivers/input/mouclass/mouclass.c +++ b/reactos/drivers/input/mouclass/mouclass.c @@ -21,17 +21,22 @@ 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; @@ -52,19 +57,20 @@ BOOLEAN MouseClassCallBack( /* 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; } /* @@ -84,6 +90,7 @@ BOOLEAN MouseClassCallBack( ClassDeviceExtension->InputCount += ReadSize; KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql); + (*ConsumedCount) += ReadSize; } else { DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount); } diff --git a/reactos/include/ddk/ntdd8042.h b/reactos/include/ddk/ntdd8042.h index a0441fe3096..4bcace955ac 100644 --- a/reactos/include/ddk/ntdd8042.h +++ b/reactos/include/ddk/ntdd8042.h @@ -204,18 +204,18 @@ typedef struct _INTERNAL_I8042_HOOK_KEYBOARD { // // 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; diff --git a/reactos/ntoskrnl/include/internal/kd.h b/reactos/ntoskrnl/include/internal/kd.h index d41a796a35a..c5c7f096d64 100644 --- a/reactos/ntoskrnl/include/internal/kd.h +++ b/reactos/ntoskrnl/include/internal/kd.h @@ -203,17 +203,17 @@ typedef struct _KDP_DEBUG_MODE /* 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 */ diff --git a/reactos/subsys/system/usetup/bootsup.c b/reactos/subsys/system/usetup/bootsup.c index ba45f089dfc..0e654f4f98f 100644 --- a/reactos/subsys/system/usetup/bootsup.c +++ b/reactos/subsys/system/usetup/bootsup.c @@ -371,7 +371,7 @@ CreateFreeLoaderIniForReactos(PWCHAR IniPath, NULL, INSERT_LAST, L"Options", - L"/DEBUGPORT=SCREEN /NOGUIBOOT"); + L"/DEBUGPORT=COM1 /NOGUIBOOT"); /* Save the ini file */ IniCacheSave(IniCache, IniPath); diff --git a/reactos/subsys/system/usetup/console.c b/reactos/subsys/system/usetup/console.c index d256fa2d04e..a528394223f 100644 --- a/reactos/subsys/system/usetup/console.c +++ b/reactos/subsys/system/usetup/console.c @@ -28,9 +28,11 @@ #include "precomp.h" #include +#include #include "usetup.h" #include "console.h" +#include "keytrans.h" #define NDEBUG #include @@ -194,6 +196,7 @@ ReadConsoleInput(PINPUT_RECORD Buffer) { IO_STATUS_BLOCK Iosb; NTSTATUS Status; + KEYBOARD_INPUT_DATA InputData; Buffer->EventType = KEY_EVENT; Status = NtReadFile(StdInput, @@ -201,11 +204,17 @@ ReadConsoleInput(PINPUT_RECORD Buffer) 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); } diff --git a/reactos/subsys/system/usetup/keytrans.c b/reactos/subsys/system/usetup/keytrans.c new file mode 100644 index 00000000000..3ea75d17aa9 --- /dev/null +++ b/reactos/subsys/system/usetup/keytrans.c @@ -0,0 +1,342 @@ +/* + * 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 + +#include "precomp.h" +#include +#include +#include + +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; +} diff --git a/reactos/subsys/system/usetup/keytrans.h b/reactos/subsys/system/usetup/keytrans.h new file mode 100644 index 00000000000..61a757eaffb --- /dev/null +++ b/reactos/subsys/system/usetup/keytrans.h @@ -0,0 +1,35 @@ +/* + * 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 */ diff --git a/reactos/subsys/system/usetup/makefile b/reactos/subsys/system/usetup/makefile index a51941eb83a..daa91584d4c 100644 --- a/reactos/subsys/system/usetup/makefile +++ b/reactos/subsys/system/usetup/makefile @@ -23,10 +23,10 @@ TARGET_CFLAGS = -D__NTAPP__ -I$(PATH_TO_TOP)/lib/zlib -Wall -Werror -Wno-format 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 diff --git a/reactos/subsys/win32k/eng/device.c b/reactos/subsys/win32k/eng/device.c index ef6e005498a..948f61d4baf 100644 --- a/reactos/subsys/win32k/eng/device.c +++ b/reactos/subsys/win32k/eng/device.c @@ -58,6 +58,7 @@ EngDeviceIoControl(HANDLE hDevice, nInBufferSize, lpOutBuffer, nOutBufferSize, FALSE, &Event, &Iosb); + DPRINT1("IRP: %x\n", Irp); Status = IoCallDriver(DeviceObject, Irp); diff --git a/reactos/subsys/win32k/include/tags.h b/reactos/subsys/win32k/include/tags.h index 88634b7b1cd..9ef987f0774 100644 --- a/reactos/subsys/win32k/include/tags.h +++ b/reactos/subsys/win32k/include/tags.h @@ -5,6 +5,7 @@ /* 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 */ diff --git a/reactos/subsys/win32k/ntuser/input.c b/reactos/subsys/win32k/ntuser/input.c index 15374e54ced..5775b166447 100644 --- a/reactos/subsys/win32k/ntuser/input.c +++ b/reactos/subsys/win32k/ntuser/input.c @@ -31,6 +31,7 @@ #include #include +#include /* GLOBALS *******************************************************************/ @@ -219,6 +220,185 @@ MouseThreadMain(PVOID StartContext) } } +/* 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) { @@ -229,6 +409,12 @@ 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, @@ -248,6 +434,9 @@ KeyboardThreadMain(PVOID StartContext) return; //(Status); } + IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle, + &IndicatorTrans); + for (;;) { /* @@ -267,8 +456,11 @@ KeyboardThreadMain(PVOID StartContext) 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; @@ -278,124 +470,223 @@ KeyboardThreadMain(PVOID StartContext) 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 (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) - fsModifiers |= MOD_CONTROL; - - if (KeyEvent.dwControlKeyState & SHIFT_PRESSED) - fsModifiers |= MOD_SHIFT; - - /* FIXME: Support MOD_WIN */ - - lParam = KeyEvent.wRepeatCount | - ((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000; - - /* Bit 24 indicates if this is an extended key */ - if (KeyEvent.dwControlKeyState & ENHANCED_KEY) + if (fsModifiers) { - lParam |= (1 << 24); - } - - if (fsModifiers & MOD_ALT) - { - /* Context mode. 1 if ALT if pressed while the key is pressed */ - lParam |= (1 << 29); - } - - 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) + if (KeyInput.Flags & KEY_BREAK) { - DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id); - MsqPostHotKeyMessage (Thread, - hWnd, - (WPARAM)id, - MAKELPARAM((WORD)fsModifiers, - (WORD)msg.wParam)); + ModifierState &= ~fsModifiers; + } + else + { + ModifierState |= fsModifiers; + + 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.) + */ + + /* 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 ); + + if (Status == STATUS_ALERTED && !InputThreadsRunning) + goto KeyboardEscape; + + } 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 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()) + for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)), + NumKeys--) { - FocusQueue = W32kGetPrimitiveMessageQueue(); - } - else - { - 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) { diff --git a/reactos/tools/helper.mk b/reactos/tools/helper.mk index 625eedf6bd9..bf818f6b5e1 100644 --- a/reactos/tools/helper.mk +++ b/reactos/tools/helper.mk @@ -683,10 +683,10 @@ ifneq ($(DBG),1) 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 diff --git a/reactos/w32api/include/ddk/winddk.h b/reactos/w32api/include/ddk/winddk.h index 5e4af896a4c..08e88069dfe 100644 --- a/reactos/w32api/include/ddk/winddk.h +++ b/reactos/w32api/include/ddk/winddk.h @@ -529,7 +529,7 @@ typedef VOID IN PVOID Context, IN ULONG Count); -typedef NTSTATUS +typedef VOID (DDKAPI *PDRIVER_STARTIO)( IN struct _DEVICE_OBJECT *DeviceObject, IN struct _IRP *Irp); @@ -1432,14 +1432,14 @@ typedef struct _CM_KEYBOARD_DEVICE_DATA { 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;