mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
i8042prt driver by tinus.
svn path=/trunk/; revision=14926
This commit is contained in:
parent
82b7f31f61
commit
a70444fab1
31 changed files with 4527 additions and 142 deletions
|
@ -84,7 +84,7 @@ DRIVERS_LIB = bzip2 oskittcp ip csq
|
||||||
DEVICE_DRIVERS = beep blue debugout null serial bootvid
|
DEVICE_DRIVERS = beep blue debugout null serial bootvid
|
||||||
|
|
||||||
# Kernel mode input drivers
|
# Kernel mode input drivers
|
||||||
INPUT_DRIVERS = keyboard mouclass psaux sermouse
|
INPUT_DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
|
||||||
|
|
||||||
# Kernel mode file system drivers
|
# Kernel mode file system drivers
|
||||||
# cdfs ext2 fs_rec ms np vfat
|
# cdfs ext2 fs_rec ms np vfat
|
||||||
|
|
|
@ -558,8 +558,14 @@ for(;;);
|
||||||
|
|
||||||
|
|
||||||
/* Load keyboard driver */
|
/* Load keyboard driver */
|
||||||
|
#if 0
|
||||||
if (!LoadDriver(SourcePath, "keyboard.sys"))
|
if (!LoadDriver(SourcePath, "keyboard.sys"))
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
if (!LoadDriver(SourcePath, "i8042prt.sys"))
|
||||||
|
return;
|
||||||
|
if (!LoadDriver(SourcePath, "kbdclass.sys"))
|
||||||
|
return;
|
||||||
|
|
||||||
/* Load screen driver */
|
/* Load screen driver */
|
||||||
if (!LoadDriver(SourcePath, "blue.sys"))
|
if (!LoadDriver(SourcePath, "blue.sys"))
|
||||||
|
|
|
@ -575,11 +575,28 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Type",0x00010001,0x00000008
|
||||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x00000001
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x00000001
|
||||||
|
|
||||||
; Keyboard driver
|
; Keyboard driver
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
|
;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","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",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
|
; Serial port enumerator
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
|
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
|
HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Type",0x00010001,0x00000010
|
||||||
|
|
||||||
; PS/2 mouse port driver
|
; PS/2 mouse port driver
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
|
;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","ImagePath",0x00020000,"system32\drivers\psaux.sys"
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
|
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
|
||||||
|
|
||||||
; RPC service
|
; RPC service
|
||||||
HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001,0x00000001
|
HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001,0x00000001
|
||||||
|
|
|
@ -22,7 +22,9 @@ cdrom.sys = 3
|
||||||
class2.sys = 3
|
class2.sys = 3
|
||||||
disk.sys = 3
|
disk.sys = 3
|
||||||
floppy.sys = 3
|
floppy.sys = 3
|
||||||
keyboard.sys = 3
|
;keyboard.sys = 3
|
||||||
|
i8042prt.sys = 3
|
||||||
|
kbdclass.sys = 3
|
||||||
l_intl.nls = 2
|
l_intl.nls = 2
|
||||||
ntfs.sys = 3
|
ntfs.sys = 3
|
||||||
ntoskrnl.exe = 2
|
ntoskrnl.exe = 2
|
||||||
|
@ -96,14 +98,16 @@ Default = "XT-, AT- or extended keyboard (83-105 keys)"
|
||||||
|
|
||||||
[Mouse]
|
[Mouse]
|
||||||
;<id> = <user friendly name>,<spare>,<service key name>
|
;<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
|
msser = "Microsoft Serial Mouse",,sermouse
|
||||||
mswhs = "Microsoft Serial Wheel Mouse",,sermouse
|
mswhs = "Microsoft Serial Wheel Mouse",,sermouse
|
||||||
none = "No Mouse"
|
none = "No Mouse"
|
||||||
|
|
||||||
[Map.Mouse]
|
[Map.Mouse]
|
||||||
;<id> = <pnp id string>
|
;<id> = <pnp id string>
|
||||||
msps2 = "MICROSOFT PS2 MOUSE"
|
i8042ps2 = "MICROSOFT PS2 MOUSE"
|
||||||
|
;msps2 = "MICROSOFT PS2 MOUSE"
|
||||||
msser = "MICROSOFT SERIAL MOUSE"
|
msser = "MICROSOFT SERIAL MOUSE"
|
||||||
mswhs = "MICROSOFT MOUSE WITH WHEEL"
|
mswhs = "MICROSOFT MOUSE WITH WHEEL"
|
||||||
none = "NO MOUSE"
|
none = "NO MOUSE"
|
||||||
|
|
|
@ -6,7 +6,7 @@ PATH_TO_TOP = ../..
|
||||||
|
|
||||||
include $(PATH_TO_TOP)/rules.mak
|
include $(PATH_TO_TOP)/rules.mak
|
||||||
|
|
||||||
DRIVERS = keyboard mouclass psaux sermouse
|
DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
|
||||||
|
|
||||||
all: $(DRIVERS)
|
all: $(DRIVERS)
|
||||||
|
|
||||||
|
|
83
reactos/drivers/input/i8042prt/README.txt
Normal file
83
reactos/drivers/input/i8042prt/README.txt
Normal file
|
@ -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.
|
804
reactos/drivers/input/i8042prt/i8042prt.c
Normal file
804
reactos/drivers/input/i8042prt/i8042prt.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
392
reactos/drivers/input/i8042prt/i8042prt.h
Normal file
392
reactos/drivers/input/i8042prt/i8042prt.h
Normal file
|
@ -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_
|
5
reactos/drivers/input/i8042prt/i8042prt.rc
Normal file
5
reactos/drivers/input/i8042prt/i8042prt.rc
Normal file
|
@ -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>
|
701
reactos/drivers/input/i8042prt/keyboard.c
Normal file
701
reactos/drivers/input/i8042prt/keyboard.c
Normal file
|
@ -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);
|
||||||
|
}
|
17
reactos/drivers/input/i8042prt/makefile
Normal file
17
reactos/drivers/input/i8042prt/makefile
Normal file
|
@ -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
|
865
reactos/drivers/input/i8042prt/mouse.c
Normal file
865
reactos/drivers/input/i8042prt/mouse.c
Normal file
|
@ -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;
|
||||||
|
}
|
140
reactos/drivers/input/i8042prt/ps2pp.c
Normal file
140
reactos/drivers/input/i8042prt/ps2pp.c
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
237
reactos/drivers/input/i8042prt/registry.c
Normal file
237
reactos/drivers/input/i8042prt/registry.c
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
|
306
reactos/drivers/input/kbdclass/kbdclass.c
Normal file
306
reactos/drivers/input/kbdclass/kbdclass.c
Normal file
|
@ -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);
|
||||||
|
}
|
98
reactos/drivers/input/kbdclass/kbdclass.h
Normal file
98
reactos/drivers/input/kbdclass/kbdclass.h
Normal file
|
@ -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_
|
7
reactos/drivers/input/kbdclass/kbdclass.rc
Normal file
7
reactos/drivers/input/kbdclass/kbdclass.rc
Normal file
|
@ -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>
|
17
reactos/drivers/input/kbdclass/makefile
Normal file
17
reactos/drivers/input/kbdclass/makefile
Normal file
|
@ -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
|
|
@ -21,17 +21,22 @@
|
||||||
|
|
||||||
BOOLEAN MouseClassCallBack(
|
BOOLEAN MouseClassCallBack(
|
||||||
PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
|
PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
|
||||||
PMOUSE_INPUT_DATA MouseDataEnd, PULONG InputCount)
|
PMOUSE_INPUT_DATA MouseDataEnd, PULONG ConsumedCount)
|
||||||
{
|
{
|
||||||
PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
||||||
PIRP Irp;
|
PIRP Irp;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
PIO_STACK_LOCATION Stack;
|
PIO_STACK_LOCATION Stack;
|
||||||
ULONG SafeInputCount = *InputCount;
|
ULONG InputCount = MouseDataEnd - MouseDataStart;
|
||||||
ULONG ReadSize;
|
ULONG ReadSize;
|
||||||
|
|
||||||
DPRINT("Entering MouseClassCallBack\n");
|
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;
|
Irp = ClassDeviceObject->CurrentIrp;
|
||||||
ClassDeviceObject->CurrentIrp = NULL;
|
ClassDeviceObject->CurrentIrp = NULL;
|
||||||
|
@ -52,19 +57,20 @@ BOOLEAN MouseClassCallBack(
|
||||||
|
|
||||||
/* Skip the packet we just sent away */
|
/* Skip the packet we just sent away */
|
||||||
MouseDataStart++;
|
MouseDataStart++;
|
||||||
SafeInputCount--;
|
(*ConsumedCount)++;
|
||||||
|
InputCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we have data from the port driver and a higher service to send the data to */
|
/* 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);
|
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
|
||||||
|
|
||||||
if (ClassDeviceExtension->InputCount + SafeInputCount > MOUSE_BUFFER_SIZE)
|
if (ClassDeviceExtension->InputCount + InputCount > MOUSE_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
|
ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
|
||||||
} else {
|
} else {
|
||||||
ReadSize = SafeInputCount;
|
ReadSize = InputCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -84,6 +90,7 @@ BOOLEAN MouseClassCallBack(
|
||||||
ClassDeviceExtension->InputCount += ReadSize;
|
ClassDeviceExtension->InputCount += ReadSize;
|
||||||
|
|
||||||
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
|
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
|
||||||
|
(*ConsumedCount) += ReadSize;
|
||||||
} else {
|
} else {
|
||||||
DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount);
|
DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,18 +204,18 @@ typedef struct _INTERNAL_I8042_HOOK_KEYBOARD {
|
||||||
//
|
//
|
||||||
// Write function
|
// 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)
|
// Queue the current packet (ie the one passed into the isr callback hook)
|
||||||
// to be reported to the class driver
|
// to be reported to the class driver
|
||||||
//
|
//
|
||||||
//UNIMPLEMENTED IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
|
IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Context for IsrWritePort, QueueKeyboardPacket
|
// Context for IsrWritePort, QueueKeyboardPacket
|
||||||
//
|
//
|
||||||
//UNIMPLEMENTED IN PVOID CallContext;
|
IN PVOID CallContext;
|
||||||
|
|
||||||
} INTERNAL_I8042_HOOK_KEYBOARD, *PINTERNAL_I8042_HOOK_KEYBOARD;
|
} INTERNAL_I8042_HOOK_KEYBOARD, *PINTERNAL_I8042_HOOK_KEYBOARD;
|
||||||
|
|
||||||
|
|
|
@ -203,17 +203,17 @@ typedef struct _KDP_DEBUG_MODE
|
||||||
/* KD Internal Debug Services */
|
/* KD Internal Debug Services */
|
||||||
typedef enum _KDP_DEBUG_SERVICE
|
typedef enum _KDP_DEBUG_SERVICE
|
||||||
{
|
{
|
||||||
DumpNonPagedPool = 0,
|
DumpNonPagedPool = 0x1e, /* a */
|
||||||
ManualBugCheck,
|
ManualBugCheck = 0x30, /* b */
|
||||||
DumpNonPagedPoolStats,
|
DumpNonPagedPoolStats = 0x2e, /* c */
|
||||||
DumpNewNonPagedPool,
|
DumpNewNonPagedPool = 0x20, /* d */
|
||||||
DumpNewNonPagedPoolStats,
|
DumpNewNonPagedPoolStats = 0x12, /* e */
|
||||||
DumpAllThreads,
|
DumpAllThreads = 0x21, /* f */
|
||||||
DumpUserThreads,
|
DumpUserThreads = 0x22, /* g */
|
||||||
KdSpare1,
|
KdSpare1 = 0x23, /* h */
|
||||||
KdSpare2,
|
KdSpare2 = 0x17, /* i */
|
||||||
KdSpare3,
|
KdSpare3 = 0x24, /* j */
|
||||||
EnterDebugger
|
EnterDebugger = 0x25 /* k */
|
||||||
} KDP_DEBUG_SERVICE;
|
} KDP_DEBUG_SERVICE;
|
||||||
|
|
||||||
/* Dispatch Table for Wrapper Functions */
|
/* Dispatch Table for Wrapper Functions */
|
||||||
|
|
|
@ -371,7 +371,7 @@ CreateFreeLoaderIniForReactos(PWCHAR IniPath,
|
||||||
NULL,
|
NULL,
|
||||||
INSERT_LAST,
|
INSERT_LAST,
|
||||||
L"Options",
|
L"Options",
|
||||||
L"/DEBUGPORT=SCREEN /NOGUIBOOT");
|
L"/DEBUGPORT=COM1 /NOGUIBOOT");
|
||||||
|
|
||||||
/* Save the ini file */
|
/* Save the ini file */
|
||||||
IniCacheSave(IniCache, IniPath);
|
IniCacheSave(IniCache, IniPath);
|
||||||
|
|
|
@ -28,9 +28,11 @@
|
||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
#include <ddk/ntddblue.h>
|
#include <ddk/ntddblue.h>
|
||||||
|
#include <ddk/ntddkbd.h>
|
||||||
|
|
||||||
#include "usetup.h"
|
#include "usetup.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "keytrans.h"
|
||||||
|
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
@ -194,6 +196,7 @@ ReadConsoleInput(PINPUT_RECORD Buffer)
|
||||||
{
|
{
|
||||||
IO_STATUS_BLOCK Iosb;
|
IO_STATUS_BLOCK Iosb;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
KEYBOARD_INPUT_DATA InputData;
|
||||||
|
|
||||||
Buffer->EventType = KEY_EVENT;
|
Buffer->EventType = KEY_EVENT;
|
||||||
Status = NtReadFile(StdInput,
|
Status = NtReadFile(StdInput,
|
||||||
|
@ -201,11 +204,17 @@ ReadConsoleInput(PINPUT_RECORD Buffer)
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&Iosb,
|
&Iosb,
|
||||||
&Buffer->Event.KeyEvent,
|
&InputData,
|
||||||
|
// &Buffer->Event.KeyEvent,
|
||||||
sizeof(KEY_EVENT_RECORD),
|
sizeof(KEY_EVENT_RECORD),
|
||||||
NULL,
|
NULL,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = IntTranslateKey(&InputData, &Buffer->Event.KeyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
return(Status);
|
return(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
342
reactos/subsys/system/usetup/keytrans.c
Normal file
342
reactos/subsys/system/usetup/keytrans.c
Normal file
|
@ -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;
|
||||||
|
}
|
35
reactos/subsys/system/usetup/keytrans.h
Normal file
35
reactos/subsys/system/usetup/keytrans.h
Normal file
|
@ -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 */
|
|
@ -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 \
|
TARGET_OBJECTS = bootsup.o cabinet.o console.o drivesup.o filequeue.o \
|
||||||
filesup.o format.o fslist.o genlist.o infcache.o \
|
filesup.o format.o fslist.o genlist.o infcache.o \
|
||||||
inicache.o partlist.o progress.o registry.o settings.o \
|
inicache.o partlist.o progress.o registry.o settings.o \
|
||||||
usetup.o
|
usetup.o keytrans.o
|
||||||
|
|
||||||
include $(PATH_TO_TOP)/rules.mak
|
include $(PATH_TO_TOP)/rules.mak
|
||||||
|
|
||||||
include $(TOOLS_PATH)/helper.mk
|
include $(TOOLS_PATH)/helper.mk
|
||||||
|
|
||||||
# EOF
|
# EOF
|
||||||
|
|
|
@ -58,6 +58,7 @@ EngDeviceIoControl(HANDLE hDevice,
|
||||||
nInBufferSize,
|
nInBufferSize,
|
||||||
lpOutBuffer,
|
lpOutBuffer,
|
||||||
nOutBufferSize, FALSE, &Event, &Iosb);
|
nOutBufferSize, FALSE, &Event, &Iosb);
|
||||||
|
DPRINT1("IRP: %x\n", Irp);
|
||||||
|
|
||||||
Status = IoCallDriver(DeviceObject, Irp);
|
Status = IoCallDriver(DeviceObject, Irp);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
/* ntuser */
|
/* ntuser */
|
||||||
#define TAG_MOUSE TAG('M', 'O', 'U', 'S') /* mouse */
|
#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_ACCEL TAG('A', 'C', 'C', 'L') /* accelerator */
|
||||||
#define TAG_HOOK TAG('W', 'N', 'H', 'K') /* hook */
|
#define TAG_HOOK TAG('W', 'N', 'H', 'K') /* hook */
|
||||||
#define TAG_HOTKEY TAG('H', 'O', 'T', 'K') /* hotkey */
|
#define TAG_HOTKEY TAG('H', 'O', 'T', 'K') /* hotkey */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <w32k.h>
|
#include <w32k.h>
|
||||||
#include <rosrtl/string.h>
|
#include <rosrtl/string.h>
|
||||||
|
#include <ddk/ntddkbd.h>
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* 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
|
STATIC VOID STDCALL
|
||||||
KeyboardThreadMain(PVOID StartContext)
|
KeyboardThreadMain(PVOID StartContext)
|
||||||
{
|
{
|
||||||
|
@ -229,6 +409,12 @@ KeyboardThreadMain(PVOID StartContext)
|
||||||
MSG msg;
|
MSG msg;
|
||||||
PUSER_MESSAGE_QUEUE FocusQueue;
|
PUSER_MESSAGE_QUEUE FocusQueue;
|
||||||
struct _ETHREAD *FocusThread;
|
struct _ETHREAD *FocusThread;
|
||||||
|
|
||||||
|
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
|
||||||
|
UINT ModifierState = 0;
|
||||||
|
USHORT LastMakeCode = 0;
|
||||||
|
USHORT LastFlags = 0;
|
||||||
|
UINT RepeatCount = 0;
|
||||||
|
|
||||||
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
|
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
|
||||||
InitializeObjectAttributes(&KeyboardObjectAttributes,
|
InitializeObjectAttributes(&KeyboardObjectAttributes,
|
||||||
|
@ -248,6 +434,9 @@ KeyboardThreadMain(PVOID StartContext)
|
||||||
return; //(Status);
|
return; //(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
|
||||||
|
&IndicatorTrans);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -267,8 +456,11 @@ KeyboardThreadMain(PVOID StartContext)
|
||||||
while (InputThreadsRunning)
|
while (InputThreadsRunning)
|
||||||
{
|
{
|
||||||
KEY_EVENT_RECORD KeyEvent;
|
KEY_EVENT_RECORD KeyEvent;
|
||||||
|
BOOLEAN NumKeys = 1;
|
||||||
|
KEYBOARD_INPUT_DATA KeyInput;
|
||||||
|
KEYBOARD_INPUT_DATA NextKeyInput;
|
||||||
LPARAM lParam = 0;
|
LPARAM lParam = 0;
|
||||||
UINT fsModifiers;
|
UINT fsModifiers, fsNextModifiers;
|
||||||
struct _ETHREAD *Thread;
|
struct _ETHREAD *Thread;
|
||||||
HWND hWnd;
|
HWND hWnd;
|
||||||
int id;
|
int id;
|
||||||
|
@ -278,124 +470,223 @@ KeyboardThreadMain(PVOID StartContext)
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
&Iosb,
|
&Iosb,
|
||||||
&KeyEvent,
|
&KeyInput,
|
||||||
sizeof(KEY_EVENT_RECORD),
|
sizeof(KEYBOARD_INPUT_DATA),
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
DPRINT( "KeyRaw: %s %04x\n",
|
DPRINT("KeyRaw: %s %04x\n",
|
||||||
KeyEvent.bKeyDown ? "down" : "up",
|
(KeyInput.Flags & KEY_BREAK) ? "up" : "down",
|
||||||
KeyEvent.wVirtualScanCode );
|
KeyInput.MakeCode );
|
||||||
|
|
||||||
if (Status == STATUS_ALERTED && !InputThreadsRunning)
|
if (Status == STATUS_ALERTED && !InputThreadsRunning)
|
||||||
{
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("Win32K: Failed to read from keyboard.\n");
|
DPRINT1("Win32K: Failed to read from keyboard.\n");
|
||||||
return; //(Status);
|
return; //(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
|
/* Update modifier state */
|
||||||
|
fsModifiers = IntKeyboardGetModifiers(&KeyInput);
|
||||||
|
|
||||||
fsModifiers = 0;
|
if (fsModifiers)
|
||||||
if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
|
|
||||||
fsModifiers |= MOD_ALT;
|
|
||||||
|
|
||||||
if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
|
|
||||||
fsModifiers |= MOD_CONTROL;
|
|
||||||
|
|
||||||
if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
|
|
||||||
fsModifiers |= MOD_SHIFT;
|
|
||||||
|
|
||||||
/* FIXME: Support MOD_WIN */
|
|
||||||
|
|
||||||
lParam = KeyEvent.wRepeatCount |
|
|
||||||
((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
|
|
||||||
|
|
||||||
/* Bit 24 indicates if this is an extended key */
|
|
||||||
if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
|
|
||||||
{
|
{
|
||||||
lParam |= (1 << 24);
|
if (KeyInput.Flags & KEY_BREAK)
|
||||||
}
|
|
||||||
|
|
||||||
if (fsModifiers & MOD_ALT)
|
|
||||||
{
|
|
||||||
/* Context mode. 1 if ALT if pressed while the key is pressed */
|
|
||||||
lParam |= (1 << 29);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! KeyEvent.bKeyDown)
|
|
||||||
{
|
|
||||||
/* Transition state. 1 for KEY_UP etc, 0 for KEY_DOWN */
|
|
||||||
lParam |= (1 << 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetHotKey(InputWindowStation,
|
|
||||||
fsModifiers,
|
|
||||||
KeyEvent.wVirtualKeyCode,
|
|
||||||
&Thread,
|
|
||||||
&hWnd,
|
|
||||||
&id))
|
|
||||||
{
|
|
||||||
if (KeyEvent.bKeyDown)
|
|
||||||
{
|
{
|
||||||
DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
|
ModifierState &= ~fsModifiers;
|
||||||
MsqPostHotKeyMessage (Thread,
|
}
|
||||||
hWnd,
|
else
|
||||||
(WPARAM)id,
|
{
|
||||||
MAKELPARAM((WORD)fsModifiers,
|
ModifierState |= fsModifiers;
|
||||||
(WORD)msg.wParam));
|
|
||||||
|
if (ModifierState == fsModifiers &&
|
||||||
|
(fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
|
||||||
|
{
|
||||||
|
/* First send out special notifications
|
||||||
|
* (For alt, the message that turns on accelerator
|
||||||
|
* display, not sure what for win. Both TODO though.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Read the next key before sending this one */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Status = NtReadFile (KeyboardDeviceHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&Iosb,
|
||||||
|
&NextKeyInput,
|
||||||
|
sizeof(KEYBOARD_INPUT_DATA),
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
DPRINT("KeyRaw: %s %04x\n",
|
||||||
|
(NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
|
||||||
|
NextKeyInput.MakeCode );
|
||||||
|
|
||||||
|
if (Status == STATUS_ALERTED && !InputThreadsRunning)
|
||||||
|
goto KeyboardEscape;
|
||||||
|
|
||||||
|
} while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
|
||||||
|
NextKeyInput.MakeCode == KeyInput.MakeCode);
|
||||||
|
/* ^ Ignore repeats, they'll be KEY_MAKE and the same
|
||||||
|
* code. I'm not caring about the counting, not sure
|
||||||
|
* if that matters. I think not.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* If the ModifierState is now empty again, send a
|
||||||
|
* special notification and eat both keypresses
|
||||||
|
*/
|
||||||
|
|
||||||
|
fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
|
||||||
|
|
||||||
|
if (fsNextModifiers)
|
||||||
|
ModifierState ^= fsNextModifiers;
|
||||||
|
|
||||||
|
if (ModifierState == 0)
|
||||||
|
{
|
||||||
|
if (fsModifiers == MOD_WIN)
|
||||||
|
IntKeyboardSendWinKeyMsg();
|
||||||
|
else if (fsModifiers == MOD_ALT)
|
||||||
|
IntKeyboardSendAltKeyMsg();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumKeys = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the target thread whose locale is in effect */
|
for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
|
||||||
if (!IntGetScreenDC())
|
NumKeys--)
|
||||||
{
|
{
|
||||||
FocusQueue = W32kGetPrimitiveMessageQueue();
|
lParam = 0;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FocusQueue = IntGetFocusMessageQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FocusQueue) continue;
|
IntKeyboardUpdateLeds(KeyboardDeviceHandle,
|
||||||
|
&KeyInput,
|
||||||
|
IndicatorTrans);
|
||||||
|
|
||||||
if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT))
|
/* While we are working, we set up lParam. The format is:
|
||||||
msg.message = WM_SYSKEYDOWN;
|
* 0-15: The number of times this key has autorepeated
|
||||||
else if(KeyEvent.bKeyDown)
|
* 16-23: The keyboard scancode
|
||||||
msg.message = WM_KEYDOWN;
|
* 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
|
||||||
else if(fsModifiers & MOD_ALT)
|
* Note that E1 is only used for PAUSE (E1-1D-45) and
|
||||||
msg.message = WM_SYSKEYUP;
|
* E0-45 happens not to be anything.
|
||||||
else
|
* 29: Alt is pressed ('Context code')
|
||||||
msg.message = WM_KEYUP;
|
* 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;
|
/* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
|
||||||
msg.lParam = lParam;
|
* and it's the same key as the last one, increase the repeat
|
||||||
msg.hwnd = FocusQueue->FocusWindow;
|
* 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 &&
|
lParam |= RepeatCount;
|
||||||
FocusThread->Tcb.Win32Thread->KeyboardLayout)
|
|
||||||
{
|
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,
|
W32kKeyProcessMessage(&msg,
|
||||||
FocusThread->Tcb.Win32Thread->KeyboardLayout);
|
FocusThread->Tcb.Win32Thread->KeyboardLayout);
|
||||||
}
|
|
||||||
else
|
if (GetHotKey(InputWindowStation,
|
||||||
continue;
|
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.
|
* Post a keyboard message.
|
||||||
*/
|
*/
|
||||||
MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
|
MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyboardEscape:
|
||||||
DPRINT( "KeyboardInput Thread Stopped...\n" );
|
DPRINT( "KeyboardInput Thread Stopped...\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
|
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
|
||||||
{
|
{
|
||||||
|
|
|
@ -683,10 +683,10 @@ ifneq ($(DBG),1)
|
||||||
MK_CFLAGS += -Os -Wno-strict-aliasing -ftracer -momit-leaf-frame-pointer
|
MK_CFLAGS += -Os -Wno-strict-aliasing -ftracer -momit-leaf-frame-pointer
|
||||||
MK_CFLAGS += -mpreferred-stack-boundary=2
|
MK_CFLAGS += -mpreferred-stack-boundary=2
|
||||||
|
|
||||||
CC_VERSION=$(word 1,$(shell gcc -dumpversion))
|
#CC_VERSION=$(word 1,$(shell gcc -dumpversion))
|
||||||
ifeq ($(CC_VERSION),3.4.3)
|
#ifeq ($(CC_VERSION),3.4.3)
|
||||||
MK_CFLAGS += -funit-at-a-time -fweb
|
MK_CFLAGS += -funit-at-a-time -fweb
|
||||||
endif
|
#endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# Remove Symbols if no debugging is used at all
|
# Remove Symbols if no debugging is used at all
|
||||||
|
|
|
@ -529,7 +529,7 @@ typedef VOID
|
||||||
IN PVOID Context,
|
IN PVOID Context,
|
||||||
IN ULONG Count);
|
IN ULONG Count);
|
||||||
|
|
||||||
typedef NTSTATUS
|
typedef VOID
|
||||||
(DDKAPI *PDRIVER_STARTIO)(
|
(DDKAPI *PDRIVER_STARTIO)(
|
||||||
IN struct _DEVICE_OBJECT *DeviceObject,
|
IN struct _DEVICE_OBJECT *DeviceObject,
|
||||||
IN struct _IRP *Irp);
|
IN struct _IRP *Irp);
|
||||||
|
@ -1432,14 +1432,14 @@ typedef struct _CM_KEYBOARD_DEVICE_DATA {
|
||||||
USHORT KeyboardFlags;
|
USHORT KeyboardFlags;
|
||||||
} CM_KEYBOARD_DEVICE_DATA, *PCM_KEYBOARD_DEVICE_DATA;
|
} CM_KEYBOARD_DEVICE_DATA, *PCM_KEYBOARD_DEVICE_DATA;
|
||||||
|
|
||||||
#define KEYBOARD_INSERT_ON 0x80
|
#define KEYBOARD_INSERT_ON 0x08
|
||||||
#define KEYBOARD_CAPS_LOCK_ON 0x40
|
#define KEYBOARD_CAPS_LOCK_ON 0x04
|
||||||
#define KEYBOARD_NUM_LOCK_ON 0x20
|
#define KEYBOARD_NUM_LOCK_ON 0x02
|
||||||
#define KEYBOARD_SCROLL_LOCK_ON 0x10
|
#define KEYBOARD_SCROLL_LOCK_ON 0x01
|
||||||
#define KEYBOARD_ALT_KEY_DOWN 0x08
|
#define KEYBOARD_ALT_KEY_DOWN 0x80
|
||||||
#define KEYBOARD_CTRL_KEY_DOWN 0x04
|
#define KEYBOARD_CTRL_KEY_DOWN 0x40
|
||||||
#define KEYBOARD_LEFT_SHIFT_DOWN 0x02
|
#define KEYBOARD_LEFT_SHIFT_DOWN 0x20
|
||||||
#define KEYBOARD_RIGHT_SHIFT_DOWN 0x01
|
#define KEYBOARD_RIGHT_SHIFT_DOWN 0x10
|
||||||
|
|
||||||
typedef struct _CM_MCA_POS_DATA {
|
typedef struct _CM_MCA_POS_DATA {
|
||||||
USHORT AdapterId;
|
USHORT AdapterId;
|
||||||
|
|
Loading…
Reference in a new issue