i8042prt driver by tinus.
Modified: trunk/reactos/Makefile
Modified: trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c
Modified: trunk/reactos/bootdata/hivesys.inf
Modified: trunk/reactos/bootdata/txtsetup.sif
Modified: trunk/reactos/drivers/input/Makefile
Added: trunk/reactos/drivers/input/i8042prt/
Added: trunk/reactos/drivers/input/i8042prt/README.txt
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.c
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.h
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.rc
Added: trunk/reactos/drivers/input/i8042prt/keyboard.c
Added: trunk/reactos/drivers/input/i8042prt/makefile
Added: trunk/reactos/drivers/input/i8042prt/mouse.c
Added: trunk/reactos/drivers/input/i8042prt/ps2pp.c
Added: trunk/reactos/drivers/input/i8042prt/registry.c
Added: trunk/reactos/drivers/input/kbdclass/
Added: trunk/reactos/drivers/input/kbdclass/kbdclass.c
Added: trunk/reactos/drivers/input/kbdclass/kbdclass.h
Added: trunk/reactos/drivers/input/kbdclass/kbdclass.rc
Added: trunk/reactos/drivers/input/kbdclass/makefile
Modified: trunk/reactos/drivers/input/mouclass/mouclass.c
Modified: trunk/reactos/include/ddk/ntdd8042.h
Modified: trunk/reactos/ntoskrnl/include/internal/kd.h
Modified: trunk/reactos/subsys/system/usetup/bootsup.c
Modified: trunk/reactos/subsys/system/usetup/console.c
Added: trunk/reactos/subsys/system/usetup/keytrans.c
Added: trunk/reactos/subsys/system/usetup/keytrans.h
Modified: trunk/reactos/subsys/system/usetup/makefile
Modified: trunk/reactos/subsys/win32k/eng/device.c
Modified: trunk/reactos/subsys/win32k/include/tags.h
Modified: trunk/reactos/subsys/win32k/ntuser/input.c
Modified: trunk/reactos/tools/helper.mk
Modified: trunk/reactos/w32api/include/ddk/winddk.h
_____
Modified: trunk/reactos/Makefile
--- trunk/reactos/Makefile 2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/Makefile 2005-05-01 20:38:29 UTC (rev 14926)
@@ -84,7 +84,7 @@
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
_____
Modified: trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c
--- trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c
2005-05-01 20:30:41 UTC (rev 14925)
+++ trunk/reactos/boot/freeldr/freeldr/reactos/setupldr.c
2005-05-01 20:38:29 UTC (rev 14926)
@@ -558,8 +558,14 @@
/* 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"))
_____
Modified: trunk/reactos/bootdata/hivesys.inf
--- trunk/reactos/bootdata/hivesys.inf 2005-05-01 20:30:41 UTC (rev
14925)
+++ trunk/reactos/bootdata/hivesys.inf 2005-05-01 20:38:29 UTC (rev
14926)
@@ -575,12 +575,29 @@
;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x000000
01
; Keyboard driver
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x0001
0001,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"K
eyboard Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x0002000
0,"system32\drivers\keyboard.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x
00000001
-HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x0
0000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x000
10001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"
Keyboard Port"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x000200
00,"system32\drivers\keyboard.sys"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0
x00000001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x
00000001
+; i8042 port driver
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","ErrorControl",0x0001
0001,0x00000000
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Group",0x00000000,"K
eyboard Port"
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","ImagePath",0x0002000
0,"system32\drivers\i8042prt.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Start",0x00010001,0x
00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Type",0x00010001,0x0
0000001
+
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","SampleRat
e",0x00010001,0x00000060
+HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","BreakOnSy
sRq",0x00010001,0x00000001
+
+; Keyboard class driver
+HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ErrorControl",0x0001
0001,0x00000000
+HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Group",0x00000000,"K
eyboard Class"
+HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ImagePath",0x0002000
0,"system32\drivers\kbdclass.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Start",0x00010001,0x
00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Type",0x00010001,0x0
0000001
+
; Serial port enumerator
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x000100
01,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Group",0x00000000,"PNP
Filter"
@@ -840,12 +857,12 @@
HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Type",0x00010001,0x00
000010
; PS/2 mouse port driver
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x0001000
1,0x00000000
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Poin
ter Port"
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"
system32\drivers\psaux.sys"
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x000
00004
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x0000
0001
-HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExten
sionDetection",0x00010001,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x000100
01,0x00000000
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Poi
nter Port"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,
"system32\drivers\psaux.sys"
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00
000004
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x000
00001
+;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExte
nsionDetection",0x00010001,0x00000000
; RPC service
HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001
,0x00000001
_____
Modified: trunk/reactos/bootdata/txtsetup.sif
--- trunk/reactos/bootdata/txtsetup.sif 2005-05-01 20:30:41 UTC (rev
14925)
+++ trunk/reactos/bootdata/txtsetup.sif 2005-05-01 20:38:29 UTC (rev
14926)
@@ -22,7 +22,9 @@
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 @@
[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"
_____
Modified: trunk/reactos/drivers/input/Makefile
--- trunk/reactos/drivers/input/Makefile 2005-05-01 20:30:41 UTC
(rev 14925)
+++ trunk/reactos/drivers/input/Makefile 2005-05-01 20:38:29 UTC
(rev 14926)
@@ -6,7 +6,7 @@
include $(PATH_TO_TOP)/rules.mak
-DRIVERS = keyboard mouclass psaux sermouse
+DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
all: $(DRIVERS)
_____
Added: trunk/reactos/drivers/input/i8042prt/README.txt
--- trunk/reactos/drivers/input/i8042prt/README.txt 2005-05-01
20:30:41 UTC (rev 14925)
+++ trunk/reactos/drivers/input/i8042prt/README.txt 2005-05-01
20:38:29 UTC (rev 14926)
@@ -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/re
skit/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.
_____
Added: trunk/reactos/drivers/input/i8042prt/i8042prt.c
--- trunk/reactos/drivers/input/i8042prt/i8042prt.c 2005-05-01
20:30:41 UTC (rev 14925)
+++ trunk/reactos/drivers/input/i8042prt/i8042prt.c 2005-05-01
20:38:29 UTC (rev 14926)
@@ -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(a)iname.com)
+ * Jason Filby (jasonfilby(a)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,
[truncated at 1000 lines; 4079 more skipped]