i8042prt driver by tinus.
authorAlex Ionescu <aionescu@gmail.com>
Sun, 1 May 2005 20:38:29 +0000 (20:38 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Sun, 1 May 2005 20:38:29 +0000 (20:38 +0000)
svn path=/trunk/; revision=14926

31 files changed:
reactos/Makefile
reactos/boot/freeldr/freeldr/reactos/setupldr.c
reactos/bootdata/hivesys.inf
reactos/bootdata/txtsetup.sif
reactos/drivers/input/Makefile
reactos/drivers/input/i8042prt/README.txt [new file with mode: 0644]
reactos/drivers/input/i8042prt/i8042prt.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/i8042prt.h [new file with mode: 0644]
reactos/drivers/input/i8042prt/i8042prt.rc [new file with mode: 0644]
reactos/drivers/input/i8042prt/keyboard.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/makefile [new file with mode: 0644]
reactos/drivers/input/i8042prt/mouse.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/ps2pp.c [new file with mode: 0644]
reactos/drivers/input/i8042prt/registry.c [new file with mode: 0644]
reactos/drivers/input/kbdclass/kbdclass.c [new file with mode: 0644]
reactos/drivers/input/kbdclass/kbdclass.h [new file with mode: 0644]
reactos/drivers/input/kbdclass/kbdclass.rc [new file with mode: 0644]
reactos/drivers/input/kbdclass/makefile [new file with mode: 0644]
reactos/drivers/input/mouclass/mouclass.c
reactos/include/ddk/ntdd8042.h
reactos/ntoskrnl/include/internal/kd.h
reactos/subsys/system/usetup/bootsup.c
reactos/subsys/system/usetup/console.c
reactos/subsys/system/usetup/keytrans.c [new file with mode: 0644]
reactos/subsys/system/usetup/keytrans.h [new file with mode: 0644]
reactos/subsys/system/usetup/makefile
reactos/subsys/win32k/eng/device.c
reactos/subsys/win32k/include/tags.h
reactos/subsys/win32k/ntuser/input.c
reactos/tools/helper.mk
reactos/w32api/include/ddk/winddk.h

index bf84236..b13aaf4 100644 (file)
@@ -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
index 3571447..692e735 100644 (file)
@@ -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"))
index 3c09dc0..fd216c3 100644 (file)
@@ -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
index a878931..3e06f27 100644 (file)
@@ -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]
 ;<id> = <user friendly name>,<spare>,<service key name>
-msps2 = "Microsoft PS2 Mouse",,psaux
+i8042ps2 = "PS2 Mouse",,i8042prt
+;msps2 = "Microsoft PS2 Mouse",,psaux
 msser = "Microsoft Serial Mouse",,sermouse
 mswhs = "Microsoft Serial Wheel Mouse",,sermouse
 none  = "No Mouse"
 
 [Map.Mouse]
 ;<id> = <pnp id string>
-msps2 = "MICROSOFT PS2 MOUSE"
+i8042ps2 = "MICROSOFT PS2 MOUSE"
+;msps2 = "MICROSOFT PS2 MOUSE"
 msser = "MICROSOFT SERIAL MOUSE"
 mswhs = "MICROSOFT MOUSE WITH WHEEL"
 none  = "NO MOUSE"
index 5e4fd07..e306322 100644 (file)
@@ -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 (file)
index 0000000..a8f09ff
--- /dev/null
@@ -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 (file)
index 0000000..83d4454
--- /dev/null
@@ -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 <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Driver data
+ */
+#define I8042_TIMEOUT 500000
+
+#define I8042_MAX_COMMAND_LENGTH 16
+#define I8042_MAX_UPWARDS_STACK 5
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * FUNCTION: Write data to a port, waiting first for it to become ready
+ */
+BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
+{
+       ULONG ResendIterations = DevExt->Settings.PollingIterations;
+
+       while ((KBD_IBF & READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT)) &&
+              (ResendIterations--))
+       {
+               KeStallExecutionProcessor(50);
+       }
+
+       if (ResendIterations) {
+               WRITE_PORT_UCHAR((PUCHAR)addr,data);
+               DPRINT("Sent %x to %x\n", data, addr);
+               return TRUE;
+       }
+       return FALSE;
+}
+
+#if 0 /* function is not needed */
+/*
+ * FUNCTION: Write data to a port, without waiting first
+ */
+static BOOLEAN I8042WriteNoWait(PDEVICE_EXTENSION DevExt, int addr, BYTE data)
+{
+       WRITE_PORT_UCHAR((PUCHAR)addr,data);
+       DPRINT("Sent %x to %x\n", data, addr);
+       return TRUE;
+}
+#endif
+
+/*
+ * FUNCTION: Read data from port 0x60
+ */
+NTSTATUS I8042ReadData(BYTE *Data)
+{
+       BYTE Status;
+       Status=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+
+       // If data is available
+       if ((Status & KBD_OBF)) {
+               Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
+
+               // If the data is valid (not timeout, not parity error)
+               if ((~Status) & (KBD_GTO | KBD_PERR))
+                       return STATUS_SUCCESS;
+       }
+       return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS I8042ReadStatus(BYTE *Status)
+{
+       Status[0]=READ_PORT_UCHAR((PUCHAR)I8042_CTRL_PORT);
+       return STATUS_SUCCESS;
+}
+
+/*
+ * FUNCTION: Read data from port 0x60
+ */
+NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data)
+{
+       ULONG Counter = DevExt->Settings.PollingIterations;
+       NTSTATUS Status;
+
+       while (Counter--) {
+               Status = I8042ReadData(Data);
+
+               if (STATUS_SUCCESS == Status)
+                       return Status;
+
+               KeStallExecutionProcessor(50);
+       }
+       // Timed out
+       return STATUS_IO_TIMEOUT;
+}
+
+VOID I8042Flush()
+{
+       BYTE Ignore;
+
+       while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
+               ; /* drop */
+       }
+}
+
+VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
+                               UCHAR Value,
+                               UCHAR SelectCmd)
+{
+       if (SelectCmd) 
+               if (!I8042Write(DevExt, I8042_CTRL_PORT, SelectCmd))
+                       return;
+
+       I8042Write(DevExt, I8042_DATA_PORT, Value);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
+                                     UCHAR Port,
+                                     UCHAR Value,
+                                     BOOLEAN WaitForAck)
+{
+       NTSTATUS Status;
+       UCHAR Ack;
+       UINT ResendIterations = DevExt->Settings.ResendIterations + 1;
+
+       do {
+               if (Port) 
+                       if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
+                               return STATUS_TIMEOUT;
+
+               if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
+                       return STATUS_TIMEOUT;
+
+               if (WaitForAck) {
+                       Status = I8042ReadDataWait(DevExt, &Ack);
+                       if (Status != STATUS_SUCCESS)
+                               return Status;
+                       if (Ack == KBD_ACK)
+                               return STATUS_SUCCESS;
+                       if (Ack != KBD_RESEND)
+                               return STATUS_UNEXPECTED_IO_ERROR;
+               } else {
+                       return STATUS_SUCCESS;
+               }
+               ResendIterations--;
+       } while (ResendIterations);
+       return STATUS_TIMEOUT;
+}
+
+/*
+ * This one reads a value from the port; You don't have to specify
+ * which one, it'll always be from the one you talked to, so one function
+ * is enough this time. Note how MSDN specifies the
+ * WaitForAck parameter to be ignored.
+ */
+static NTSTATUS STDCALL I8042SynchReadPort(PVOID Context,
+                                           PUCHAR Value,
+                                           BOOLEAN WaitForAck)
+{
+       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)Context;
+
+       return I8042ReadDataWait(DevExt, Value);
+}
+
+/* Write the current byte of the packet. Returns FALSE in case
+ * of problems.
+ */
+static BOOLEAN STDCALL I8042PacketWrite(PDEVICE_EXTENSION DevExt)
+{
+       UCHAR Port = DevExt->PacketPort;
+
+       if (Port) {
+               if (!I8042Write(DevExt,
+                               I8042_CTRL_PORT,
+                               Port)) {
+                       /* something is really wrong! */
+                       DPRINT1("Failed to send packet byte!\n");
+                       return FALSE;
+               }
+       }
+
+       return I8042Write(DevExt,
+                         I8042_DATA_PORT,
+                         DevExt->Packet.Bytes[DevExt->Packet.CurrentByte]);
+}
+
+
+/*
+ * This function starts a packet. It must be called with the
+ * correct DIRQL.
+ */
+NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
+                                  PDEVICE_OBJECT Device,
+                                  PUCHAR Bytes,
+                                  ULONG ByteCount,
+                                  PIRP Irp)
+{
+       KIRQL Irql;
+       NTSTATUS Status;
+       PFDO_DEVICE_EXTENSION FdoDevExt = Device->DeviceExtension;
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+       DevExt->CurrentIrp = Irp;
+       DevExt->CurrentIrpDevice = Device;
+
+       if (Idle != DevExt->Packet.State) {
+               Status = STATUS_DEVICE_BUSY;
+               goto startpacketdone;
+       }
+
+       DevExt->Packet.Bytes = Bytes;
+       DevExt->Packet.CurrentByte = 0;
+       DevExt->Packet.ByteCount = ByteCount;
+       DevExt->Packet.State = SendingBytes;
+       DevExt->PacketResult = Status = STATUS_PENDING;
+
+       if (Mouse == FdoDevExt->Type)
+               DevExt->PacketPort = 0xD4;
+       else
+               DevExt->PacketPort = 0;
+
+       if (!I8042PacketWrite(DevExt)) {
+               Status = STATUS_TIMEOUT;
+               DevExt->Packet.State = Idle;
+               DevExt->PacketResult = STATUS_ABANDONED;
+               goto startpacketdone;
+       }
+
+       DevExt->Packet.CurrentByte++;
+
+startpacketdone:
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+
+       if (STATUS_PENDING != Status) {
+               DevExt->CurrentIrp = NULL;
+               DevExt->CurrentIrpDevice = NULL;
+               Irp->IoStatus.Status = Status;
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       }
+       return Status;
+}
+
+BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
+                            UCHAR Output)
+{
+       if (Idle == DevExt->Packet.State)
+               return FALSE;
+
+       switch (Output) {
+       case KBD_RESEND:
+               DevExt->PacketResends++;
+               if (DevExt->PacketResends > DevExt->Settings.ResendIterations) {
+                       DevExt->Packet.State = Idle;
+                       DevExt->PacketComplete = TRUE;
+                       DevExt->PacketResult = STATUS_TIMEOUT;
+                       DevExt->PacketResends = 0;
+                       return TRUE;
+               }
+               DevExt->Packet.CurrentByte--;
+               break;
+
+       case KBD_NACK:
+               DevExt->Packet.State = Idle;
+               DevExt->PacketComplete = TRUE;
+               DevExt->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
+               DevExt->PacketResends = 0;
+               return TRUE;
+
+       default:
+               DevExt->PacketResends = 0;
+       }
+
+       if (DevExt->Packet.CurrentByte >= DevExt->Packet.ByteCount) {
+               DevExt->Packet.State = Idle;
+               DevExt->PacketComplete = TRUE;
+               DevExt->PacketResult = STATUS_SUCCESS;
+               return TRUE;
+       }
+
+       if (!I8042PacketWrite(DevExt)) {
+               DevExt->Packet.State = Idle;
+               DevExt->PacketComplete = TRUE;
+               DevExt->PacketResult = STATUS_TIMEOUT;
+               return TRUE;
+       }
+       DevExt->Packet.CurrentByte++;
+
+       return TRUE;
+}
+
+VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
+{
+       BOOL FinishIrp = FALSE;
+       NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
+       KIRQL Irql;
+
+       /* If the interrupt happens before this is setup, the key
+        * was already in the buffer. Too bad! */
+       if (!DevExt->HighestDIRQLInterrupt)
+               return;
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+       if (Idle == DevExt->Packet.State &&
+           DevExt->PacketComplete) {
+               FinishIrp = TRUE;
+               Result = DevExt->PacketResult;
+               DevExt->PacketComplete = FALSE;
+       }
+
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt,
+                                  Irql);
+
+       if (!FinishIrp)
+               return;
+
+       if (DevExt->CurrentIrp) {
+               DevExt->CurrentIrp->IoStatus.Status = Result;
+               IoCompleteRequest(DevExt->CurrentIrp, IO_NO_INCREMENT);
+               IoStartNextPacket(DevExt->CurrentIrpDevice, FALSE);
+               DevExt->CurrentIrp = NULL;
+               DevExt->CurrentIrpDevice = NULL;
+       }
+}
+
+VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
+                           PVOID Context)
+{
+       KEVENT Event;
+       IO_STATUS_BLOCK IoStatus;
+       NTSTATUS Status;
+       PDEVICE_EXTENSION DevExt;
+       PFDO_DEVICE_EXTENSION FdoDevExt;
+       PIRP NewIrp;
+       PI8042_HOOK_WORKITEM WorkItemData = (PI8042_HOOK_WORKITEM)Context;
+
+       ULONG IoControlCode;
+       PVOID InputBuffer;
+       ULONG InputBufferLength;
+       BOOLEAN IsKbd;
+
+       DPRINT("HookWorkItem\n");
+       
+       FdoDevExt = (PFDO_DEVICE_EXTENSION)
+                                 DeviceObject->DeviceExtension;
+
+       DevExt = FdoDevExt->PortDevExt;
+
+       if (WorkItemData->Target == DevExt->KeyboardData.ClassDeviceObject) {
+               IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
+               InputBuffer = &DevExt->KeyboardHook;
+               InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
+               IsKbd = TRUE;
+               DPRINT ("is for keyboard.\n");
+       } else if (WorkItemData->Target == DevExt->MouseData.ClassDeviceObject){
+               IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
+               InputBuffer = &DevExt->MouseHook;
+               InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
+               IsKbd = FALSE;
+               DPRINT ("is for mouse.\n");
+       } else {
+               DPRINT1("I8042SendHookWorkItem: Can't find DeviceObject\n");
+               WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
+               goto hookworkitemdone;
+       }
+
+       KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+       NewIrp = IoBuildDeviceIoControlRequest(
+                      IoControlCode,
+                      WorkItemData->Target,
+                      InputBuffer,
+                      InputBufferLength,
+                      NULL,
+                      0,
+                      TRUE,
+                      &Event,
+                     &IoStatus);
+                                  
+       if (!NewIrp) {
+               DPRINT("IOCTL_INTERNAL_(device)_CONNECT: "
+                      "Can't allocate IRP\n");
+               WorkItemData->Irp->IoStatus.Status = 
+                             STATUS_INSUFFICIENT_RESOURCES;
+               goto hookworkitemdone;
+       }
+
+       Status = IoCallDriver(
+                       WorkItemData->Target,
+                       NewIrp);
+
+       if (STATUS_PENDING == Status)
+               KeWaitForSingleObject(&Event,
+                                     Executive,
+                                     KernelMode,
+                                     FALSE,
+                                     NULL);
+
+       if (IsKbd) {
+               /* Call the hooked initialization if it exists */
+               if (DevExt->KeyboardHook.InitializationRoutine) {
+                       Status = DevExt->KeyboardHook.InitializationRoutine(
+                                             DevExt->KeyboardHook.Context,
+                                             DevExt,
+                                             I8042SynchReadPort,
+                                             I8042SynchWritePortKbd,
+                                             FALSE);
+                       if (Status != STATUS_SUCCESS) {
+                               WorkItemData->Irp->IoStatus.Status = Status;
+                               goto hookworkitemdone;
+                       }
+               }
+               /* TODO: Now would be the right time to enable the interrupt */
+
+               DevExt->KeyboardClaimed = TRUE;
+       } else {
+               /* Mouse doesn't have this, but we need to send a
+                * reset to start the detection.
+                */
+               KIRQL Irql;
+
+               Irql = KeAcquireInterruptSpinLock(
+                                           DevExt->HighestDIRQLInterrupt);
+
+               I8042Write(DevExt, I8042_CTRL_PORT, 0xD4);
+               I8042Write(DevExt, I8042_DATA_PORT, 0xFF); 
+
+               KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+       }
+
+       WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
+
+hookworkitemdone:
+       WorkItemData->Irp->IoStatus.Information = 0;
+       IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
+
+       IoFreeWorkItem(WorkItemData->WorkItem);
+       ExFreePool(WorkItemData);
+       DPRINT("HookWorkItem done\n");
+}
+
+VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       if (!I8042StartIoKbd(DeviceObject, Irp)) {
+               DPRINT1("Unhandled StartIo!\n");
+       }
+}
+
+NTSTATUS STDCALL I8042InternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+
+       DPRINT("InternalDeviceControl\n");
+
+       switch (FdoDevExt->Type) {
+       case Keyboard:
+               Status = I8042InternalDeviceControlKbd(DeviceObject, Irp);
+               break;
+       case Mouse:
+               Status = I8042InternalDeviceControlMouse(DeviceObject, Irp);
+               break;
+       }
+
+       if (Status == STATUS_INVALID_DEVICE_REQUEST) {
+               DPRINT1("Invalid internal device request!\n");
+       }
+
+       if (Status != STATUS_PENDING)
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+       return Status;
+}
+
+NTSTATUS STDCALL I8042CreateDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       NTSTATUS Status;
+
+       DPRINT ("I8042CreateDispatch\n");
+
+       Status = STATUS_SUCCESS;
+
+       Irp->IoStatus.Status = Status;
+       Irp->IoStatus.Information = 0;
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+       return Status;
+}
+
+static NTSTATUS STDCALL I8042BasicDetect(PDEVICE_EXTENSION DevExt)
+{
+       NTSTATUS Status;
+       UCHAR Value;
+       UINT Counter;
+
+       I8042Flush();
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST))
+               return STATUS_TIMEOUT;
+
+       // Wait longer?
+       Counter = 3;
+       do {
+               Status = I8042ReadDataWait(DevExt, &Value);
+       } while ((Counter--) && (STATUS_TIMEOUT == Status));
+               
+       if (Status != STATUS_SUCCESS)
+               return Status;
+
+       if (Value != 0x55) {
+               DPRINT1("Got %x instead of 55\n", Value);
+               return STATUS_IO_DEVICE_ERROR;
+       } 
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_LINE_TEST))
+               return STATUS_TIMEOUT;
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS)
+               return Status;
+
+       if (Value == 0) {
+               DevExt->KeyboardExists = TRUE;
+       } else {
+               DevExt->KeyboardExists = FALSE;
+       }
+       
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
+               return STATUS_TIMEOUT;
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS)
+               return Status;
+
+       if (Value == 0) {
+               DevExt->MouseExists = TRUE;
+       } else {
+               DevExt->MouseExists = FALSE;
+       }
+       
+       return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
+{
+       NTSTATUS Status;
+
+       Status = I8042BasicDetect(DevExt);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1("Basic keyboard detection failed: %x\n", Status);
+               return Status;
+       }
+
+       if (!DevExt->KeyboardExists) {
+               DPRINT("Keyboard not detected\n")
+               if (DevExt->Settings.Headless)
+                       /* Act as if it exists regardless */
+                       DevExt->KeyboardExists = TRUE;
+       } else {
+               DPRINT("Keyboard detected\n");
+               DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
+       }
+
+       if (DevExt->KeyboardExists) {
+               I8042KeyboardEnable(DevExt);
+               I8042KeyboardEnableInterrupt(DevExt);
+       }
+
+       if (DevExt->MouseExists)
+               I8042MouseEnable(DevExt);
+
+       return STATUS_SUCCESS;
+}
+
+static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
+                                       PDEVICE_OBJECT Pdo)
+{
+       UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\KeyboardClass0");
+       UNICODE_STRING MouseName = ROS_STRING_INITIALIZER(L"\\Device\\PointerClass0");
+       ULONG MappedIrqKeyboard = 0, MappedIrqMouse = 0;
+       KIRQL DirqlKeyboard = 0;
+       KIRQL DirqlMouse = 0;
+       KIRQL DirqlMax;
+       KAFFINITY Affinity;
+       NTSTATUS Status;
+       PDEVICE_EXTENSION DevExt;
+       PFDO_DEVICE_EXTENSION FdoDevExt;
+       PDEVICE_OBJECT Fdo;
+
+       DPRINT("I8042AddDevice\n");
+
+       IoCreateDevice(DriverObject,
+                      sizeof(DEVICE_EXTENSION),
+                      NULL,
+                      FILE_DEVICE_8042_PORT,
+                      FILE_DEVICE_SECURE_OPEN,
+                      TRUE,
+                      &Fdo);
+
+       IoAttachDeviceToDeviceStack(Fdo, Pdo);
+
+       DevExt = Fdo->DeviceExtension;
+
+       RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
+
+       I8042ReadRegistry(DriverObject, DevExt);
+
+       KeInitializeSpinLock(&DevExt->SpinLock);
+       InitializeListHead(&DevExt->BusDevices);
+
+       KeInitializeDpc(&DevExt->DpcKbd,
+                       I8042DpcRoutineKbd,
+                       DevExt);
+
+       KeInitializeDpc(&DevExt->DpcMouse,
+                       I8042DpcRoutineMouse,
+                       DevExt);
+
+       KeInitializeDpc(&DevExt->DpcMouseTimeout,
+                       I8042DpcRoutineMouseTimeout,
+                       DevExt);
+
+       KeInitializeTimer(&DevExt->TimerMouseTimeout);
+
+       Status = I8042Initialize(DevExt);
+       if (STATUS_SUCCESS != Status) {
+               DPRINT1("Initialization failure: %x\n", Status);
+               return Status;
+       }
+
+       if (DevExt->KeyboardExists) {
+               MappedIrqKeyboard = HalGetInterruptVector(Internal,
+                                                         0,
+                                                         0,
+                                                         KEYBOARD_IRQ,
+                                                         &DirqlKeyboard,
+                                                         &Affinity);
+
+               Status = IoCreateDevice(DriverObject,
+                                       sizeof(FDO_DEVICE_EXTENSION),
+                                       &DeviceName,
+                                       FILE_DEVICE_8042_PORT,
+                                       FILE_DEVICE_SECURE_OPEN,
+                                       TRUE,
+                                       &Fdo);
+
+               FdoDevExt = Fdo->DeviceExtension;
+
+               RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
+
+               FdoDevExt->PortDevExt = DevExt;
+               FdoDevExt->Type = Keyboard;
+               FdoDevExt->DeviceObject = Fdo;
+
+               Fdo->Flags |= DO_BUFFERED_IO;
+
+               DevExt->DebugWorkItem = IoAllocateWorkItem(Fdo);
+               DevExt->KeyboardObject = Fdo;
+
+               DevExt->KeyboardBuffer = ExAllocatePoolWithTag(
+                              NonPagedPool,
+                              DevExt->KeyboardAttributes.InputDataQueueLength *
+                                         sizeof(KEYBOARD_INPUT_DATA),
+                              TAG_I8042);
+
+               if (!DevExt->KeyboardBuffer) {
+                       DPRINT1("No memory for keyboardbuffer\n");
+                       return STATUS_INSUFFICIENT_RESOURCES;
+               }
+
+               InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
+       }
+
+       if (DevExt->MouseExists) {
+               MappedIrqMouse = HalGetInterruptVector(Internal,
+                                                         0,
+                                                         0,
+                                                         MOUSE_IRQ,
+                                                         &DirqlMouse,
+                                                         &Affinity);
+
+               Status = IoCreateDevice(DriverObject,
+                                       sizeof(FDO_DEVICE_EXTENSION),
+                                       &MouseName,
+                                       FILE_DEVICE_8042_PORT,
+                                       FILE_DEVICE_SECURE_OPEN,
+                                       TRUE,
+                                       &Fdo);
+
+               FdoDevExt = Fdo->DeviceExtension;
+
+               RtlZeroMemory(FdoDevExt, sizeof(FDO_DEVICE_EXTENSION));
+
+               FdoDevExt->PortDevExt = DevExt;
+               FdoDevExt->Type = Mouse;
+               FdoDevExt->DeviceObject = Fdo;
+
+               Fdo->Flags |= DO_BUFFERED_IO;
+               DevExt->MouseObject = Fdo;
+
+               DevExt->MouseBuffer = ExAllocatePoolWithTag(
+                              NonPagedPool,
+                              DevExt->MouseAttributes.InputDataQueueLength *
+                                            sizeof(MOUSE_INPUT_DATA),
+                              TAG_I8042);
+
+               if (!DevExt->MouseBuffer) {
+                       ExFreePool(DevExt->KeyboardBuffer);
+                       DPRINT1("No memory for mouse buffer\n");
+                       return STATUS_INSUFFICIENT_RESOURCES;
+               }
+
+               InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
+       }
+
+       if (DirqlKeyboard > DirqlMouse)
+               DirqlMax = DirqlKeyboard;
+       else
+               DirqlMax = DirqlMouse;
+
+       if (DevExt->KeyboardExists) {
+               Status = IoConnectInterrupt(&DevExt->KeyboardInterruptObject,
+                                           I8042InterruptServiceKbd,
+                                           (PVOID)DevExt,
+                                           &DevExt->SpinLock,
+                                           MappedIrqKeyboard,
+                                           DirqlKeyboard,
+                                           DirqlMax,
+                                           LevelSensitive,
+                                           FALSE,
+                                           Affinity,
+                                           FALSE);
+
+               DPRINT("Keyboard Irq Status: %x\n", Status);
+       }
+
+       if (DevExt->MouseExists) {
+               Status = IoConnectInterrupt(&DevExt->MouseInterruptObject,
+                                           I8042InterruptServiceMouse,
+                                           (PVOID)DevExt,
+                                           &DevExt->SpinLock,
+                                           MappedIrqMouse,
+                                           DirqlMouse,
+                                           DirqlMax,
+                                           LevelSensitive,
+                                           FALSE,
+                                           Affinity,
+                                           FALSE); 
+
+               DPRINT("Mouse Irq Status: %x\n", Status);
+       }
+
+       if (DirqlKeyboard > DirqlMouse)
+               DevExt->HighestDIRQLInterrupt = DevExt->KeyboardInterruptObject;
+       else
+               DevExt->HighestDIRQLInterrupt = DevExt->MouseInterruptObject;
+
+       DPRINT("I8042AddDevice done\n");
+
+       return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject, 
+                            PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Module entry point
+ */
+{
+       DPRINT("I8042 Driver 0.0.1\n");
+
+       DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
+       DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = 
+                                              I8042InternalDeviceControl; 
+
+       DriverObject->DriverStartIo = I8042StartIo;
+       DriverObject->DriverExtension->AddDevice = I8042AddDevice;
+
+       return(STATUS_SUCCESS);
+}
+
diff --git a/reactos/drivers/input/i8042prt/i8042prt.h b/reactos/drivers/input/i8042prt/i8042prt.h
new file mode 100644 (file)
index 0000000..6d155e2
--- /dev/null
@@ -0,0 +1,392 @@
+#ifndef _I8042DRV_H
+#define _I8042DRV_H
+#include <ddk/ntddk.h>
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define KEYBOARD_IRQ       1
+#define MOUSE_IRQ          12
+#define KBD_BUFFER_SIZE    32
+
+// should be in ntdd8042.h
+
+typedef VOID DDKAPI
+(*KEYBOARD_CLASS_SERVICE_CALLBACK) (
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PKEYBOARD_INPUT_DATA InputDataStart,
+       IN PKEYBOARD_INPUT_DATA InputDataEnd,
+       IN OUT PULONG InputDataConsumed
+);
+
+/* I'm not actually sure if this is in the ddk, would seem logical */
+typedef VOID DDKAPI
+(*MOUSE_CLASS_SERVICE_CALLBACK) (
+       IN PDEVICE_OBJECT DeviceObject,
+       IN PMOUSE_INPUT_DATA InputDataStart,
+       IN PMOUSE_INPUT_DATA InputDataEnd,
+       IN OUT PULONG InputDataConsumed
+);
+
+typedef struct _CONNECT_DATA {
+       PDEVICE_OBJECT ClassDeviceObject;
+       PVOID ClassService;
+} CONNECT_DATA, *PCONNECT_DATA;
+
+#define IOCTL_INTERNAL_KEYBOARD_CONNECT \
+   CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#define IOCTL_INTERNAL_MOUSE_CONNECT \
+   CTL_CODE(FILE_DEVICE_MOUSE, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+/* For some bizarre reason, these are different from the defines in
+ * w32api. I'm quite sure these are correct though, needs to be checked
+ * against the ddk
+ */
+#define KEYBOARD_SCROLL_LOCK_ON 0x01
+#define KEYBOARD_NUM_LOCK_ON 0x02
+#define KEYBOARD_CAPS_LOCK_ON 0x04
+
+/*-----------------------------------------------------
+ *  DeviceExtension
+ * --------------------------------------------------*/
+typedef struct _COMMAND_CONTEXT
+{
+       int NumInput;
+       int CurInput;
+       UCHAR * Input;
+       int NumOutput;
+       int CurOutput;
+       UCHAR * Output;
+       NTSTATUS Status;
+
+       BOOLEAN GotAck;
+       KEVENT Event;
+
+       PVOID DevExt;
+} COMMAND_CONTEXT, *PCOMMAND_CONTEXT;
+
+typedef enum _MOUSE_TIMEOUT_STATE
+{
+       NoChange,
+       TimeoutStart,
+       TimeoutCancel
+} MOUSE_TIMEOUT_STATE, *PMOUSE_TIMEOUT_STATE;
+
+/* TODO: part of this should be in the _ATTRIBUTES structs instead */
+typedef struct _I8042_SETTINGS
+{
+       DWORD Headless;               /* done */
+       DWORD CrashScroll;
+       DWORD CrashSysRq;             /* done */
+       DWORD ReportResetErrors;
+       DWORD PollStatusIterations;   /* done */
+       DWORD ResendIterations;       /* done */
+       DWORD PollingIterations;
+       DWORD PollingIterationsMaximum;
+       DWORD OverrideKeyboardType;
+       DWORD OverrideKeyboardSubtype;
+       DWORD MouseResendStallTime;
+       DWORD MouseSynchIn100ns;
+       DWORD MouseResolution;
+       DWORD NumberOfButtons;
+       DWORD EnableWheelDetection;
+} I8042_SETTINGS, *PI8042_SETTINGS;
+
+typedef enum _I8042_MOUSE_TYPE
+{
+       GenericPS2,
+       Intellimouse,
+       IntellimouseExplorer,
+       Ps2pp
+} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
+
+typedef enum _I8042_DEVICE_TYPE
+{
+       Keyboard,
+       Mouse
+} I8042_DEVICE_TYPE, *PI8042_DEVICE_TYPE;
+
+typedef struct _I8042_DEVICE
+{
+       LIST_ENTRY ListEntry;
+       PDEVICE_OBJECT Pdo;
+} I8042_DEVICE, *PI8042_DEVICE;
+
+typedef struct _DEVICE_EXTENSION
+{
+       PDEVICE_OBJECT KeyboardObject;
+       PDEVICE_OBJECT MouseObject;
+
+       CONNECT_DATA KeyboardData;
+       CONNECT_DATA MouseData;
+
+       BOOLEAN KeyboardExists;
+       BOOLEAN KeyboardIsAT;
+       BOOLEAN MouseExists;
+       
+       BOOLEAN KeyboardClaimed;
+       BOOLEAN MouseClaimed;
+
+       ULONG BusNumber;
+       LIST_ENTRY BusDevices;
+
+       INTERNAL_I8042_START_INFORMATION KeyboardStartInformation;
+       INTERNAL_I8042_START_INFORMATION MouseStartInformation;
+
+       INTERNAL_I8042_HOOK_KEYBOARD KeyboardHook;
+       INTERNAL_I8042_HOOK_MOUSE MouseHook;
+
+       PKINTERRUPT KeyboardInterruptObject;
+       PKINTERRUPT MouseInterruptObject;
+       PKINTERRUPT HighestDIRQLInterrupt;
+       KSPIN_LOCK SpinLock;
+       KDPC DpcKbd;
+       KDPC DpcMouse;
+
+       KTIMER TimerMouseTimeout;
+       KDPC DpcMouseTimeout;
+       MOUSE_TIMEOUT_STATE MouseTimeoutState;
+       BOOLEAN MouseTimeoutActive;
+
+       KEYBOARD_ATTRIBUTES KeyboardAttributes;
+       KEYBOARD_INDICATOR_PARAMETERS KeyboardIndicators;
+       KEYBOARD_TYPEMATIC_PARAMETERS KeyboardTypematic;
+
+       BOOLEAN WantAck;
+       BOOLEAN WantOutput;
+       BOOLEAN SignalEvent;
+
+       KEYBOARD_SCAN_STATE KeyboardScanState;
+       BOOLEAN KeyComplete;
+       KEYBOARD_INPUT_DATA *KeyboardBuffer;
+       ULONG KeysInBuffer;
+
+       MOUSE_ATTRIBUTES MouseAttributes;
+
+       MOUSE_STATE MouseState;
+       BOOLEAN MouseComplete;
+       MOUSE_RESET_SUBSTATE MouseResetState;
+       MOUSE_INPUT_DATA *MouseBuffer;
+       ULONG MouseInBuffer;
+       USHORT MouseButtonState;
+
+       UCHAR MouseLogiBuffer[3];
+       UCHAR MouseLogitechID;
+       I8042_MOUSE_TYPE MouseType;
+
+       OUTPUT_PACKET Packet;
+       UINT PacketResends;
+       BOOLEAN PacketComplete;
+       NTSTATUS PacketResult;
+       UCHAR PacketBuffer[16];
+       UCHAR PacketPort;
+
+       PIRP CurrentIrp;
+       PDEVICE_OBJECT CurrentIrpDevice;
+
+       /* registry config values */
+       I8042_SETTINGS Settings;
+
+       /* Debugger stuff */
+       BOOLEAN TabPressed;
+       ULONG DebugKey;
+       PIO_WORKITEM DebugWorkItem;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+typedef struct _FDO_DEVICE_EXTENSION
+{
+       PDEVICE_EXTENSION PortDevExt;
+       I8042_DEVICE_TYPE Type;
+       PDEVICE_OBJECT DeviceObject;
+
+       LIST_ENTRY BusDevices;
+} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
+
+typedef struct _I8042_HOOK_WORKITEM
+{
+       PIO_WORKITEM WorkItem;
+       PDEVICE_OBJECT Target;
+       PIRP Irp;
+} I8042_HOOK_WORKITEM, *PI8042_HOOK_WORKITEM;
+
+/*
+ * Some defines
+ */
+#define TAG_I8042 TAG('8', '0', '4', '2')
+
+#define KBD_WRAP_MASK      0x1F
+
+#define disable()          __asm__("cli\n\t")
+#define enable()           __asm__("sti\n\t")
+
+#define ALT_PRESSED                    (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
+#define CTRL_PRESSED                   (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
+
+
+/*
+ * Keyboard controller ports
+ */
+
+#define I8042_DATA_PORT      0x60
+#define I8042_CTRL_PORT      0x64
+
+
+/*
+ * Controller commands
+ */
+
+#define KBD_READ_MODE      0x20
+#define KBD_WRITE_MODE     0x60
+#define KBD_SELF_TEST      0xAA
+#define KBD_LINE_TEST      0xAB
+#define KBD_CTRL_ENABLE    0xAE
+
+#define MOUSE_LINE_TEST    0xA9
+#define MOUSE_CTRL_ENABLE  0xA8
+
+#define KBD_READ_OUTPUT_PORT 0xD0
+#define KBD_WRITE_OUTPUT_PORT 0xD1
+
+/*
+ * Keyboard commands
+ */
+
+#define KBD_SET_LEDS       0xED
+#define KBD_GET_ID         0xF2
+#define KBD_ENABLE         0xF4
+#define KBD_DISABLE        0xF5
+#define KBD_RESET          0xFF
+
+
+/*
+ * Keyboard responces
+ */
+
+#define KBD_BATCC          0xAA
+#define KBD_ACK            0xFA
+#define KBD_NACK           0xFC
+#define KBD_RESEND         0xFE
+
+/*
+ * Controller status register bits
+ */
+
+#define KBD_OBF            0x01
+#define KBD_IBF            0x02
+#define KBD_AUX            0x10
+#define KBD_GTO            0x40
+#define KBD_PERR           0x80
+
+
+/*
+ * LED bits
+ */
+
+#define KBD_LED_SCROLL     0x01
+#define KBD_LED_NUM        0x02
+#define KBD_LED_CAPS       0x04
+
+/*
+ * Mouse responses
+ */
+#define MOUSE_ACK          0xFA
+#define MOUSE_ERROR        0xFC
+#define MOUSE_NACK         0xFE
+
+/* i8042prt.c */
+NTSTATUS I8042ReadData(BYTE *Data);
+
+NTSTATUS I8042ReadStatus(BYTE *Status);
+
+NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, BYTE *Data);
+
+VOID I8042Flush();
+
+VOID STDCALL I8042IsrWritePort(PDEVICE_EXTENSION DevExt,
+                               UCHAR Value,
+                               UCHAR SelectCmd);
+
+NTSTATUS STDCALL I8042SynchWritePort(PDEVICE_EXTENSION DevExt,
+                                     UCHAR Port,
+                                     UCHAR Value,
+                                     BOOLEAN WaitForAck);
+
+NTSTATUS STDCALL I8042StartPacket(PDEVICE_EXTENSION DevExt,
+                                  PDEVICE_OBJECT Device,
+                                  PUCHAR Bytes,
+                                  ULONG ByteCount,
+                                  PIRP Irp);
+
+BOOLEAN STDCALL I8042PacketIsr(PDEVICE_EXTENSION DevExt,
+                            UCHAR Output);
+
+VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt);
+
+VOID STDCALL I8042SendHookWorkItem(PDEVICE_OBJECT DeviceObject,
+                                   PVOID Context);
+
+BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, int addr, BYTE data);
+
+/* keyboard.c */
+VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
+                                  UCHAR Value);
+
+NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
+                                        UCHAR Value,
+                                        BOOLEAN WaitForAck);
+
+BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
+                                         VOID * Context);
+
+VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
+                                PVOID DeferredContext,
+                                PVOID SystemArgument1,
+                                PVOID SystemArgument2);
+
+BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject,
+                                               PIRP Irp);
+
+BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt);
+
+BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt);
+
+BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt);
+
+/* registry.c */
+VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
+                               PDEVICE_EXTENSION DevExt);
+
+/* mouse.c */
+VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
+                                  PVOID DeferredContext,
+                                  PVOID SystemArgument1,
+                                  PVOID SystemArgument2);
+
+VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
+                                         PVOID DeferredContext,
+                                         PVOID SystemArgument1,
+                                         PVOID SystemArgument2);
+
+BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
+                                           VOID *Context);
+
+NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject,
+                                                 PIRP Irp);
+
+VOID STDCALL I8042QueueMousePacket(PVOID Context);
+
+VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
+                                     USHORT Mask);
+
+VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
+                              BYTE Output);
+
+BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt);
+BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt);
+
+/* ps2pp.c */
+VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, BYTE Input);
+
+#endif // _KEYBOARD_H_
diff --git a/reactos/drivers/input/i8042prt/i8042prt.rc b/reactos/drivers/input/i8042prt/i8042prt.rc
new file mode 100644 (file)
index 0000000..6c44176
--- /dev/null
@@ -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 <reactos/version.rc>
diff --git a/reactos/drivers/input/i8042prt/keyboard.c b/reactos/drivers/input/i8042prt/keyboard.c
new file mode 100644 (file)
index 0000000..e81a6a1
--- /dev/null
@@ -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 <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* GLOBALS *******************************************************************/
+
+static BYTE TypematicTable[] = {
+       0x00, 0x00, 0x00, 0x05, 0x08, 0x0B, 0x0D, 0x0F, 0x10, 0x12, /*  0-9 */
+       0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1A, /* 10-19 */
+       0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E };
+
+typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION {
+       USHORT NumberOfIndicatorKeys;
+       INDICATOR_LIST IndicatorList[3];
+} LOCAL_KEYBOARD_INDICATOR_TRANSLATION, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION;
+
+static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, {
+       {0x3A, KEYBOARD_CAPS_LOCK_ON},
+       {0x45, KEYBOARD_NUM_LOCK_ON},
+       {0x46, KEYBOARD_SCROLL_LOCK_ON}}};
+
+static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
+                                       PVOID Context);
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * These functions are callbacks for filter driver custom interrupt
+ * service routines.
+ */
+VOID STDCALL I8042IsrWritePortKbd(PVOID Context,
+                                         UCHAR Value)
+{
+       I8042IsrWritePort(Context, Value, 0);
+}
+
+static VOID STDCALL I8042QueueKeyboardPacket(PVOID Context)
+{
+       PDEVICE_OBJECT DeviceObject = Context;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       DevExt->KeyComplete = TRUE;
+       DevExt->KeysInBuffer++;
+       if (DevExt->KeysInBuffer >
+                        DevExt->KeyboardAttributes.InputDataQueueLength) {
+               DPRINT1("Keyboard buffer overflow\n");
+               DevExt->KeysInBuffer--;
+       }
+
+       DPRINT("Irq completes key\n");
+       KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+}
+
+/*
+ * These functions are callbacks for filter driver custom
+ * initialization routines.
+ */
+NTSTATUS STDCALL I8042SynchWritePortKbd(PVOID Context,
+                                        UCHAR Value,
+                                        BOOLEAN WaitForAck)
+{
+       return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
+                                  0,
+                                  Value, 
+                                  WaitForAck);
+}
+
+BOOLEAN STDCALL I8042InterruptServiceKbd(struct _KINTERRUPT *Interrupt,
+                                             VOID * Context)
+{
+       BYTE Output;
+       BYTE PortStatus;
+       NTSTATUS Status;
+       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
+       BOOLEAN HookContinue = FALSE, HookReturn;
+       UINT Iterations = 0;
+
+       KEYBOARD_INPUT_DATA *InputData =
+                                DevExt->KeyboardBuffer + DevExt->KeysInBuffer;
+
+       do {
+               Status = I8042ReadStatus(&PortStatus);
+               DPRINT("PortStatus: %x\n", PortStatus);
+               Status = I8042ReadData(&Output);
+               Iterations++;
+               if (STATUS_SUCCESS == Status)
+                       break;
+               KeStallExecutionProcessor(1);
+       } while (Iterations < DevExt->Settings.PollStatusIterations);
+
+       if (STATUS_SUCCESS != Status) {
+               DPRINT1("Spurious I8042 interrupt\n");
+               return FALSE;
+       }
+
+       DPRINT("Got: %x\n", Output);
+
+       if (DevExt->KeyboardHook.IsrRoutine) {
+               HookReturn = DevExt->KeyboardHook.IsrRoutine(
+                                             DevExt->KeyboardHook.Context,
+                                            InputData,
+                                            &DevExt->Packet,
+                                            PortStatus,
+                                            &Output,
+                                            &HookContinue,
+                                            &DevExt->KeyboardScanState);
+
+               if (!HookContinue)
+                       return HookReturn;
+       }
+
+       if (I8042PacketIsr(DevExt, Output)) {
+               if (DevExt->PacketComplete) {
+                       DPRINT("Packet complete\n");
+                       KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+               }
+               DPRINT("Irq eaten by packet\n");
+               return TRUE;
+       }
+
+       DPRINT("Irq is keyboard input\n");
+
+       if (Normal == DevExt->KeyboardScanState) {
+               switch (Output) {
+               case 0xe0:
+                       DevExt->KeyboardScanState = GotE0;
+                       return TRUE;
+               case 0xe1:
+                       DevExt->KeyboardScanState = GotE1;
+                       return TRUE;
+               default:
+                       ;/* continue */
+               }
+       }
+
+       InputData->Flags = 0;
+
+       switch (DevExt->KeyboardScanState) {
+       case GotE0:
+               InputData->Flags |= KEY_E0;
+               break;
+       case GotE1:
+               InputData->Flags |= KEY_E1;
+               break;
+       default:
+               ;
+       }
+       DevExt->KeyboardScanState = Normal;
+
+       if (Output & 0x80)
+               InputData->Flags |= KEY_BREAK;
+       else
+               InputData->Flags |= KEY_MAKE;
+       
+       InputData->MakeCode = Output & 0x7f;
+
+       I8042QueueKeyboardPacket(DevExt->KeyboardObject);
+
+       return TRUE;
+}
+       
+VOID STDCALL I8042DpcRoutineKbd(PKDPC Dpc,
+                                PVOID DeferredContext,
+                                PVOID SystemArgument1,
+                                PVOID SystemArgument2)
+{
+       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+       ULONG KeysTransferred = 0;
+       ULONG KeysInBufferCopy;
+       KIRQL Irql;
+
+       I8042PacketDpc(DevExt);
+
+       if (!DevExt->KeyComplete)
+               return;
+
+       /* We got the interrupt as it was being enabled, too bad */
+       if (!DevExt->HighestDIRQLInterrupt)
+               return;
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+       DevExt->KeyComplete = FALSE;
+       KeysInBufferCopy = DevExt->KeysInBuffer;
+
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+
+       /* Test for TAB (debugging) */
+       if (DevExt->Settings.CrashSysRq) {
+               PKEYBOARD_INPUT_DATA InputData = DevExt->KeyboardBuffer + 
+                                                         KeysInBufferCopy - 1;
+               if (InputData->MakeCode == 0x0F) {
+                       DPRINT("Tab!\n");
+                       DevExt->TabPressed = !(InputData->Flags & KEY_BREAK);
+               } else if (DevExt->TabPressed) {
+                       DPRINT ("Queueing work item %x\n", DevExt->DebugWorkItem);
+                       DevExt->DebugKey = InputData->MakeCode;
+                       DevExt->TabPressed = FALSE;
+
+                       IoQueueWorkItem(DevExt->DebugWorkItem,
+                                       &(I8042DebugWorkItem),
+                                       DelayedWorkQueue,
+                                       DevExt);
+               }
+       }
+
+       DPRINT ("Send a key\n");
+
+       if (!DevExt->KeyboardData.ClassService)
+               return;
+
+       ((KEYBOARD_CLASS_SERVICE_CALLBACK) DevExt->KeyboardData.ClassService)(
+                                DevExt->KeyboardData.ClassDeviceObject,
+                                DevExt->KeyboardBuffer,
+                                DevExt->KeyboardBuffer + KeysInBufferCopy,
+                                &KeysTransferred);
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+       DevExt->KeysInBuffer -= KeysTransferred;
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+}
+
+/* You have to send the rate/delay in a somewhat awkward format */
+static USHORT I8042GetTypematicByte(USHORT Rate, USHORT Delay)
+{
+       USHORT ret;
+       
+       if (Rate < 3) {
+               ret = 0x0;
+       } else if (Rate > 26) {
+               ret = 0x1F;
+       } else {
+               ret = TypematicTable[Rate];
+       }
+
+       if (Delay < 375) {
+               ;
+       } else if (Delay < 625) {
+               ret |= 0x20;
+       } else if (Delay < 875) {
+               ret |= 0x40;
+       } else {
+               ret |= 0x60;
+       }
+       return ret;
+}
+/*
+ * Process the keyboard internal device requests
+ * returns FALSE if it doesn't understand the
+ * call so someone else can handle it.
+ */
+BOOLEAN STDCALL I8042StartIoKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       PIO_STACK_LOCATION Stk;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       Stk = IoGetCurrentIrpStackLocation(Irp);
+    
+       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+       case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
+               I8042StartPacket(
+                            DevExt,
+                            DeviceObject,
+                            Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+                            Stk->Parameters.DeviceIoControl.InputBufferLength,
+                            Irp);
+               break;
+
+       case IOCTL_KEYBOARD_SET_INDICATORS:
+               DevExt->PacketBuffer[0] = 0xED;
+               DevExt->PacketBuffer[1] = 0;
+               if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
+                       DevExt->PacketBuffer[1] |= 0x04;
+
+               if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
+                       DevExt->PacketBuffer[1] |= 0x02;
+
+               if (DevExt->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
+                       DevExt->PacketBuffer[1] |= 0x01;
+
+               I8042StartPacket(DevExt,
+                                DeviceObject,
+                                DevExt->PacketBuffer,
+                                2,
+                                Irp);
+               break;
+       case IOCTL_KEYBOARD_SET_TYPEMATIC:
+               DevExt->PacketBuffer[0] = 0xF3;
+               DevExt->PacketBuffer[1] = I8042GetTypematicByte(
+                                        DevExt->KeyboardTypematic.Rate,
+                                        DevExt->KeyboardTypematic.Delay);
+
+               I8042StartPacket(DevExt,
+                                DeviceObject,
+                                DevExt->PacketBuffer,
+                                2,
+                                Irp);
+               break;
+       default:
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*
+ * Runs the keyboard IOCTL_INTERNAL dispatch.
+ * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
+ * so someone else can have a try at it.
+ */
+NTSTATUS STDCALL I8042InternalDeviceControlKbd(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       PIO_STACK_LOCATION Stk;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       DPRINT("InternalDeviceControl\n");
+
+       Irp->IoStatus.Information = 0;
+       Stk = IoGetCurrentIrpStackLocation(Irp);
+    
+       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+
+       case IOCTL_INTERNAL_KEYBOARD_CONNECT:
+               DPRINT("IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 
+                                                     sizeof(CONNECT_DATA)) {
+                       DPRINT1("Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                       goto intcontfailure;
+               }
+
+               if (!DevExt->KeyboardExists) {
+                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+                       goto intcontfailure;
+               }
+
+               if (DevExt->KeyboardClaimed) {
+                       DPRINT1("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
+                              "Keyboard is already claimed\n");
+                       Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
+                       goto intcontfailure;
+               }
+
+               memcpy(&DevExt->KeyboardData,
+                      Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+                      sizeof(CONNECT_DATA));
+               DevExt->KeyboardHook.IsrWritePort = I8042IsrWritePortKbd;
+               DevExt->KeyboardHook.QueueKeyboardPacket = 
+                                                   I8042QueueKeyboardPacket;
+               DevExt->KeyboardHook.CallContext = DevExt;
+
+               {
+                       PIO_WORKITEM WorkItem;
+                       PI8042_HOOK_WORKITEM WorkItemData;
+
+                       WorkItem = IoAllocateWorkItem(DeviceObject);
+                       if (!WorkItem) {
+                               DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
+                                       "Can't allocate work item\n");
+                               Irp->IoStatus.Status = 
+                                             STATUS_INSUFFICIENT_RESOURCES;
+                               goto intcontfailure;
+                       }
+
+                       WorkItemData = ExAllocatePoolWithTag(
+                                                  NonPagedPool,
+                                                  sizeof(I8042_HOOK_WORKITEM),
+                                                  TAG_I8042);
+                       if (!WorkItemData) {
+                               DPRINT ("IOCTL_INTERNAL_KEYBOARD_CONNECT: "
+                                       "Can't allocate work item data\n");
+                               Irp->IoStatus.Status = 
+                                             STATUS_INSUFFICIENT_RESOURCES;
+                               IoFreeWorkItem(WorkItem);
+                               goto intcontfailure;
+                       }
+                       WorkItemData->WorkItem = WorkItem;
+                       WorkItemData->Target = 
+                                       DevExt->KeyboardData.ClassDeviceObject;
+                       WorkItemData->Irp = Irp;
+
+                       IoMarkIrpPending(Irp);
+                       IoQueueWorkItem(WorkItem,
+                                       I8042SendHookWorkItem,
+                                       DelayedWorkQueue,
+                                       WorkItemData);
+
+                       Irp->IoStatus.Status = STATUS_PENDING;
+               }
+
+               break;
+       case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER:
+               DPRINT("IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
+                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                       goto intcontfailure;
+               }
+               if (!DevExt->KeyboardInterruptObject) {
+                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+                       goto intcontfailure;
+               }
+
+               IoMarkIrpPending(Irp);
+               IoStartPacket(DeviceObject, Irp, NULL, NULL);
+               Irp->IoStatus.Status = STATUS_PENDING;
+
+               break;
+       case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
+               DPRINT("IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
+               if (Stk->Parameters.DeviceIoControl.OutputBufferLength < 
+                                                sizeof(KEYBOARD_ATTRIBUTES)) {
+                       DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+               memcpy(Irp->AssociatedIrp.SystemBuffer,
+                      &DevExt->KeyboardAttributes,
+                      sizeof(KEYBOARD_ATTRIBUTES));
+
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               break;
+       case IOCTL_KEYBOARD_QUERY_INDICATORS:
+               DPRINT("IOCTL_KEYBOARD_QUERY_INDICATORS\n");
+               if (Stk->Parameters.DeviceIoControl.OutputBufferLength < 
+                                      sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
+                       DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+               memcpy(Irp->AssociatedIrp.SystemBuffer,
+                      &DevExt->KeyboardIndicators,
+                      sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               break;
+       case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
+               DPRINT("IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
+               if (Stk->Parameters.DeviceIoControl.OutputBufferLength < 
+                                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
+                       DPRINT("Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+               memcpy(Irp->AssociatedIrp.SystemBuffer,
+                      &DevExt->KeyboardTypematic,
+                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
+
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               break;
+       case IOCTL_KEYBOARD_SET_INDICATORS:
+               DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 
+                                      sizeof(KEYBOARD_INDICATOR_PARAMETERS)) {
+                       DPRINT("Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+
+               memcpy(&DevExt->KeyboardIndicators,
+                      Irp->AssociatedIrp.SystemBuffer,
+                      sizeof(KEYBOARD_INDICATOR_PARAMETERS));
+
+               DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
+
+               IoMarkIrpPending(Irp);
+               IoStartPacket(DeviceObject, Irp, NULL, NULL);
+               Irp->IoStatus.Status = STATUS_PENDING;
+
+               break;
+       case IOCTL_KEYBOARD_SET_TYPEMATIC:
+               DPRINT("IOCTL_KEYBOARD_SET_TYPEMATIC\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 
+                                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS)) {
+                       DPRINT("Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+
+               memcpy(&DevExt->KeyboardTypematic,
+                      Irp->AssociatedIrp.SystemBuffer,
+                      sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
+
+               IoMarkIrpPending(Irp);
+               IoStartPacket(DeviceObject, Irp, NULL, NULL);
+               Irp->IoStatus.Status = STATUS_PENDING;
+
+               break;
+       case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+               /* We should check the UnitID, but it's kind of pointless as
+                * all keyboards are supposed to have the same one
+                */
+               if (Stk->Parameters.DeviceIoControl.OutputBufferLength < 
+                                sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) {
+                       DPRINT("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
+                              "invalid buffer size (expected)\n");
+                       /* It's to query the buffer size */
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+               Irp->IoStatus.Information =
+                                sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
+
+               memcpy(Irp->AssociatedIrp.SystemBuffer,
+                      &IndicatorTranslation,
+                      sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
+
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               break;
+       case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
+               /* Nothing to do here */
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               break;
+       default:
+               Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+               break;
+       }
+
+intcontfailure:
+       return Irp->IoStatus.Status;
+}
+
+BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
+{
+       DPRINT("Enabling keyboard\n");
+       if (STATUS_SUCCESS != I8042SynchWritePort(DevExt,
+                                                 0,
+                                                 KBD_ENABLE,
+                                                 TRUE)) {
+               DPRINT("Can't enable keyboard\n");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+BOOLEAN STDCALL I8042KeyboardEnableInterrupt(PDEVICE_EXTENSION DevExt)
+{
+       UCHAR Value;
+       NTSTATUS Status;
+
+       DPRINT("Enabling keyboard interrupt\n");
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+               DPRINT1("Can't read i8042 mode\n");
+               return FALSE;
+       }
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1("No response after read i8042 mode\n");
+               return FALSE;
+       }
+
+       Value &= ~(0x10); // don't disable keyboard
+       Value |= 0x01;    // enable keyboard interrupts
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+               DPRINT1("Can't set i8042 mode\n");
+               return FALSE;
+       }
+
+       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+               DPRINT1("Can't send i8042 mode\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+BOOLEAN STDCALL I8042DetectKeyboard(PDEVICE_EXTENSION DevExt)
+{
+       NTSTATUS Status;
+       UCHAR Value;
+       UINT RetryCount = 10;
+
+       DPRINT("Detecting keyboard\n");
+
+       do {
+               Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
+       } while (STATUS_TIMEOUT == Status && RetryCount--);
+
+       if (Status != STATUS_SUCCESS) {
+               DPRINT("Can't write GET_ID (%x)\n", Status);
+               return FALSE;
+       }
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1("No response after GET_ID\n");
+               /* Could be an AT keyboard */
+               DevExt->KeyboardIsAT = TRUE;
+               goto detectsetleds;
+       }
+       DevExt->KeyboardIsAT = FALSE;
+
+       if (Value != 0xAB && Value != 0xAC) {
+               DPRINT("Bad ID: %x\n", Value);
+               /* This is certainly not a keyboard */
+               return FALSE;
+       }
+
+       DPRINT("Keyboard ID: %x", Value);
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT("Partial ID\n");
+               return FALSE;
+       }
+
+       DPRINT ("%x\n", Value);
+
+detectsetleds:
+       Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT("Can't write SET_LEDS (%x)\n", Status);
+               return FALSE;
+       }
+       Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT("Can't finish SET_LEDS (%x)\n", Status);
+               return FALSE;
+       }
+
+       // Turn on translation
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+               DPRINT1("Can't read i8042 mode\n");
+               return FALSE;
+       }
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1("No response after read i8042 mode\n");
+               return FALSE;
+       }
+
+       Value |= 0x40;    // enable keyboard translation
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+               DPRINT1("Can't set i8042 mode\n");
+               return FALSE;
+       }
+
+       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+               DPRINT1("Can't send i8042 mode\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/* debug stuff */
+VOID STDCALL
+KdpServiceDispatcher(ULONG Code, PVOID Context1, PVOID Context2); 
+
+static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
+                                       PVOID Context)
+{
+       ULONG Key;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       Key = InterlockedExchange(&DevExt->DebugKey, 0);
+       DPRINT("Debug key: %x\n", Key);
+
+       if (!Key)
+               return;
+
+       KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
+}
diff --git a/reactos/drivers/input/i8042prt/makefile b/reactos/drivers/input/i8042prt/makefile
new file mode 100644 (file)
index 0000000..43537fd
--- /dev/null
@@ -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 (file)
index 0000000..b044b0f
--- /dev/null
@@ -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 <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/*
+ * These functions are callbacks for filter driver custom interrupt
+ * service routines.
+ */
+VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
+                                    UCHAR Value)
+{
+       I8042IsrWritePort(Context, Value, 0xD4);
+}
+
+NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
+                                         UCHAR Value,
+                                         BOOLEAN WaitForAck)
+{
+       return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
+                                  0xD4,
+                                  Value,
+                                  WaitForAck);
+}
+
+/*
+ * Call the customization hook. The Ret2 parameter is about wether
+ * we should go on with the interrupt. The return value is what
+ * we should return (indicating to the system wether someone else
+ * should try to handle the interrupt)
+ */
+BOOLEAN STDCALL I8042MouseCallIsrHook(PDEVICE_EXTENSION DevExt,
+                                      UCHAR Status,
+                                      PUCHAR Input,
+                                     PBOOLEAN ToReturn)
+{
+       BOOLEAN HookReturn, HookContinue;
+
+       HookContinue = FALSE;
+
+       if (DevExt->MouseHook.IsrRoutine) {
+               HookReturn = DevExt->MouseHook.IsrRoutine(
+                                  DevExt->MouseHook.Context,
+                                  DevExt->MouseBuffer + DevExt->MouseInBuffer,
+                                  &DevExt->Packet,
+                                  Status,
+                                  Input,
+                                  &HookContinue,
+                                  &DevExt->MouseState,
+                                  &DevExt->MouseResetState);
+
+               if (!HookContinue) {
+                       *ToReturn = HookReturn;
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
+                                   UCHAR Status,
+                                   PUCHAR Value)
+{
+       BOOLEAN ToReturn;
+
+       if (I8042MouseCallIsrHook(DevExt, Status, Value, &ToReturn))
+               return ToReturn;
+
+       if (MouseResetting != DevExt->MouseState) {
+               return FALSE;
+       }
+       DevExt->MouseTimeoutState = TimeoutStart;
+
+       switch (DevExt->MouseResetState) {
+       case 1100: /* the first ack, drop it. */
+               DevExt->MouseResetState = ExpectingReset;
+               return TRUE;
+       /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok,
+        * FC00 if not.
+        */
+       case ExpectingReset:
+               if (0xAA == *Value) {
+                       DevExt->MouseResetState++;
+               } else {
+                       DevExt->MouseExists = FALSE;
+                       DevExt->MouseState = MouseIdle;
+                       DPRINT("Mouse returned bad reset reply: "
+                              "%x (expected aa)\n", *Value);
+               }
+               return TRUE;
+       case ExpectingResetId:
+               if (0x00 == *Value) {
+                       DevExt->MouseResetState++;
+                       DevExt->MouseType = GenericPS2;
+                       I8042IsrWritePortMouse(DevExt, 0xF2);
+               } else {
+                       DevExt->MouseExists = FALSE;
+                       DevExt->MouseState = MouseIdle;
+                       DPRINT1("Mouse returned bad reset reply part two: "
+                               "%x (expected 0)\n", Value);
+               }
+               return TRUE;
+       case ExpectingGetDeviceIdACK:
+               if (MOUSE_ACK == *Value) {
+                       DevExt->MouseResetState++;
+               } else if (MOUSE_NACK == *Value ||
+                          MOUSE_ERROR == *Value) {
+                       DevExt->MouseResetState++;
+                       /* Act as if 00 (normal mouse) was received */
+                       DPRINT("Mouse doesn't support 0xd2, "
+                              "(returns %x, expected %x), faking.\n",
+                              *Value, MOUSE_ACK);
+                       *Value = 0;
+                       I8042MouseResetIsr(DevExt, Status, Value);
+               }
+               return TRUE;
+       case ExpectingGetDeviceIdValue:
+               switch (*Value) {
+               case 0x02:
+                       DevExt->MouseAttributes.MouseIdentifier =
+                                                   BALLPOINT_I8042_HARDWARE;
+                       break;
+               case 0x03:
+               case 0x04:
+                       DevExt->MouseAttributes.MouseIdentifier =
+                                                   WHEELMOUSE_I8042_HARDWARE;
+                       break;
+               default:
+                       DevExt->MouseAttributes.MouseIdentifier =
+                                                   MOUSE_I8042_HARDWARE;
+               }
+               DevExt->MouseResetState++;
+               I8042IsrWritePortMouse(DevExt, 0xE8);
+               return TRUE;
+       case ExpectingSetResolutionDefaultACK:
+               DevExt->MouseResetState++;
+               I8042IsrWritePortMouse(DevExt, 0x00);
+               return TRUE;
+       case ExpectingSetResolutionDefaultValueACK:
+               DevExt->MouseResetState = ExpectingSetScaling1to1ACK;
+               I8042IsrWritePortMouse(DevExt, 0xE6);
+               return TRUE;
+       case ExpectingSetScaling1to1ACK:
+       case ExpectingSetScaling1to1ACK2:
+               DevExt->MouseResetState++;
+               I8042IsrWritePortMouse(DevExt, 0xE6);
+               return TRUE;
+       case ExpectingSetScaling1to1ACK3:
+               DevExt->MouseResetState++;
+               I8042IsrWritePortMouse(DevExt, 0xE9);
+               return TRUE;
+       case ExpectingReadMouseStatusACK:
+               DevExt->MouseResetState++;
+               return TRUE;
+       case ExpectingReadMouseStatusByte1:
+               DevExt->MouseLogiBuffer[0] = *Value;
+               DevExt->MouseResetState++;
+               return TRUE;
+       case ExpectingReadMouseStatusByte2:
+               DevExt->MouseLogiBuffer[1] = *Value;
+               DevExt->MouseResetState++;
+               return TRUE;
+       case ExpectingReadMouseStatusByte3:
+               DevExt->MouseLogiBuffer[2] = *Value;
+               /* Now MouseLogiBuffer is a set of info. If the second
+                * byte is 0, the mouse didn't understand the magic
+                * code. Otherwise, it it a Logitech and the second byte 
+                * is the number of buttons, bit 7 of the first byte tells 
+                * if it understands special E7 commands, the rest is an ID.
+                */
+               if (DevExt->MouseLogiBuffer[1]) {
+                       DevExt->MouseAttributes.NumberOfButtons =
+                                                DevExt->MouseLogiBuffer[1];
+                       /* For some reason the ID is the wrong way around */
+                       DevExt->MouseLogitechID = 
+                                 ((DevExt->MouseLogiBuffer[0] >> 4) & 0x07) |
+                                 ((DevExt->MouseLogiBuffer[0] << 3) & 0x78);
+                       DevExt->MouseType = Ps2pp;
+                       I8042IsrWritePortMouse(DevExt, 0xf3);
+                       DevExt->MouseResetState = ExpectingSetSamplingRateACK;
+                       return TRUE;
+                       /* TODO: Go through EnableWheel and Enable5Buttons */
+               }
+               DevExt->MouseResetState = EnableWheel;
+               I8042MouseResetIsr(DevExt, Status, Value);
+               return TRUE;
+       case EnableWheel:
+               I8042IsrWritePortMouse(DevExt, 0xf3);
+               DevExt->MouseResetState = 1001;
+               return TRUE;
+       case 1001:
+               I8042IsrWritePortMouse(DevExt, 0xc8);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1002:
+       case 1004:
+               I8042IsrWritePortMouse(DevExt, 0xf3);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1003:
+               I8042IsrWritePortMouse(DevExt, 0x64);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1005:
+               I8042IsrWritePortMouse(DevExt, 0x50);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1006:
+               I8042IsrWritePortMouse(DevExt, 0xf2);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1007:
+               /* Ignore ACK */
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1008:
+               /* Now if the value == 3, it's either an Intellimouse
+                * or Intellimouse Explorer. */
+               if (0x03 == *Value) {
+                       DevExt->MouseAttributes.NumberOfButtons = 3;
+                       DevExt->MouseAttributes.MouseIdentifier =
+                                                  WHEELMOUSE_I8042_HARDWARE;
+                       DevExt->MouseType = Intellimouse;
+                       DevExt->MouseResetState = Enable5Buttons;
+                       I8042MouseResetIsr(DevExt, Status, Value);
+                       return TRUE;
+               } /* Else, just set the default settings and be done */
+               I8042IsrWritePortMouse(DevExt, 0xf3);
+               DevExt->MouseResetState = ExpectingSetSamplingRateACK;
+               return TRUE;
+       case Enable5Buttons:
+               I8042IsrWritePortMouse(DevExt, 0xf3);
+               DevExt->MouseResetState = 1021;
+               return TRUE;
+       case 1022:
+       case 1024:
+               I8042IsrWritePortMouse(DevExt, 0xf3);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1021:
+       case 1023:
+               I8042IsrWritePortMouse(DevExt, 0xc8);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1025:
+               I8042IsrWritePortMouse(DevExt, 0x50);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1026:
+               I8042IsrWritePortMouse(DevExt, 0xf2);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case 1027:
+               if (0x04 == *Value) {
+                       DevExt->MouseAttributes.NumberOfButtons = 5;
+                       DevExt->MouseAttributes.MouseIdentifier =
+                                                  WHEELMOUSE_I8042_HARDWARE;
+                       DevExt->MouseType = IntellimouseExplorer;
+               }
+               I8042IsrWritePortMouse(DevExt, 0xf3);
+               DevExt->MouseResetState = ExpectingSetSamplingRateACK;
+               return TRUE;
+       case ExpectingSetSamplingRateACK:
+               I8042IsrWritePortMouse(DevExt,
+                                      DevExt->MouseAttributes.SampleRate);
+               DevExt->MouseResetState++;
+               return TRUE;
+       case ExpectingSetSamplingRateValueACK:
+               if (MOUSE_NACK == *Value) {
+                       I8042IsrWritePortMouse(DevExt, 0x3c);
+                       DevExt->MouseAttributes.SampleRate = 60;
+                       DevExt->MouseResetState = 1040;
+                       return TRUE;
+               }
+       case 1040:  /* Fallthrough */
+               I8042IsrWritePortMouse(DevExt, 0xe8);
+               DevExt->MouseResetState = ExpectingFinalResolutionACK;
+               return TRUE;
+       case ExpectingFinalResolutionACK:
+               I8042IsrWritePortMouse(DevExt, 0x03);
+               DevExt->MouseResetState = ExpectingFinalResolutionValueACK;
+               return TRUE;
+       case ExpectingFinalResolutionValueACK:
+               I8042IsrWritePortMouse(DevExt, 0xf4);
+               DevExt->MouseResetState = ExpectingEnableACK;
+               return TRUE;
+       case ExpectingEnableACK:
+               DevExt->MouseState = MouseIdle;
+               DevExt->MouseTimeoutState = TimeoutCancel;
+               DPRINT("Mouse type = %d\n", DevExt->MouseType);
+               return TRUE;
+       default:
+               if (DevExt->MouseResetState < 100 ||
+                   DevExt->MouseResetState > 999)
+                       DPRINT1("MouseResetState went out of range: %d\n",
+                                        DevExt->MouseResetState);
+               return FALSE;
+       }
+}
+
+/*
+ * Prepare for reading the next packet and queue the dpc for handling
+ * this one.
+ * 
+ * Context is the device object.
+ */
+VOID STDCALL I8042QueueMousePacket(PVOID Context)
+{
+       PDEVICE_OBJECT DeviceObject = Context;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       DevExt->MouseComplete = TRUE;
+       DevExt->MouseInBuffer++;
+       if (DevExt->MouseInBuffer >
+                        DevExt->MouseAttributes.InputDataQueueLength) {
+               DPRINT1("Mouse buffer overflow\n");
+               DevExt->MouseInBuffer--;
+       }
+
+       DPRINT("Irq completes mouse packet\n");
+       KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
+}
+
+/*
+ * Updates ButtonFlags according to RawButtons and a saved state;
+ * Only takes in account the bits that are set in Mask
+ */
+VOID STDCALL I8042MouseHandleButtons(PDEVICE_EXTENSION DevExt,
+                                     USHORT Mask)
+{
+       PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
+                                                DevExt->MouseInBuffer;
+       USHORT NewButtonData = MouseInput->RawButtons & Mask;
+       USHORT ButtonDiff = (NewButtonData ^ DevExt->MouseButtonState) & Mask;
+
+       /* Note that the defines are such:
+        * MOUSE_LEFT_BUTTON_DOWN 1
+        * MOUSE_LEFT_BUTTON_UP   2
+        */
+       MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) |
+                                  (((~(NewButtonData)) << 1) &
+                                                      (ButtonDiff << 1)) |
+                                  (MouseInput->RawButtons & 0xfc00);
+
+       DPRINT("Left raw/up/down: %d/%d/%d\n", MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
+                       MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
+                       MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
+
+       DevExt->MouseButtonState = (DevExt->MouseButtonState & ~Mask) |
+                                  (NewButtonData & Mask);
+}
+
+VOID STDCALL I8042MouseHandle(PDEVICE_EXTENSION DevExt,
+                              BYTE Output)
+{
+       PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
+                                                DevExt->MouseInBuffer;
+       CHAR Scroll;
+
+       switch (DevExt->MouseState) {
+       case MouseIdle:
+               /* This bit should be 1, if not drop the packet, we
+                * might be lucky and get in sync again
+                */
+               if (!(Output & 8)) {
+                       DPRINT1("Bad input, dropping..\n");
+                       return;
+               }
+
+               MouseInput->Buttons = 0;
+               MouseInput->RawButtons = 0;
+               MouseInput->Flags = MOUSE_MOVE_RELATIVE;
+
+               /* Note how we ignore the overflow bits, like Windows
+                * is said to do. There's no reasonable thing to do
+                * anyway.
+                */
+
+               if (Output & 16)
+                       MouseInput->LastX = 1;
+               else
+                       MouseInput->LastX = 0;
+
+               if (Output & 32)
+                       MouseInput->LastY = 1;
+               else
+                       MouseInput->LastY = 0;
+
+               if (Output & 1) {
+                       MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN;
+               }
+
+               if (Output & 2) {
+                       MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN;
+               }
+
+               if (Output & 4) {
+                       MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN;
+               }
+               DevExt->MouseState = XMovement;
+               break;
+       case XMovement:
+               if (MouseInput->LastX)
+                       MouseInput->LastX = (LONG) Output - 256;
+               else
+                       MouseInput->LastX = Output;
+
+               DevExt->MouseState = YMovement;
+               break;
+       case YMovement:
+               if (MouseInput->LastY)
+                       MouseInput->LastY = (LONG)Output - 256;
+               else
+                       MouseInput->LastY = (LONG)Output;
+
+               /* Windows wants it the other way around */
+               MouseInput->LastY = -MouseInput->LastY;
+
+               if (DevExt->MouseType == GenericPS2 ||
+                   DevExt->MouseType == Ps2pp) {
+                       I8042MouseHandleButtons(DevExt,
+                                               MOUSE_LEFT_BUTTON_DOWN |
+                                                  MOUSE_RIGHT_BUTTON_DOWN |
+                                                  MOUSE_MIDDLE_BUTTON_DOWN);
+                       I8042QueueMousePacket(
+                                       DevExt->MouseObject);
+                       DevExt->MouseState = MouseIdle;
+               } else {
+                       DevExt->MouseState = ZMovement;
+               }
+               break;
+       case ZMovement:
+               Scroll = Output & 0x0f;
+               if (Scroll & 8)
+                       Scroll |= 0xf0;
+
+               if (Scroll) {
+                       MouseInput->RawButtons |= MOUSE_WHEEL;
+                       MouseInput->ButtonData = (USHORT) Scroll;
+               }
+
+               if (DevExt->MouseType == IntellimouseExplorer) {
+                       if (Output & 16)
+                               MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+
+                       if (Output & 32)
+                               MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+               }
+               I8042MouseHandleButtons(DevExt, MOUSE_LEFT_BUTTON_DOWN |
+                                               MOUSE_RIGHT_BUTTON_DOWN |
+                                               MOUSE_MIDDLE_BUTTON_DOWN |
+                                               MOUSE_BUTTON_4_DOWN |
+                                               MOUSE_BUTTON_5_DOWN);
+               I8042QueueMousePacket(DevExt->MouseObject);
+               DevExt->MouseState = MouseIdle;
+               break;
+       default:
+               DPRINT1("Unexpected state!\n");
+       }
+}
+
+BOOLEAN STDCALL I8042InterruptServiceMouse(struct _KINTERRUPT *Interrupt,
+                                           VOID *Context)
+{
+       BYTE Output, PortStatus;
+       NTSTATUS Status;
+       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
+       UINT Iterations = 0;
+
+       do {
+               Status = I8042ReadStatus(&PortStatus);
+               Status = I8042ReadData(&Output);
+               Iterations++;
+               if (STATUS_SUCCESS == Status)
+                       break;
+               KeStallExecutionProcessor(1);
+       } while (Iterations < DevExt->Settings.PollStatusIterations);
+
+       if (STATUS_SUCCESS != Status) {
+               DPRINT1("Spurious I8042 mouse interrupt\n");
+               return FALSE;
+       }
+
+       DPRINT("Got: %x\n", Output);
+
+       if (I8042PacketIsr(DevExt, Output)) {
+               if (DevExt->PacketComplete) {
+                       DPRINT("Packet complete\n");
+                       KeInsertQueueDpc(&DevExt->DpcKbd, DevExt, NULL);
+               }
+               DPRINT("Irq eaten by packet\n");
+               return TRUE;
+       }
+
+       if (I8042MouseResetIsr(DevExt, PortStatus, &Output)) {
+               DPRINT("Handled by ResetIsr or hooked Isr\n");
+               if (NoChange != DevExt->MouseTimeoutState) {
+                       KeInsertQueueDpc(&DevExt->DpcMouse, DevExt, NULL);
+               }
+               return TRUE;
+       }
+
+       if (DevExt->MouseType == Ps2pp)
+               I8042MouseHandlePs2pp(DevExt, Output);
+       else
+               I8042MouseHandle(DevExt, Output);
+
+       return TRUE;
+}
+
+VOID STDCALL I8042DpcRoutineMouse(PKDPC Dpc,
+                                  PVOID DeferredContext,
+                                  PVOID SystemArgument1,
+                                  PVOID SystemArgument2)
+{
+       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)SystemArgument1;
+       ULONG MouseTransferred = 0;
+       ULONG MouseInBufferCopy;
+       KIRQL Irql;
+       LARGE_INTEGER Timeout;
+
+       switch (DevExt->MouseTimeoutState) {
+       case TimeoutStart:
+               DevExt->MouseTimeoutState = NoChange;
+               if (DevExt->MouseTimeoutActive &&
+                   !KeCancelTimer(&DevExt->TimerMouseTimeout)) {
+                       /* The timer fired already, give up */
+                       DevExt->MouseTimeoutActive = FALSE;
+                       return;
+               }
+
+               Timeout.QuadPart = -15000000;
+                                   /* 1.5 seconds, should be enough */
+
+               KeSetTimer(&DevExt->TimerMouseTimeout,
+                          Timeout,
+                          &DevExt->DpcMouseTimeout);
+               DevExt->MouseTimeoutActive = TRUE;
+               return;
+       case TimeoutCancel:
+               DevExt->MouseTimeoutState = NoChange;
+               KeCancelTimer(&DevExt->TimerMouseTimeout);
+               DevExt->MouseTimeoutActive = FALSE;
+       default:
+               /* nothing, don't want a warning */ ;
+       }
+
+       /* Should be unlikely */
+       if (!DevExt->MouseComplete)
+               return;
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+       DevExt->MouseComplete = FALSE;
+       MouseInBufferCopy = DevExt->MouseInBuffer;
+
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+
+       DPRINT ("Send a mouse packet\n");
+
+       if (!DevExt->MouseData.ClassService)
+               return;
+
+       ((MOUSE_CLASS_SERVICE_CALLBACK) DevExt->MouseData.ClassService)(
+                                DevExt->MouseData.ClassDeviceObject,
+                                DevExt->MouseBuffer,
+                                DevExt->MouseBuffer + MouseInBufferCopy,
+                                &MouseTransferred);
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+       DevExt->MouseInBuffer -= MouseTransferred;
+       if (DevExt->MouseInBuffer)
+               RtlMoveMemory(DevExt->MouseBuffer,
+                             DevExt->MouseBuffer+MouseTransferred,
+                             DevExt->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
+
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+}
+
+/* This timer DPC will be called when the mouse reset times out.
+ * I'll just send the 'disable mouse port' command to the controller
+ * and say the mouse doesn't exist.
+ */
+VOID STDCALL I8042DpcRoutineMouseTimeout(PKDPC Dpc,
+                                         PVOID DeferredContext,
+                                         PVOID SystemArgument1,
+                                         PVOID SystemArgument2)
+{
+       PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeferredContext;
+       KIRQL Irql;
+
+       Irql = KeAcquireInterruptSpinLock(DevExt->HighestDIRQLInterrupt);
+
+       DPRINT1("Mouse initialization timeout! (substate %x) "
+                                               "Disabling mouse.\n",
+               DevExt->MouseResetState);
+
+       if (!I8042MouseDisable(DevExt)) {
+               DPRINT1("Failed to disable mouse.\n");
+       }
+
+       DevExt->MouseExists = FALSE;
+
+       KeReleaseInterruptSpinLock(DevExt->HighestDIRQLInterrupt, Irql);
+}
+
+/*
+ * Process the mouse internal device requests
+ * returns FALSE if it doesn't understand the
+ * call so someone else can handle it.
+ */
+BOOLEAN STDCALL I8042StartIoMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       PIO_STACK_LOCATION Stk;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       Stk = IoGetCurrentIrpStackLocation(Irp);
+    
+       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+       case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
+               I8042StartPacket(
+                            DevExt,
+                            DeviceObject,
+                            Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+                            Stk->Parameters.DeviceIoControl.InputBufferLength,
+                            Irp);
+               break;
+
+       default:
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*
+ * Runs the mouse IOCTL_INTERNAL dispatch.
+ * Returns NTSTATUS_INVALID_DEVICE_REQUEST if it doesn't handle this request
+ * so someone else can have a try at it.
+ */
+NTSTATUS STDCALL I8042InternalDeviceControlMouse(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       PIO_STACK_LOCATION Stk;
+       PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
+       PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
+
+       DPRINT("InternalDeviceControl\n");
+
+       Irp->IoStatus.Information = 0;
+       Stk = IoGetCurrentIrpStackLocation(Irp);
+    
+       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+
+       case IOCTL_INTERNAL_MOUSE_CONNECT:
+               DPRINT("IOCTL_INTERNAL_MOUSE_CONNECT\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 
+                                                     sizeof(CONNECT_DATA)) {
+                       DPRINT1("Mouse IOCTL_INTERNAL_MOUSE_CONNECT "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                       goto intcontfailure;
+               }
+
+               if (!DevExt->MouseExists) {
+                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+                       goto intcontfailure;
+               }
+
+               if (DevExt->MouseClaimed) {
+                       DPRINT1("IOCTL_INTERNAL_MOUSE_CONNECT: "
+                              "Mouse is already claimed\n");
+                       Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
+                       goto intcontfailure;
+               }
+
+               memcpy(&DevExt->MouseData,
+                      Stk->Parameters.DeviceIoControl.Type3InputBuffer,
+                      sizeof(CONNECT_DATA));
+               DevExt->MouseHook.IsrWritePort = I8042IsrWritePortMouse;
+               DevExt->MouseHook.QueueMousePacket = 
+                                                   I8042QueueMousePacket;
+               DevExt->MouseHook.CallContext = DevExt;
+
+               {
+                       PIO_WORKITEM WorkItem;
+                       PI8042_HOOK_WORKITEM WorkItemData;
+
+                       WorkItem = IoAllocateWorkItem(DeviceObject);
+                       if (!WorkItem) {
+                               DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
+                                       "Can't allocate work item\n");
+                               Irp->IoStatus.Status = 
+                                             STATUS_INSUFFICIENT_RESOURCES;
+                               goto intcontfailure;
+                       }
+
+                       WorkItemData = ExAllocatePoolWithTag(
+                                                  NonPagedPool,
+                                                  sizeof(I8042_HOOK_WORKITEM),
+                                                  TAG_I8042);
+                       if (!WorkItemData) {
+                               DPRINT ("IOCTL_INTERNAL_MOUSE_CONNECT: "
+                                       "Can't allocate work item data\n");
+                               Irp->IoStatus.Status = 
+                                             STATUS_INSUFFICIENT_RESOURCES;
+                               IoFreeWorkItem(WorkItem);
+                               goto intcontfailure;
+                       }
+                       WorkItemData->WorkItem = WorkItem;
+                       WorkItemData->Target = 
+                                       DevExt->MouseData.ClassDeviceObject;
+                       WorkItemData->Irp = Irp;
+
+                       IoMarkIrpPending(Irp);
+                       DevExt->MouseState = MouseResetting;
+                       DevExt->MouseResetState = 1100;
+                       IoQueueWorkItem(WorkItem,
+                                       I8042SendHookWorkItem,
+                                       DelayedWorkQueue,
+                                       WorkItemData);
+
+                       Irp->IoStatus.Status = STATUS_PENDING;
+               }
+
+               break;
+       case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
+               DPRINT("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 1) {
+                       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                       goto intcontfailure;
+               }
+               if (!DevExt->MouseInterruptObject) {
+                       Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
+                       goto intcontfailure;
+               }
+
+               IoMarkIrpPending(Irp);
+               IoStartPacket(DeviceObject, Irp, NULL, NULL);
+               Irp->IoStatus.Status = STATUS_PENDING;
+
+               break;
+       case IOCTL_MOUSE_QUERY_ATTRIBUTES:
+               DPRINT("IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
+               if (Stk->Parameters.DeviceIoControl.InputBufferLength < 
+                                                sizeof(MOUSE_ATTRIBUTES)) {
+                       DPRINT("Mouse IOCTL_MOUSE_QUERY_ATTRIBUTES "
+                              "invalid buffer size\n");
+                       Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       goto intcontfailure;
+               }
+               memcpy(Irp->AssociatedIrp.SystemBuffer,
+                      &DevExt->MouseAttributes,
+                      sizeof(MOUSE_ATTRIBUTES));
+
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               break;
+       default:
+               Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+               break;
+       }
+
+intcontfailure:
+       return Irp->IoStatus.Status;
+}
+
+BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt)
+{
+       UCHAR Value;
+       NTSTATUS Status;
+
+       DPRINT("Enabling mouse\n");
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+               DPRINT1("Can't read i8042 mode\n");
+               return FALSE;
+       }
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1("No response after read i8042 mode\n");
+               return FALSE;
+       }
+
+       Value &= ~(0x20); // don't disable mouse
+       Value |= 0x02;    // enable mouse interrupts
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+               DPRINT1("Can't set i8042 mode\n");
+               return FALSE;
+       }
+
+       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+               DPRINT1("Can't send i8042 mode\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt)
+{
+       UCHAR Value;
+       NTSTATUS Status;
+
+       DPRINT("Disabling mouse\n");
+
+       I8042Flush(); /* Just to be (kind of) sure */
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
+               DPRINT1("Can't read i8042 mode\n");
+               return FALSE;
+       }
+
+       Status = I8042ReadDataWait(DevExt, &Value);
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1("No response after read i8042 mode\n");
+               return FALSE;
+       }
+
+       Value |= 0x20; // don't disable mouse
+       Value &= ~(0x02);    // enable mouse interrupts
+
+       if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_WRITE_MODE)) {
+               DPRINT1("Can't set i8042 mode\n");
+               return FALSE;
+       }
+
+       if (!I8042Write(DevExt, I8042_DATA_PORT, Value)) {
+               DPRINT1("Can't send i8042 mode\n");
+               return FALSE;
+       }
+
+       I8042Flush(); 
+       /* Just to be (kind of) sure; if the mouse would
+        * say something while we are disabling it, these bytes would
+        * block the keyboard.
+        */
+
+       return TRUE;
+}
diff --git a/reactos/drivers/input/i8042prt/ps2pp.c b/reactos/drivers/input/i8042prt/ps2pp.c
new file mode 100644 (file)
index 0000000..cf03f1e
--- /dev/null
@@ -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 <ddk/ntddk.h>
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+
+VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, BYTE Input)
+{
+       UCHAR PktType;
+       PMOUSE_INPUT_DATA MouseInput = DevExt->MouseBuffer +
+                                                DevExt->MouseInBuffer;
+
+/* First, collect 3 bytes for a packet
+ * We can detect out-of-sync only by checking
+ * the whole packet anyway.
+ *
+ * If bit 7 and 8 of the first byte are 0, its
+ * a normal packet.
+ *
+ * Otherwise, the packet is different, like this:
+ * 1: E  1 b3 b2  x  x  x  x
+ * 2: x  x b1 b0 x1 x0  1  0 
+ * 3: x  x  x  x  x  x x1 x0
+ *
+ * b3-0 form a code that specifies the packet type:
+ * 
+ * 0  Device Type
+ * 1  Rollers and buttons
+ * 2   Reserved
+ * 3   Reserved
+ * 4  Device ID 
+ * 5  Channel & Battery
+ * 6  Wireless notifications
+ * 7   Reserved
+ * 8  ShortID LSB (ShortID is a number that is supposed to differentiate
+ * 9  ShortID MSB  between your mouse and your neighbours')
+ * 10  Reserved
+ * 11 Mouse capabilities
+ * 12 Remote control LSB
+ * 13 Remote control MSB
+ * 14  Reserved
+ * 15 Extended packet
+ */
+
+       switch (DevExt->MouseState) {
+       case MouseIdle:
+       case XMovement:
+               DevExt->MouseLogiBuffer[DevExt->MouseState] = Input;
+               DevExt->MouseState++;
+               break;
+       
+       case YMovement:
+               DevExt->MouseLogiBuffer[2] = Input;
+               DevExt->MouseState = MouseIdle;
+
+               /* first check if it's a normal packet */
+
+               if (!(DevExt->MouseLogiBuffer[0] & 0xC0)) {
+                       DevExt->MouseState = MouseIdle;
+                       I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[0]);
+                       I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[1]);
+                       I8042MouseHandle(DevExt, DevExt->MouseLogiBuffer[2]);
+                       /* We could care about wether MouseState really
+                        * advances, but we don't need to because we're
+                        * only doing three bytes anyway, so the packet 
+                        * will never complete if it's broken.
+                        */
+                       return;
+               }
+
+               /* sanity check */
+
+               if (((DevExt->MouseLogiBuffer[0] & 0x48) != 0x48) ||
+                   (((DevExt->MouseLogiBuffer[1] & 0x0C) >> 2) !=
+                    (DevExt->MouseLogiBuffer[2] & 0x03))) {
+                       DPRINT1("Ps2pp packet fails sanity checks\n");
+                       return;
+               }
+
+               /* Now get the packet type */
+
+               PktType = ((DevExt->MouseLogiBuffer[0] & 0x30) >> 4) &
+                         ((DevExt->MouseLogiBuffer[1] & 0x30) >> 6);
+
+               switch (PktType) {
+               case 0:
+                       /* The packet contains the device ID, but we
+                        * already read that in the initialization
+                        * sequence. Ignore it.
+                        */
+                       return; 
+               case 1:
+                       RtlZeroMemory(MouseInput, sizeof(MOUSE_INPUT_DATA));
+                       if (DevExt->MouseLogiBuffer[2] & 0x10)
+                               MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
+
+                       if (DevExt->MouseLogiBuffer[2] & 0x20)
+                               MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
+
+                       if (DevExt->MouseLogiBuffer[2] & 0x0F) {
+                               MouseInput->ButtonFlags |= MOUSE_WHEEL;
+                               if (DevExt->MouseLogiBuffer[2] & 0x08)
+                                       MouseInput->ButtonData = 
+                                          (DevExt->MouseLogiBuffer[2] & 0x07) -
+                                              8;
+                               else
+                                       MouseInput->ButtonData = 
+                                            DevExt->MouseLogiBuffer[2] & 0x07;
+                       }
+                       I8042MouseHandleButtons(DevExt, MOUSE_BUTTON_4_DOWN |
+                                                       MOUSE_BUTTON_5_DOWN);
+                       I8042QueueMousePacket(
+                                        DevExt->MouseObject);
+                       return;
+               default:
+                       /* These are for things that would probably
+                        * be handled by logitechs own driver.
+                        */
+                       return;
+               }
+       default:
+               DPRINT1("Unexpected input state for ps2pp!\n");
+       }
+}
diff --git a/reactos/drivers/input/i8042prt/registry.c b/reactos/drivers/input/i8042prt/registry.c
new file mode 100644 (file)
index 0000000..d71d99a
--- /dev/null
@@ -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 <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "i8042prt.h"
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * Read the registry keys associated with this device. The RegistryPath
+ * var is a hack. This should be more like what microsoft does, but I
+ * don't know exactly what they do except that it's a hack too...
+ */
+VOID STDCALL I8042ReadRegistry(PDRIVER_OBJECT DriverObject,
+                               PDEVICE_EXTENSION DevExt)
+                               
+{
+       RTL_QUERY_REGISTRY_TABLE Parameters[18];
+       UNICODE_STRING ParametersPath;
+
+       PWSTR RegistryPath = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\i8042Prt\\Parameters";
+
+       NTSTATUS Status;
+
+       DWORD DefaultHeadless = 0;
+       DWORD DefaultCrashScroll = 0;
+       DWORD DefaultCrashSysRq = 0;
+       DWORD DefaultReportResetErrors = 0;
+       DWORD DefaultPollStatusIterations = 1;
+       DWORD DefaultResendIterations = 3;
+       DWORD DefaultPollingIterations = 12000;
+       DWORD DefaultPollingIterationsMaximum = 12000;
+       DWORD DefaultKeyboardDataQueueSize = 100;
+       DWORD DefaultOverrideKeyboardType = 0;
+       DWORD DefaultOverrideKeyboardSubtype = 0;
+       DWORD DefaultMouseDataQueueSize = 100;
+       DWORD DefaultMouseResendStallTime = 1000;
+       DWORD DefaultMouseSynchIn100ns = 20000000;
+       DWORD DefaultMouseResolution = 3;
+       DWORD DefaultSampleRate = 60;
+       DWORD DefaultNumberOfButtons = 2;
+       DWORD DefaultEnableWheelDetection = 1;
+
+       RtlInitUnicodeString(&ParametersPath, NULL);
+       ParametersPath.MaximumLength = (wcslen(RegistryPath) *
+                                               sizeof(WCHAR)) +
+                                      sizeof(UNICODE_NULL);
+
+       ParametersPath.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                             ParametersPath.MaximumLength,
+                                             TAG_I8042);
+
+       if (!ParametersPath.Buffer) {
+               DPRINT1("No buffer space for reading registry\n");
+               return;
+       }
+
+       RtlZeroMemory(ParametersPath.Buffer, ParametersPath.MaximumLength);
+       RtlAppendUnicodeToString(&ParametersPath, RegistryPath);
+
+       RtlZeroMemory(Parameters, sizeof(Parameters));
+
+       Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[0].Name = L"Headless";
+       Parameters[0].EntryContext = &DevExt->Settings.Headless;
+       Parameters[0].DefaultType = REG_DWORD;
+       Parameters[0].DefaultData = &DefaultHeadless;
+       Parameters[0].DefaultLength = sizeof(ULONG);
+
+       Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[1].Name = L"CrashOnCtrlScroll";
+       Parameters[1].EntryContext = &DevExt->Settings.CrashScroll;
+       Parameters[1].DefaultType = REG_DWORD;
+       Parameters[1].DefaultData = &DefaultCrashScroll;
+       Parameters[1].DefaultLength = sizeof(ULONG);
+
+       Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[2].Name = L"BreakOnSysRq";
+       Parameters[2].EntryContext = &DevExt->Settings.CrashSysRq;
+       Parameters[2].DefaultType = REG_DWORD;
+       Parameters[2].DefaultData = &DefaultCrashSysRq;
+       Parameters[2].DefaultLength = sizeof(ULONG);
+
+       Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[3].Name = L"ReportResetErrors";
+       Parameters[3].EntryContext = &DevExt->Settings.ReportResetErrors;
+       Parameters[3].DefaultType = REG_DWORD;
+       Parameters[3].DefaultData = &DefaultReportResetErrors;
+       Parameters[3].DefaultLength = sizeof(ULONG);
+
+       Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[4].Name = L"PollStatusIterations";
+       Parameters[4].EntryContext = &DevExt->Settings.PollStatusIterations;
+       Parameters[4].DefaultType = REG_DWORD;
+       Parameters[4].DefaultData = &DefaultPollStatusIterations;
+       Parameters[4].DefaultLength = sizeof(ULONG);
+
+       Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[5].Name = L"ResendIterations";
+       Parameters[5].EntryContext = &DevExt->Settings.ResendIterations;
+       Parameters[5].DefaultType = REG_DWORD;
+       Parameters[5].DefaultData = &DefaultResendIterations;
+       Parameters[5].DefaultLength = sizeof(ULONG);
+
+       Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[6].Name = L"PollingIterations";
+       Parameters[6].EntryContext = &DevExt->Settings.PollingIterations;
+       Parameters[6].DefaultType = REG_DWORD;
+       Parameters[6].DefaultData = &DefaultPollingIterations;
+       Parameters[6].DefaultLength = sizeof(ULONG);
+
+       Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[7].Name = L"PollingIterationsMaximum";
+       Parameters[7].EntryContext = &DevExt->Settings.PollingIterationsMaximum;
+       Parameters[7].DefaultType = REG_DWORD;
+       Parameters[7].DefaultData = &DefaultPollingIterationsMaximum;
+       Parameters[7].DefaultLength = sizeof(ULONG);
+
+       Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[8].Name = L"KeyboardDataQueueSize";
+       Parameters[8].EntryContext =
+                              &DevExt->KeyboardAttributes.InputDataQueueLength;
+       Parameters[8].DefaultType = REG_DWORD;
+       Parameters[8].DefaultData = &DefaultKeyboardDataQueueSize;
+       Parameters[8].DefaultLength = sizeof(ULONG);
+
+       Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[9].Name = L"OverrideKeyboardType";
+       Parameters[9].EntryContext = &DevExt->Settings.OverrideKeyboardType;
+       Parameters[9].DefaultType = REG_DWORD;
+       Parameters[9].DefaultData = &DefaultOverrideKeyboardType;
+       Parameters[9].DefaultLength = sizeof(ULONG);
+
+       Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[10].Name = L"OverrideKeyboardSubtype";
+       Parameters[10].EntryContext = &DevExt->Settings.OverrideKeyboardSubtype;
+       Parameters[10].DefaultType = REG_DWORD;
+       Parameters[10].DefaultData = &DefaultOverrideKeyboardSubtype;
+       Parameters[10].DefaultLength = sizeof(ULONG);
+
+       Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[11].Name = L"MouseDataQueueSize";
+       Parameters[11].EntryContext =
+                             &DevExt->MouseAttributes.InputDataQueueLength;
+       Parameters[11].DefaultType = REG_DWORD;
+       Parameters[11].DefaultData = &DefaultMouseDataQueueSize;
+       Parameters[11].DefaultLength = sizeof(ULONG);
+
+       Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[12].Name = L"MouseResendStallTime";
+       Parameters[12].EntryContext = &DevExt->Settings.MouseResendStallTime;
+       Parameters[12].DefaultType = REG_DWORD;
+       Parameters[12].DefaultData = &DefaultMouseResendStallTime;
+       Parameters[12].DefaultLength = sizeof(ULONG);
+
+       Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[13].Name = L"MouseSynchIn100ns";
+       Parameters[13].EntryContext = &DevExt->Settings.MouseSynchIn100ns;
+       Parameters[13].DefaultType = REG_DWORD;
+       Parameters[13].DefaultData = &DefaultMouseSynchIn100ns;
+       Parameters[13].DefaultLength = sizeof(ULONG);
+
+       Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[14].Name = L"MouseResolution";
+       Parameters[14].EntryContext = &DevExt->Settings.MouseResolution;
+       Parameters[14].DefaultType = REG_DWORD;
+       Parameters[14].DefaultData = &DefaultMouseResolution;
+       Parameters[14].DefaultLength = sizeof(ULONG);
+
+       Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[14].Name = L"SampleRate";
+       Parameters[14].EntryContext = &DevExt->MouseAttributes.SampleRate;
+       Parameters[14].DefaultType = REG_DWORD;
+       Parameters[14].DefaultData = &DefaultSampleRate;
+       Parameters[14].DefaultLength = sizeof(ULONG);
+
+       Parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[15].Name = L"NumberOfButtons";
+       Parameters[15].EntryContext = &DevExt->Settings.NumberOfButtons;
+       Parameters[15].DefaultType = REG_DWORD;
+       Parameters[15].DefaultData = &DefaultNumberOfButtons;
+       Parameters[15].DefaultLength = sizeof(ULONG);
+
+       Parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       Parameters[16].Name = L"EnableWheelDetection";
+       Parameters[16].EntryContext = &DevExt->Settings.EnableWheelDetection;
+       Parameters[16].DefaultType = REG_DWORD;
+       Parameters[16].DefaultData = &DefaultEnableWheelDetection;
+       Parameters[16].DefaultLength = sizeof(ULONG);
+
+       Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE |
+                                               RTL_REGISTRY_OPTIONAL,
+                                       ParametersPath.Buffer,
+                                       Parameters,
+                                       NULL,
+                                       NULL);
+
+       if (Status != STATUS_SUCCESS) {
+               DPRINT1 ("Can't read registry: %x\n", Status);
+               /* Actually, the defaults are not set when the function
+                * fails, as would happen during setup, so you have to
+                * set them manually anyway...
+                */
+               RTL_QUERY_REGISTRY_TABLE *Current = Parameters;
+               while (Current->Name) {
+                       *((DWORD *)Current->EntryContext) =
+                                              *((DWORD *)Current->DefaultData);
+                       Current++;
+               }
+               DPRINT1 ("Manually set defaults\n");
+
+       }
+       ExFreePool(ParametersPath.Buffer);
+       DPRINT("Done reading registry\n");
+}
+
diff --git a/reactos/drivers/input/kbdclass/kbdclass.c b/reactos/drivers/input/kbdclass/kbdclass.c
new file mode 100644 (file)
index 0000000..866275a
--- /dev/null
@@ -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 <ddk/ntddk.h>
+#include <string.h>
+#include <ntos/keyboard.h>
+#include <ntos/minmax.h>
+#include <rosrtl/string.h>
+
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#include "kbdclass.h"
+
+/* GLOBALS *******************************************************************/
+
+/*
+ * Driver data
+ */
+
+static BOOLEAN AlreadyOpened = FALSE;
+
+static VOID STDCALL KbdCopyKeys(PDEVICE_OBJECT DeviceObject,
+                           PIRP Irp)
+{
+       PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+       PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+       ULONG NrToRead = stk->Parameters.Read.Length /
+                                                sizeof(KEYBOARD_INPUT_DATA);
+       ULONG NrRead = Irp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
+       KEYBOARD_INPUT_DATA *Rec =
+                      (KEYBOARD_INPUT_DATA *)Irp->AssociatedIrp.SystemBuffer;
+
+       while (DevExt->KeysInBuffer &&
+              NrRead < NrToRead) {
+               memcpy(&Rec[NrRead],
+                      &DevExt->KbdBuffer[DevExt->BufHead],
+                      sizeof(KEYBOARD_INPUT_DATA));
+
+               if (++DevExt->BufHead >= KBD_BUFFER_SIZE)
+                       DevExt->BufHead = 0;
+
+               DevExt->KeysInBuffer--;
+               NrRead++;
+       }
+       Irp->IoStatus.Information = NrRead * sizeof(KEYBOARD_INPUT_DATA);
+
+       if (NrRead < NrToRead) {
+               Irp->IoStatus.Status = STATUS_PENDING;
+               DPRINT("Pending... (NrRead %d, NrToRead %d\n", NrRead, NrToRead);
+       } else {
+               DPRINT("Send scancode: %x\n", ((KEYBOARD_INPUT_DATA*)Irp->AssociatedIrp.SystemBuffer)->MakeCode);
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+               IoCompleteRequest(Irp, IO_NO_INCREMENT);
+               IoStartNextPacket (DeviceObject, FALSE);
+               DPRINT("Success!\n");
+       }
+}
+
+static VOID STDCALL KbdClassServiceCallback (
+                                      PDEVICE_OBJECT DeviceObject,
+                                      PKEYBOARD_INPUT_DATA InputDataStart,
+                                      PKEYBOARD_INPUT_DATA InputDataEnd,
+                                      PULONG InputDataConsumed)
+{
+       PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+       PKEYBOARD_INPUT_DATA CurrentInput = InputDataStart;
+
+       DPRINT("ServiceCallback called\n");
+
+       while (DevExt->KeysInBuffer < KBD_BUFFER_SIZE &&
+              CurrentInput < InputDataEnd) {
+               memcpy(&DevExt->KbdBuffer[DevExt->BufTail],
+                      CurrentInput,
+                      sizeof(KEYBOARD_INPUT_DATA));
+
+               if (++DevExt->BufTail >= KBD_BUFFER_SIZE)
+                       DevExt->BufTail = 0;
+               DevExt->KeysInBuffer++;
+
+               CurrentInput++;
+               InputDataConsumed[0]++;
+       }
+
+       if (CurrentInput < InputDataStart)
+               /* Copy the rest to the beginning, perhaps the keyboard
+                * can buffer it for us */
+               memmove(InputDataStart,
+                       CurrentInput,
+                       ((char *)InputDataEnd - (char *)CurrentInput));
+
+       if (DeviceObject->CurrentIrp) {
+               PIRP Irp = DeviceObject->CurrentIrp;
+               PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+               if (stk->MajorFunction == IRP_MJ_READ)
+                       KbdCopyKeys(DeviceObject, Irp);
+       }
+}
+
+VOID STDCALL KbdStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       /* We only do this for read irps */
+       DPRINT("KeyboardStartIo(DeviceObject %x Irp %x)\n",DeviceObject,Irp);
+       KbdCopyKeys(DeviceObject, Irp);
+}
+
+
+/*
+ * These are just passed down the stack but we must change the IOCTL to be
+ * INTERNAL. MSDN says there might be more...
+ */
+NTSTATUS STDCALL KbdDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+       PIO_STACK_LOCATION Stk = IoGetCurrentIrpStackLocation(Irp);
+       PIO_STACK_LOCATION NextStk = IoGetNextIrpStackLocation(Irp);
+
+       DPRINT ("KbdDeviceControl %x\n", Stk->Parameters.DeviceIoControl.IoControlCode);
+
+       switch (Stk->Parameters.DeviceIoControl.IoControlCode) {
+       case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
+       case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
+       case IOCTL_KEYBOARD_QUERY_INDICATORS:
+       case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
+       case IOCTL_KEYBOARD_SET_INDICATORS:
+       case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
+               IoCopyCurrentIrpStackLocationToNext(Irp);
+               NextStk->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+               return IoCallDriver(DevExt->I8042Device, Irp);
+       default:
+               return STATUS_INVALID_DEVICE_REQUEST;
+       }
+}
+
+static NTSTATUS STDCALL KbdInternalDeviceControl(PDEVICE_OBJECT DeviceObject,
+                                                 PIRP Irp)
+{
+       PDEVICE_EXTENSION DevExt = DeviceObject->DeviceExtension;
+
+       DPRINT ("KbdInternalDeviceControl\n");
+
+       IoSkipCurrentIrpStackLocation(Irp);
+       return IoCallDriver(DevExt->I8042Device, Irp);
+}
+
+static NTSTATUS STDCALL KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+       PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+       NTSTATUS Status;
+
+       DPRINT("DeviceObject %x\n",DeviceObject);
+       DPRINT("Irp %x\n",Irp);
+   
+       DPRINT("Dispatch: stk->MajorFunction %d\n", stk->MajorFunction);
+       DPRINT("AlreadyOpened %d\n",AlreadyOpened);
+   
+       switch (stk->MajorFunction) {
+       case IRP_MJ_CREATE:
+               if (AlreadyOpened == TRUE) {
+                       CHECKPOINT;
+                       Status = STATUS_UNSUCCESSFUL;
+                       DPRINT1("Keyboard is already open\n");
+               } else {
+                       CHECKPOINT;
+                       Status = STATUS_SUCCESS;
+                       AlreadyOpened = TRUE;
+               }
+               break;
+
+       case IRP_MJ_CLOSE:
+               Status = STATUS_SUCCESS;
+               AlreadyOpened = FALSE;
+               break;
+
+       case IRP_MJ_READ:
+               DPRINT("Queueing packet\n");
+               IoMarkIrpPending(Irp);
+               IoStartPacket(DeviceObject,Irp,NULL,NULL);
+               return(STATUS_PENDING);
+
+       default:
+               Status = STATUS_NOT_IMPLEMENTED;
+               break;
+       }
+
+       Irp->IoStatus.Status = Status;
+       Irp->IoStatus.Information = 0;
+       IoCompleteRequest(Irp,IO_NO_INCREMENT);
+       DPRINT("Status %d\n",Status);
+       return(Status);
+}
+
+static VOID STDCALL KbdClassSendConnect(PDEVICE_EXTENSION DevExt)
+{
+       CONNECT_DATA ConnectData;
+       KEVENT Event;
+       IO_STATUS_BLOCK IoStatus;
+       NTSTATUS Status;
+       PIRP Irp;
+
+       KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+       ConnectData.ClassDeviceObject = DevExt->DeviceObject;
+       ConnectData.ClassService = KbdClassServiceCallback;
+
+       Irp = IoBuildDeviceIoControlRequest(
+                       IOCTL_INTERNAL_KEYBOARD_CONNECT,
+                       DevExt->I8042Device,
+                       &ConnectData,
+                       sizeof(CONNECT_DATA),
+                       NULL,
+                       0,
+                       TRUE,
+                       &Event,
+                       &IoStatus);
+
+       if (!Irp)
+               return;
+
+       Status = IoCallDriver(
+                       DevExt->I8042Device,
+                       Irp);
+       DPRINT("SendConnect status: %x\n", Status);
+
+       if (STATUS_PENDING ==Status)
+               KeWaitForSingleObject(&Event,
+                                     Executive,
+                                     KernelMode,
+                                     FALSE,
+                                     NULL);
+       DPRINT("SendConnect done\n");
+}
+
+NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject, 
+                            PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Module entry point
+ */
+{
+       PDEVICE_OBJECT DeviceObject;
+       PDEVICE_EXTENSION DevExt;
+       PFILE_OBJECT I8042File;
+       NTSTATUS Status;
+       UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\Keyboard");
+       UNICODE_STRING SymlinkName = ROS_STRING_INITIALIZER(L"\\??\\Keyboard");
+       UNICODE_STRING I8042Name = ROS_STRING_INITIALIZER(L"\\Device\\KeyboardClass0");
+   
+       DPRINT("Keyboard Class Driver 0.0.1\n");
+
+       DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdDispatch;
+       DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdDispatch;
+       DriverObject->MajorFunction[IRP_MJ_READ] = KbdDispatch;
+       DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = 
+                                                    KbdInternalDeviceControl;
+       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdDeviceControl;
+
+       DriverObject->DriverStartIo = KbdStartIo;
+
+       IoCreateDevice(DriverObject,
+                      sizeof(DEVICE_EXTENSION),
+                      &DeviceName,
+                      FILE_DEVICE_KEYBOARD,
+                      0,
+                      TRUE,
+                      &DeviceObject);
+       
+       RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
+       DevExt = DeviceObject->DeviceExtension;
+       DevExt->DeviceObject = DeviceObject;
+
+       Status = IoGetDeviceObjectPointer(&I8042Name,
+                                         FILE_READ_DATA,
+                                         &I8042File,
+                                         &DevExt->I8042Device);
+
+       if (STATUS_SUCCESS != Status) {
+               DPRINT("Failed to open device: %x\n", Status);
+               return Status;
+       }
+
+       ObReferenceObject(DevExt->I8042Device);
+       ObDereferenceObject(I8042File);
+
+       DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
+
+       DeviceObject->StackSize = 1 + DevExt->I8042Device->StackSize;
+   
+       IoCreateSymbolicLink(&SymlinkName, &DeviceName);
+
+       KbdClassSendConnect(DevExt);
+   
+       return(STATUS_SUCCESS);
+}
diff --git a/reactos/drivers/input/kbdclass/kbdclass.h b/reactos/drivers/input/kbdclass/kbdclass.h
new file mode 100644 (file)
index 0000000..a96273d
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef _KEYBOARD_H_
+#define _KEYBOARD_H_
+#include <ddk/ntddkbd.h>
+#include <ddk/ntdd8042.h>
+
+#define KBD_BUFFER_SIZE    32
+#define KBD_WRAP_MASK      0x1F
+
+/*-----------------------------------------------------
+ *  DeviceExtension
+ * --------------------------------------------------*/
+typedef struct _DEVICE_EXTENSION
+{
+       PDEVICE_OBJECT I8042Device;
+       PDEVICE_OBJECT DeviceObject;
+
+       KEYBOARD_INPUT_DATA KbdBuffer[KBD_BUFFER_SIZE];
+       int BufHead,BufTail;
+       int KeysInBuffer;
+
+       BOOLEAN AlreadyOpened;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+typedef struct _CONNECT_DATA {
+       PDEVICE_OBJECT ClassDeviceObject;
+       PVOID ClassService;
+} CONNECT_DATA, *PCONNECT_DATA;
+
+/*
+ * Some defines
+ */
+
+#define IOCTL_INTERNAL_KEYBOARD_CONNECT \
+   CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#define KEYBOARD_IRQ       1
+
+#define disable()          __asm__("cli\n\t")
+#define enable()           __asm__("sti\n\t")
+
+#define ALT_PRESSED                    (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
+#define CTRL_PRESSED                   (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
+
+
+/*
+ * Keyboard controller ports
+ */
+
+#define KBD_DATA_PORT      0x60
+#define KBD_CTRL_PORT      0x64
+
+
+/*
+ * Controller commands
+ */
+
+#define KBD_READ_MODE      0x20
+#define KBD_WRITE_MODE     0x60
+#define KBD_SELF_TEST      0xAA
+#define KBD_LINE_TEST      0xAB
+#define KBD_CTRL_ENABLE    0xAE
+
+/*
+ * Keyboard commands
+ */
+
+#define KBD_ENABLE         0xF4
+#define KBD_DISABLE        0xF5
+#define KBD_RESET          0xFF
+
+
+/*
+ * Keyboard responces
+ */
+
+#define KBD_ACK            0xFA
+#define KBD_BATCC          0xAA
+
+
+/*
+ * Controller status register bits
+ */
+
+#define KBD_OBF            0x01
+#define KBD_IBF            0x02
+#define KBD_GTO            0x40
+#define KBD_PERR           0x80
+
+
+/*
+ * LED bits
+ */
+
+#define KBD_LED_SCROLL     0x01
+#define KBD_LED_NUM        0x02
+#define KBD_LED_CAPS       0x04
+
+#endif // _KEYBOARD_H_
diff --git a/reactos/drivers/input/kbdclass/kbdclass.rc b/reactos/drivers/input/kbdclass/kbdclass.rc
new file mode 100644 (file)
index 0000000..732b237
--- /dev/null
@@ -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 <reactos/version.rc>
diff --git a/reactos/drivers/input/kbdclass/makefile b/reactos/drivers/input/kbdclass/makefile
new file mode 100644 (file)
index 0000000..82baae6
--- /dev/null
@@ -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
index 553b2fd..8882a57 100644 (file)
 
 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);
    }
index a0441fe..4bcace9 100644 (file)
@@ -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;
 
index d41a796..c5c7f09 100644 (file)
@@ -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 */
index ba45f08..0e654f4 100644 (file)
@@ -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);
index d256fa2..a528394 100644 (file)
 
 #include "precomp.h"
 #include <ddk/ntddblue.h>
+#include <ddk/ntddkbd.h>
 
 #include "usetup.h"
 #include "console.h"
+#include "keytrans.h"
 
 #define NDEBUG
 #include <debug.h>
@@ -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 (file)
index 0000000..3ea75d1
--- /dev/null
@@ -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 <debug.h>
+
+#include "precomp.h"
+#include <ddk/ntddblue.h>
+#include <ddk/ntddkbd.h>
+#include <windows.h>
+
+static WORD KeyTable[] = {
+/* 0x00 */
+       0x00,           VK_ESCAPE,      0x31,           0x32,
+       0x33,           0x34,           0x35,           0x36,
+       0x37,           0x38,           0x39,           0x30,
+       VK_OEM_MINUS,   VK_OEM_PLUS,    VK_BACK,        VK_TAB,
+/* 0x10 */
+       0x51,           0x57,           0x45,           0x52,
+       0x54,           0x59,           0x55,           0x49,
+       0x4f,           0x50,           VK_OEM_4,       VK_OEM_6,
+       VK_RETURN,      VK_CONTROL,     0x41,           0x53,
+/* 0x20 */
+       0x44,           0x46,           0x47,           0x48,
+       0x4a,           0x4b,           0x4c,           VK_OEM_1,
+       VK_OEM_7,       0xc0,           VK_LSHIFT,      VK_OEM_5,
+       0x5a,           0x58,           0x43,           0x56,
+/* 0x30 */
+       0x42,           0x4e,           0x4d,           VK_OEM_COMMA,
+       VK_OEM_PERIOD,  VK_OEM_2,       VK_RSHIFT,      VK_MULTIPLY,
+       VK_LMENU,       VK_SPACE,       VK_CAPITAL,     VK_F1,
+       VK_F2,          VK_F3,          VK_F4,          VK_F5,
+/* 0x40 */
+       VK_F6,          VK_F7,          VK_F8,          VK_F9,
+       VK_F10,         VK_NUMLOCK,     VK_SCROLL,      VK_NUMPAD7,
+       VK_NUMPAD8,     VK_NUMPAD9,     VK_SUBTRACT,    VK_NUMPAD4,
+       VK_NUMPAD5,     VK_NUMPAD6,     VK_ADD,         VK_NUMPAD1,
+/* 0x50 */
+       VK_NUMPAD2,     VK_NUMPAD3,     VK_NUMPAD0,     VK_SEPARATOR,
+       0,              0,              0,              VK_F11,
+       VK_F12,         0,              0,              0,
+       0,              0,              0,              0,
+/* 0x60 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+/* 0x70 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0
+};
+
+static WORD KeyTableEnhanced[] = {
+/* 0x00 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+/* 0x10 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       VK_RETURN,      VK_RCONTROL,    0,              0,
+/* 0x20 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+/* 0x30 */
+       0,              0,              0,              0,
+       0,              VK_DIVIDE,      0,              VK_SNAPSHOT,
+       VK_RMENU,       0,              0,              0,
+       0,              0,              0,              0,
+/* 0x40 */
+       0,              0,              0,              0,
+       0,              0,              0,              VK_HOME,
+       VK_UP,          VK_PRIOR,       0,              VK_LEFT,
+       0,              VK_RIGHT,       0,              VK_END,
+/* 0x50 */
+       VK_DOWN,        VK_NEXT,        VK_INSERT,      VK_DELETE,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+/* 0x60 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+/* 0x70 */
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0,
+       0,              0,              0,              0
+};
+
+typedef struct _SCANTOASCII {
+       USHORT ScanCode;
+       USHORT Enhanced;
+       UCHAR Normal;
+       UCHAR Shift;
+       UCHAR NumLock;
+} SCANTOASCII, *PSCANTOASCII;
+
+SCANTOASCII ScanToAscii[] = {
+{      0x1e,   0,      'a',    'A',    0       },
+{      0x30,   0,      'b',    'B',    0       },
+{      0x2e,   0,      'c',    'C',    0       },
+{      0x20,   0,      'd',    'D',    0       },
+{      0x12,   0,      'e',    'E',    0       },
+{      0x21,   0,      'f',    'F',    0       },
+{      0x22,   0,      'g',    'G',    0       },
+{      0x23,   0,      'h',    'H',    0       },
+{      0x17,   0,      'i',    'I',    0       },
+{      0x24,   0,      'j',    'J',    0       },
+{      0x25,   0,      'k',    'K',    0       },
+{      0x26,   0,      'l',    'L',    0       },
+{      0x32,   0,      'm',    'M',    0       },
+{      0x31,   0,      'n',    'N',    0       },
+{      0x18,   0,      'o',    'O',    0       },
+{      0x19,   0,      'p',    'P',    0       },
+{      0x10,   0,      'q',    'Q',    0       },
+{      0x13,   0,      'r',    'R',    0       },
+{      0x1f,   0,      's',    'S',    0       },
+{      0x14,   0,      't',    'T',    0       },
+{      0x16,   0,      'u',    'U',    0       },
+{      0x2f,   0,      'v',    'V',    0       },
+{      0x11,   0,      'w',    'W',    0       },
+{      0x2d,   0,      'x',    'X',    0       },
+{      0x15,   0,      'y',    'Y',    0       },
+{      0x2c,   0,      'z',    'Z',    0       },
+
+{      0x02,   0,      '1',    '!',    0       },
+{      0x03,   0,      '2',    '@',    0       },
+{      0x04,   0,      '3',    '#',    0       },
+{      0x05,   0,      '4',    '$',    0       },
+{      0x06,   0,      '5',    '%',    0       },
+{      0x07,   0,      '6',    '^',    0       },
+{      0x08,   0,      '7',    '&',    0       },
+{      0x09,   0,      '8',    '*',    0       },
+{      0x0a,   0,      '9',    '(',    0       },
+{      0x0b,   0,      '0',    ')',    0       },
+
+{      0x29,   0,      '\'',   '~',    0       },
+{      0x0c,   0,      '-',    '_',    0       },
+{      0x0d,   0,      '=',    '+',    0       },
+{      0x1a,   0,      '[',    '{',    0       },
+{      0x1b,   0,      ']',    '}',    0       },
+{      0x2b,   0,      '\\',   '|',    0       },
+{      0x27,   0,      ';',    ':',    0       },
+{      0x28,   0,      '\'',   '"',    0       },
+{      0x33,   0,      ',',    '<',    0       },
+{      0x34,   0,      '.',    '>',    0       },
+{      0x35,   0,      '/',    '?',    0       },
+
+{      0x4f,   0,      0,      0,      '1'     },
+{      0x50,   0,      0,      0,      '2'     },
+{      0x51,   0,      0,      0,      '3'     },
+{      0x4b,   0,      0,      0,      '4'     },
+{      0x4c,   0,      0,      0,      '5'     },
+{      0x4d,   0,      0,      0,      '6'     },
+{      0x47,   0,      0,      0,      '7'     },
+{      0x48,   0,      0,      0,      '8'     },
+{      0x49,   0,      0,      0,      '9'     },
+{      0x52,   0,      0,      0,      '0'     },
+
+{      0x4a,   0,      '-',    '-',    0       },
+{      0x4e,   0,      '+',    '+',    0       },
+{      0x37,   0,      '*',    '*',    0       },
+{      0x35,   1,      '/',    '/',    0       },
+{      0x53,   0,      0,      0,      '.'     },
+
+{      0x39,   0,      ' ',    ' ',    0       },
+
+{      0x1c,   0,      '\r',   '\r',   0       },
+{      0x1c,   1,      '\r',   '\r',   0       },
+{      0x0e,   0,      0x08,   0x08,   0       }, /* backspace */
+
+{      0,      0,      0,      0,      0       }
+};
+
+
+static void
+IntUpdateControlKeyState(LPDWORD State, PKEYBOARD_INPUT_DATA InputData)
+{
+       DWORD Value = 0;
+
+       if (InputData->Flags & KEY_E1) /* Only the pause key has E1 */
+               return;
+
+       if (!(InputData->Flags & KEY_E0)) {
+               switch (InputData->MakeCode) {
+                       case 0x2a:
+                       case 0x36:
+                               Value = SHIFT_PRESSED;
+                               break;
+
+                       case 0x1d:
+                               Value = LEFT_CTRL_PRESSED;
+                               break;
+
+                       case 0x38:
+                               Value = LEFT_ALT_PRESSED;
+                               break;
+
+                       default:
+                               return;
+               }
+       } else {
+               switch (InputData->MakeCode) {
+                       case 0x1d:
+                               Value = RIGHT_CTRL_PRESSED;
+                               break;
+
+                       case 0x38:
+                               Value = RIGHT_ALT_PRESSED;
+                               break;
+
+                       default:
+                               return;
+               }
+       }
+
+       if (InputData->Flags & KEY_BREAK)
+               *State &= ~Value;
+       else
+               *State |= Value;
+}
+
+static DWORD
+IntVKFromKbdInput(PKEYBOARD_INPUT_DATA InputData, DWORD KeyState)
+{
+       if (!(KeyState & ENHANCED_KEY)) {
+               DPRINT("Not enhanced, using %x\n", InputData->MakeCode & 0x7f);
+               return KeyTable[InputData->MakeCode & 0x7f];
+       }
+
+       DPRINT("Enhanced, using %x\n", InputData->MakeCode & 0x7f);
+       return KeyTableEnhanced[InputData->MakeCode & 0x7f];
+}
+
+static UCHAR
+IntAsciiFromInput(PKEYBOARD_INPUT_DATA InputData, DWORD KeyState)
+{
+       UINT Counter = 0;
+       USHORT Enhanced = 0;
+
+       if (KeyState & ENHANCED_KEY) Enhanced = 1;
+
+       while (ScanToAscii[Counter].ScanCode != 0) {
+               if ((ScanToAscii[Counter].ScanCode == InputData->MakeCode)  &&
+                   (ScanToAscii[Counter].Enhanced == Enhanced)) {
+                       if (ScanToAscii[Counter].NumLock) {
+                               if ((KeyState & NUMLOCK_ON) &&
+                                   !(KeyState & SHIFT_PRESSED)) {
+                                       return ScanToAscii[Counter].NumLock;
+                               } else {
+                                       return ScanToAscii[Counter].Normal;
+                               }
+                       }
+                       if (KeyState & SHIFT_PRESSED)
+                               return ScanToAscii[Counter].Shift;
+
+                       return ScanToAscii[Counter].Normal;
+               }
+               Counter++;
+       }
+
+       return 0;
+}
+
+/* This is going to be quick and messy. The usetup app runs in native mode
+ * so it cannot use the translation routines in win32k which means it'll have
+ * to be done here too.
+ *
+ * Only the bKeyDown, AsciiChar and wVirtualKeyCode members are used
+ * in the app so I'll just fill the others with somewhat sane values
+ */
+NTSTATUS
+IntTranslateKey(PKEYBOARD_INPUT_DATA InputData, KEY_EVENT_RECORD *Event)
+{
+       static DWORD dwControlKeyState;
+
+       RtlZeroMemory(Event, sizeof(KEY_EVENT_RECORD));
+
+       if (!(InputData->Flags & KEY_BREAK))
+               Event->bKeyDown = TRUE;
+       else
+               Event->bKeyDown = FALSE;
+
+       Event->wRepeatCount = 1;
+       Event->wVirtualScanCode = InputData->MakeCode;
+
+       DPRINT("Translating: %x\n", InputData->MakeCode);
+
+       IntUpdateControlKeyState(&dwControlKeyState, InputData);
+       Event->dwControlKeyState = dwControlKeyState;
+
+       if (InputData->Flags & KEY_E0)
+               Event->dwControlKeyState |= ENHANCED_KEY;
+
+       Event->wVirtualKeyCode = IntVKFromKbdInput(InputData,
+                                                  Event->dwControlKeyState);
+
+       DPRINT("Result: %x\n", Event->wVirtualKeyCode);
+
+       if (Event->bKeyDown) {
+               Event->uChar.AsciiChar =
+                                  IntAsciiFromInput(InputData,
+                                                    Event->dwControlKeyState);
+               DPRINT("Char: %x\n", Event->uChar.AsciiChar);
+       } else {
+               Event->uChar.AsciiChar = 0;
+       }
+
+       return STATUS_SUCCESS;
+}
diff --git a/reactos/subsys/system/usetup/keytrans.h b/reactos/subsys/system/usetup/keytrans.h
new file mode 100644 (file)
index 0000000..61a757e
--- /dev/null
@@ -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 */
index a51941e..daa9158 100644 (file)
@@ -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
index ef6e005..948f61d 100644 (file)
@@ -58,6 +58,7 @@ EngDeviceIoControl(HANDLE  hDevice,
                                      nInBufferSize,
                                      lpOutBuffer,
                                      nOutBufferSize, FALSE, &Event, &Iosb);
+    DPRINT1("IRP: %x\n", Irp);
 
   Status = IoCallDriver(DeviceObject, Irp);
 
index 88634b7..9ef987f 100644 (file)
@@ -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 */
index 15374e5..5775b16 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <w32k.h>
 #include <rosrtl/string.h>
+#include <ddk/ntddkbd.h>
 
 /* 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 (fsModifiers)
+           {
+             if (KeyInput.Flags & KEY_BREAK)
+               {
+                 ModifierState &= ~fsModifiers;
+               }
+             else
+               {
+                 ModifierState |= fsModifiers;
 
-         if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
-           fsModifiers |= MOD_CONTROL;
+                 if (ModifierState == fsModifiers &&
+                     (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
+                   {
+                     /* First send out special notifications 
+                      * (For alt, the message that turns on accelerator
+                      * display, not sure what for win. Both TODO though.)
+                      */
 
-         if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
-           fsModifiers |= MOD_SHIFT;
+                     /* Read the next key before sending this one */
+                     do
+                       {
+                         Status = NtReadFile (KeyboardDeviceHandle,
+                                              NULL,
+                                              NULL,
+                                              NULL,
+                                              &Iosb,
+                                              &NextKeyInput,
+                                              sizeof(KEYBOARD_INPUT_DATA),
+                                              NULL,
+                                              NULL);
+                         DPRINT("KeyRaw: %s %04x\n",
+                                (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
+                                NextKeyInput.MakeCode );
 
-         /* FIXME: Support MOD_WIN */
+                         if (Status == STATUS_ALERTED && !InputThreadsRunning)
+                           goto KeyboardEscape;
 
-         lParam = KeyEvent.wRepeatCount | 
-           ((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
-         
-         /* Bit 24 indicates if this is an extended key */
-         if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
-           {
-             lParam |= (1 << 24);
-           }
-         
-         if (fsModifiers & MOD_ALT)
-           {
-             /* Context mode. 1 if ALT if pressed while the key is pressed */
-             lParam |= (1 << 29);
-           }
+                       } while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
+                                NextKeyInput.MakeCode == KeyInput.MakeCode);
+                     /* ^ Ignore repeats, they'll be KEY_MAKE and the same
+                      *   code. I'm not caring about the counting, not sure
+                      *   if that matters. I think not.
+                      */
 
-         if (! KeyEvent.bKeyDown)
-           {
-             /* Transition state. 1 for KEY_UP etc, 0 for KEY_DOWN */
-             lParam |= (1 << 31);
-           }
-         
-         if (GetHotKey(InputWindowStation,
-                       fsModifiers,
-                       KeyEvent.wVirtualKeyCode,
-                       &Thread,
-                       &hWnd,
-                       &id))
-           {
-             if (KeyEvent.bKeyDown)
-               {
-                 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
-                 MsqPostHotKeyMessage (Thread,
-                                       hWnd,
-                                       (WPARAM)id,
-                                       MAKELPARAM((WORD)fsModifiers, 
-                                                  (WORD)msg.wParam));
+                     /* If the ModifierState is now empty again, send a
+                      * special notification and eat both keypresses
+                      */
+
+                     fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
+
+                     if (fsNextModifiers)
+                       ModifierState ^= fsNextModifiers;
+
+                     if (ModifierState == 0)
+                       {
+                         if (fsModifiers == MOD_WIN)
+                           IntKeyboardSendWinKeyMsg();
+                         else if (fsModifiers == MOD_ALT)
+                           IntKeyboardSendAltKeyMsg();
+                         continue;
+                       }
+
+                     NumKeys = 2;
+                   }
                }
-             continue; 
            }
 
-         /* Find the target thread whose locale is in effect */
-         if (!IntGetScreenDC())
-           {
-             FocusQueue = W32kGetPrimitiveMessageQueue();
-           }
-         else
+         for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
+                       NumKeys--)
            {
-             FocusQueue = IntGetFocusMessageQueue();
-           }
+             lParam = 0;
 
-         if (!FocusQueue) continue;
+             IntKeyboardUpdateLeds(KeyboardDeviceHandle,
+                                   &KeyInput,
+                                   IndicatorTrans);
 
-         if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT)) 
-           msg.message = WM_SYSKEYDOWN;
-         else if(KeyEvent.bKeyDown)
-           msg.message = WM_KEYDOWN;
-         else if(fsModifiers & MOD_ALT)
-           msg.message = WM_SYSKEYUP;
-         else
-           msg.message = WM_KEYUP;
+         /* While we are working, we set up lParam. The format is:
+          *  0-15: The number of times this key has autorepeated
+          * 16-23: The keyboard scancode
+          *    24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
+          *        Note that E1 is only used for PAUSE (E1-1D-45) and
+          *        E0-45 happens not to be anything.
+          *    29: Alt is pressed ('Context code')
+          *    30: Previous state, if the key was down before this message
+          *        This is a cheap way to ignore autorepeat keys
+          *    31: 1 if the key is being pressed
+          */
 
-         msg.wParam = KeyEvent.wVirtualKeyCode;
-         msg.lParam = lParam;
-         msg.hwnd = FocusQueue->FocusWindow;
+         /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
+          * and it's the same key as the last one, increase the repeat
+          * count.
+          */
 
-         FocusThread = FocusQueue->Thread;
+             if (!(KeyInput.Flags & KEY_BREAK))
+               {
+                 if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
+                     (KeyInput.MakeCode == LastMakeCode))
+                   {
+                     RepeatCount++;
+                     lParam |= (1 << 30);
+                   }
+                 else
+                   {
+                     RepeatCount = 0;
+                     LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
+                     LastMakeCode = KeyInput.MakeCode;
+                   }
+               }
+             else
+               {
+                 LastFlags = 0;
+                 LastMakeCode = 0; /* Should never match */
+                 lParam |= (1 << 30) | (1 << 31);
+               }
 
-         if (FocusThread && FocusThread->Tcb.Win32Thread &&
-             FocusThread->Tcb.Win32Thread->KeyboardLayout)
-           {
+             lParam |= RepeatCount;
+
+             lParam |= (KeyInput.MakeCode & 0xff) << 16;
+
+             if (KeyInput.Flags & (KEY_E0 | KEY_E1))
+                 lParam |= (1 << 24);
+
+             if (ModifierState & MOD_ALT)
+               {
+                 lParam |= (1 << 29);
+
+                 if (!(KeyInput.Flags & KEY_BREAK))
+                   msg.message = WM_SYSKEYDOWN;
+                 else
+                   msg.message = WM_SYSKEYUP;
+               }
+             else
+               {
+                 if (!(KeyInput.Flags & KEY_BREAK))
+                   msg.message = WM_KEYDOWN;
+                 else
+                   msg.message = WM_KEYUP;
+               }
+
+             /* Find the target thread whose locale is in effect */
+             if (!IntGetScreenDC())
+               FocusQueue = W32kGetPrimitiveMessageQueue();
+             else
+               FocusQueue = IntGetFocusMessageQueue();
+
+             /* This might cause us to lose hot keys, which are important
+              * (ctrl-alt-del secure attention sequence). Not sure if it
+              * can happen though.
+              */
+             if (!FocusQueue) continue;
+
+             msg.lParam = lParam;
+             msg.hwnd = FocusQueue->FocusWindow;
+
+             FocusThread = FocusQueue->Thread;
+
+             if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
+                   FocusThread->Tcb.Win32Thread->KeyboardLayout))
+               continue;
+
+             /* This function uses lParam to fill wParam according to the
+              * keyboard layout in use.
+              */
              W32kKeyProcessMessage(&msg,
                                    FocusThread->Tcb.Win32Thread->KeyboardLayout);
-           } 
-         else
-           continue;
+
+             if (GetHotKey(InputWindowStation,
+                           ModifierState,
+                           msg.wParam,
+                           &Thread,
+                           &hWnd,
+                           &id))
+               {
+                 if (KeyEvent.bKeyDown)
+                   {
+                     DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
+                     MsqPostHotKeyMessage (Thread,
+                                           hWnd,
+                                           (WPARAM)id,
+                                           MAKELPARAM((WORD)ModifierState, 
+                                                      (WORD)msg.wParam));
+                   }
+                 continue;     /* Eat key up motion too */
+               }
          
-         /*
-          * Post a keyboard message.
-          */
-         MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
+             /*
+              * Post a keyboard message.
+              */
+             MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
+           } 
        }
+
+KeyboardEscape:
       DPRINT( "KeyboardInput Thread Stopped...\n" );
     }
 }
 
-
 NTSTATUS STDCALL
 NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
 {
index 625eedf..bf818f6 100644 (file)
@@ -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
index 5e4af89..08e8806 100644 (file)
@@ -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;