mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +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
|
||||
|
||||
# Kernel mode input drivers
|
||||
INPUT_DRIVERS = keyboard mouclass psaux sermouse
|
||||
INPUT_DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
|
||||
|
||||
# Kernel mode file system drivers
|
||||
# cdfs ext2 fs_rec ms np vfat
|
||||
|
|
|
@ -558,8 +558,14 @@ for(;;);
|
|||
|
||||
|
||||
/* Load keyboard driver */
|
||||
#if 0
|
||||
if (!LoadDriver(SourcePath, "keyboard.sys"))
|
||||
return;
|
||||
#endif
|
||||
if (!LoadDriver(SourcePath, "i8042prt.sys"))
|
||||
return;
|
||||
if (!LoadDriver(SourcePath, "kbdclass.sys"))
|
||||
return;
|
||||
|
||||
/* Load screen driver */
|
||||
if (!LoadDriver(SourcePath, "blue.sys"))
|
||||
|
|
|
@ -575,11 +575,28 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Type",0x00010001,0x00000008
|
|||
;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x00000001
|
||||
|
||||
; Keyboard driver
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
|
||||
|
||||
; i8042 port driver
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","ErrorControl",0x00010001,0x00000000
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Group",0x00000000,"Keyboard Port"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","ImagePath",0x00020000,"system32\drivers\i8042prt.sys"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Start",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Type",0x00010001,0x00000001
|
||||
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","SampleRate",0x00010001,0x00000060
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","BreakOnSysRq",0x00010001,0x00000001
|
||||
|
||||
; Keyboard class driver
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ErrorControl",0x00010001,0x00000000
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Group",0x00000000,"Keyboard Class"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ImagePath",0x00020000,"system32\drivers\kbdclass.sys"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Start",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Type",0x00010001,0x00000001
|
||||
|
||||
; Serial port enumerator
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
|
||||
|
@ -840,12 +857,12 @@ HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Start",0x00010001,0x00000002
|
|||
HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Type",0x00010001,0x00000010
|
||||
|
||||
; PS/2 mouse port driver
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
|
||||
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
|
||||
|
||||
; RPC service
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001,0x00000001
|
||||
|
|
|
@ -22,7 +22,9 @@ cdrom.sys = 3
|
|||
class2.sys = 3
|
||||
disk.sys = 3
|
||||
floppy.sys = 3
|
||||
keyboard.sys = 3
|
||||
;keyboard.sys = 3
|
||||
i8042prt.sys = 3
|
||||
kbdclass.sys = 3
|
||||
l_intl.nls = 2
|
||||
ntfs.sys = 3
|
||||
ntoskrnl.exe = 2
|
||||
|
@ -96,14 +98,16 @@ Default = "XT-, AT- or extended keyboard (83-105 keys)"
|
|||
|
||||
[Mouse]
|
||||
;<id> = <user friendly name>,<spare>,<service key name>
|
||||
msps2 = "Microsoft PS2 Mouse",,psaux
|
||||
i8042ps2 = "PS2 Mouse",,i8042prt
|
||||
;msps2 = "Microsoft PS2 Mouse",,psaux
|
||||
msser = "Microsoft Serial Mouse",,sermouse
|
||||
mswhs = "Microsoft Serial Wheel Mouse",,sermouse
|
||||
none = "No Mouse"
|
||||
|
||||
[Map.Mouse]
|
||||
;<id> = <pnp id string>
|
||||
msps2 = "MICROSOFT PS2 MOUSE"
|
||||
i8042ps2 = "MICROSOFT PS2 MOUSE"
|
||||
;msps2 = "MICROSOFT PS2 MOUSE"
|
||||
msser = "MICROSOFT SERIAL MOUSE"
|
||||
mswhs = "MICROSOFT MOUSE WITH WHEEL"
|
||||
none = "NO MOUSE"
|
||||
|
|
|
@ -6,7 +6,7 @@ PATH_TO_TOP = ../..
|
|||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
DRIVERS = keyboard mouclass psaux sermouse
|
||||
DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
|
||||
|
||||
all: $(DRIVERS)
|
||||
|
||||
|
|
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(
|
||||
PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
|
||||
PMOUSE_INPUT_DATA MouseDataEnd, PULONG InputCount)
|
||||
PMOUSE_INPUT_DATA MouseDataEnd, PULONG ConsumedCount)
|
||||
{
|
||||
PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
|
||||
PIRP Irp;
|
||||
KIRQL OldIrql;
|
||||
PIO_STACK_LOCATION Stack;
|
||||
ULONG SafeInputCount = *InputCount;
|
||||
ULONG InputCount = MouseDataEnd - MouseDataStart;
|
||||
ULONG ReadSize;
|
||||
|
||||
DPRINT("Entering MouseClassCallBack\n");
|
||||
if (ClassDeviceExtension->ReadIsPending == TRUE)
|
||||
/* A filter driver might have consumed all the data already; I'm
|
||||
* not sure if they are supposed to move the packets when they
|
||||
* consume them though.
|
||||
*/
|
||||
if (ClassDeviceExtension->ReadIsPending == TRUE &&
|
||||
InputCount)
|
||||
{
|
||||
Irp = ClassDeviceObject->CurrentIrp;
|
||||
ClassDeviceObject->CurrentIrp = NULL;
|
||||
|
@ -52,19 +57,20 @@ BOOLEAN MouseClassCallBack(
|
|||
|
||||
/* Skip the packet we just sent away */
|
||||
MouseDataStart++;
|
||||
SafeInputCount--;
|
||||
(*ConsumedCount)++;
|
||||
InputCount--;
|
||||
}
|
||||
|
||||
/* If we have data from the port driver and a higher service to send the data to */
|
||||
if (SafeInputCount != 0)
|
||||
if (InputCount != 0)
|
||||
{
|
||||
KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
|
||||
|
||||
if (ClassDeviceExtension->InputCount + SafeInputCount > MOUSE_BUFFER_SIZE)
|
||||
if (ClassDeviceExtension->InputCount + InputCount > MOUSE_BUFFER_SIZE)
|
||||
{
|
||||
ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
|
||||
} else {
|
||||
ReadSize = SafeInputCount;
|
||||
ReadSize = InputCount;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -84,6 +90,7 @@ BOOLEAN MouseClassCallBack(
|
|||
ClassDeviceExtension->InputCount += ReadSize;
|
||||
|
||||
KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
|
||||
(*ConsumedCount) += ReadSize;
|
||||
} else {
|
||||
DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount);
|
||||
}
|
||||
|
|
|
@ -204,18 +204,18 @@ typedef struct _INTERNAL_I8042_HOOK_KEYBOARD {
|
|||
//
|
||||
// Write function
|
||||
//
|
||||
//UNIMPLEMENTED IN PI8042_ISR_WRITE_PORT IsrWritePort;
|
||||
IN PI8042_ISR_WRITE_PORT IsrWritePort;
|
||||
|
||||
//
|
||||
// Queue the current packet (ie the one passed into the isr callback hook)
|
||||
// to be reported to the class driver
|
||||
//
|
||||
//UNIMPLEMENTED IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
|
||||
IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
|
||||
|
||||
//
|
||||
// Context for IsrWritePort, QueueKeyboardPacket
|
||||
//
|
||||
//UNIMPLEMENTED IN PVOID CallContext;
|
||||
IN PVOID CallContext;
|
||||
|
||||
} INTERNAL_I8042_HOOK_KEYBOARD, *PINTERNAL_I8042_HOOK_KEYBOARD;
|
||||
|
||||
|
|
|
@ -203,17 +203,17 @@ typedef struct _KDP_DEBUG_MODE
|
|||
/* KD Internal Debug Services */
|
||||
typedef enum _KDP_DEBUG_SERVICE
|
||||
{
|
||||
DumpNonPagedPool = 0,
|
||||
ManualBugCheck,
|
||||
DumpNonPagedPoolStats,
|
||||
DumpNewNonPagedPool,
|
||||
DumpNewNonPagedPoolStats,
|
||||
DumpAllThreads,
|
||||
DumpUserThreads,
|
||||
KdSpare1,
|
||||
KdSpare2,
|
||||
KdSpare3,
|
||||
EnterDebugger
|
||||
DumpNonPagedPool = 0x1e, /* a */
|
||||
ManualBugCheck = 0x30, /* b */
|
||||
DumpNonPagedPoolStats = 0x2e, /* c */
|
||||
DumpNewNonPagedPool = 0x20, /* d */
|
||||
DumpNewNonPagedPoolStats = 0x12, /* e */
|
||||
DumpAllThreads = 0x21, /* f */
|
||||
DumpUserThreads = 0x22, /* g */
|
||||
KdSpare1 = 0x23, /* h */
|
||||
KdSpare2 = 0x17, /* i */
|
||||
KdSpare3 = 0x24, /* j */
|
||||
EnterDebugger = 0x25 /* k */
|
||||
} KDP_DEBUG_SERVICE;
|
||||
|
||||
/* Dispatch Table for Wrapper Functions */
|
||||
|
|
|
@ -371,7 +371,7 @@ CreateFreeLoaderIniForReactos(PWCHAR IniPath,
|
|||
NULL,
|
||||
INSERT_LAST,
|
||||
L"Options",
|
||||
L"/DEBUGPORT=SCREEN /NOGUIBOOT");
|
||||
L"/DEBUGPORT=COM1 /NOGUIBOOT");
|
||||
|
||||
/* Save the ini file */
|
||||
IniCacheSave(IniCache, IniPath);
|
||||
|
|
|
@ -28,9 +28,11 @@
|
|||
|
||||
#include "precomp.h"
|
||||
#include <ddk/ntddblue.h>
|
||||
#include <ddk/ntddkbd.h>
|
||||
|
||||
#include "usetup.h"
|
||||
#include "console.h"
|
||||
#include "keytrans.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
@ -194,6 +196,7 @@ ReadConsoleInput(PINPUT_RECORD Buffer)
|
|||
{
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
NTSTATUS Status;
|
||||
KEYBOARD_INPUT_DATA InputData;
|
||||
|
||||
Buffer->EventType = KEY_EVENT;
|
||||
Status = NtReadFile(StdInput,
|
||||
|
@ -201,11 +204,17 @@ ReadConsoleInput(PINPUT_RECORD Buffer)
|
|||
NULL,
|
||||
NULL,
|
||||
&Iosb,
|
||||
&Buffer->Event.KeyEvent,
|
||||
&InputData,
|
||||
// &Buffer->Event.KeyEvent,
|
||||
sizeof(KEY_EVENT_RECORD),
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = IntTranslateKey(&InputData, &Buffer->Event.KeyEvent);
|
||||
}
|
||||
|
||||
return(Status);
|
||||
}
|
||||
|
||||
|
|
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 \
|
||||
filesup.o format.o fslist.o genlist.o infcache.o \
|
||||
inicache.o partlist.o progress.o registry.o settings.o \
|
||||
usetup.o
|
||||
usetup.o keytrans.o
|
||||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
include $(TOOLS_PATH)/helper.mk
|
||||
|
||||
# EOF
|
||||
# EOF
|
||||
|
|
|
@ -58,6 +58,7 @@ EngDeviceIoControl(HANDLE hDevice,
|
|||
nInBufferSize,
|
||||
lpOutBuffer,
|
||||
nOutBufferSize, FALSE, &Event, &Iosb);
|
||||
DPRINT1("IRP: %x\n", Irp);
|
||||
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
/* ntuser */
|
||||
#define TAG_MOUSE TAG('M', 'O', 'U', 'S') /* mouse */
|
||||
#define TAG_KEYBOARD TAG('K', 'B', 'D', ' ') /* keyboard */
|
||||
#define TAG_ACCEL TAG('A', 'C', 'C', 'L') /* accelerator */
|
||||
#define TAG_HOOK TAG('W', 'N', 'H', 'K') /* hook */
|
||||
#define TAG_HOTKEY TAG('H', 'O', 'T', 'K') /* hotkey */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <w32k.h>
|
||||
#include <rosrtl/string.h>
|
||||
#include <ddk/ntddkbd.h>
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
|
@ -219,6 +220,185 @@ MouseThreadMain(PVOID StartContext)
|
|||
}
|
||||
}
|
||||
|
||||
/* Returns a value that indicates if the key is a modifier key, and
|
||||
* which one.
|
||||
*/
|
||||
STATIC UINT STDCALL
|
||||
IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
|
||||
{
|
||||
if (InputData->Flags & KEY_E1)
|
||||
return 0;
|
||||
|
||||
if (!(InputData->Flags & KEY_E0))
|
||||
{
|
||||
switch (InputData->MakeCode)
|
||||
{
|
||||
case 0x2a: /* left shift */
|
||||
case 0x36: /* right shift */
|
||||
return MOD_SHIFT;
|
||||
|
||||
case 0x1d: /* left control */
|
||||
return MOD_CONTROL;
|
||||
|
||||
case 0x38: /* left alt */
|
||||
return MOD_ALT;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (InputData->MakeCode)
|
||||
{
|
||||
case 0x1d: /* right control */
|
||||
return MOD_CONTROL;
|
||||
|
||||
case 0x38: /* right alt */
|
||||
return MOD_ALT;
|
||||
|
||||
case 0x5b: /* left gui (windows) */
|
||||
case 0x5c: /* right gui (windows) */
|
||||
return MOD_WIN;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Asks the keyboard driver to send a small table that shows which
|
||||
* lights should connect with which scancodes
|
||||
*/
|
||||
STATIC NTSTATUS STDCALL
|
||||
IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
|
||||
PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
DWORD Size = 0;
|
||||
IO_STATUS_BLOCK Block;
|
||||
PKEYBOARD_INDICATOR_TRANSLATION Ret;
|
||||
|
||||
Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
|
||||
|
||||
Ret = ExAllocatePoolWithTag(PagedPool,
|
||||
Size,
|
||||
TAG_KEYBOARD);
|
||||
|
||||
while (Ret)
|
||||
{
|
||||
Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&Block,
|
||||
IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
|
||||
NULL, 0,
|
||||
Ret, Size);
|
||||
|
||||
if (Status != STATUS_BUFFER_TOO_SMALL)
|
||||
break;
|
||||
|
||||
ExFreePool(Ret);
|
||||
|
||||
Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
|
||||
|
||||
Ret = ExAllocatePoolWithTag(PagedPool,
|
||||
Size,
|
||||
TAG_KEYBOARD);
|
||||
}
|
||||
|
||||
if (!Ret)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
if (Status != STATUS_SUCCESS)
|
||||
{
|
||||
ExFreePool(Ret);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*IndicatorTrans = Ret;
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Sends the keyboard commands to turn on/off the lights.
|
||||
*/
|
||||
STATIC NTSTATUS STDCALL
|
||||
IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
|
||||
PKEYBOARD_INPUT_DATA KeyInput,
|
||||
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UINT Count;
|
||||
static KEYBOARD_INDICATOR_PARAMETERS Indicators;
|
||||
IO_STATUS_BLOCK Block;
|
||||
|
||||
if (!IndicatorTrans)
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
|
||||
{
|
||||
if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
|
||||
{
|
||||
Indicators.LedFlags ^=
|
||||
IndicatorTrans->IndicatorList[Count].IndicatorFlags;
|
||||
|
||||
/* Update the lights on the hardware */
|
||||
|
||||
Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&Block,
|
||||
IOCTL_KEYBOARD_SET_INDICATORS,
|
||||
&Indicators, sizeof(Indicators),
|
||||
NULL, 0);
|
||||
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC VOID STDCALL
|
||||
IntKeyboardSendWinKeyMsg()
|
||||
{
|
||||
PWINDOW_OBJECT Window;
|
||||
MSG Mesg;
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = ObmReferenceObjectByHandle(InputWindowStation->HandleTable,
|
||||
InputWindowStation->ShellWindow,
|
||||
otWindow,
|
||||
(PVOID *)&Window);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Couldn't find window to send Windows key message!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Mesg.hwnd = InputWindowStation->ShellWindow;
|
||||
Mesg.message = WM_SYSCOMMAND;
|
||||
Mesg.wParam = SC_TASKLIST;
|
||||
Mesg.lParam = 0;
|
||||
|
||||
/* The QS_HOTKEY is just a guess */
|
||||
MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
|
||||
|
||||
ObmDereferenceObject(Window);
|
||||
}
|
||||
|
||||
STATIC VOID STDCALL
|
||||
IntKeyboardSendAltKeyMsg()
|
||||
{
|
||||
MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
|
||||
}
|
||||
|
||||
STATIC VOID STDCALL
|
||||
KeyboardThreadMain(PVOID StartContext)
|
||||
{
|
||||
|
@ -229,6 +409,12 @@ KeyboardThreadMain(PVOID StartContext)
|
|||
MSG msg;
|
||||
PUSER_MESSAGE_QUEUE FocusQueue;
|
||||
struct _ETHREAD *FocusThread;
|
||||
|
||||
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
|
||||
UINT ModifierState = 0;
|
||||
USHORT LastMakeCode = 0;
|
||||
USHORT LastFlags = 0;
|
||||
UINT RepeatCount = 0;
|
||||
|
||||
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
|
||||
InitializeObjectAttributes(&KeyboardObjectAttributes,
|
||||
|
@ -248,6 +434,9 @@ KeyboardThreadMain(PVOID StartContext)
|
|||
return; //(Status);
|
||||
}
|
||||
|
||||
IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
|
||||
&IndicatorTrans);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
|
@ -267,8 +456,11 @@ KeyboardThreadMain(PVOID StartContext)
|
|||
while (InputThreadsRunning)
|
||||
{
|
||||
KEY_EVENT_RECORD KeyEvent;
|
||||
BOOLEAN NumKeys = 1;
|
||||
KEYBOARD_INPUT_DATA KeyInput;
|
||||
KEYBOARD_INPUT_DATA NextKeyInput;
|
||||
LPARAM lParam = 0;
|
||||
UINT fsModifiers;
|
||||
UINT fsModifiers, fsNextModifiers;
|
||||
struct _ETHREAD *Thread;
|
||||
HWND hWnd;
|
||||
int id;
|
||||
|
@ -278,124 +470,223 @@ KeyboardThreadMain(PVOID StartContext)
|
|||
NULL,
|
||||
NULL,
|
||||
&Iosb,
|
||||
&KeyEvent,
|
||||
sizeof(KEY_EVENT_RECORD),
|
||||
&KeyInput,
|
||||
sizeof(KEYBOARD_INPUT_DATA),
|
||||
NULL,
|
||||
NULL);
|
||||
DPRINT( "KeyRaw: %s %04x\n",
|
||||
KeyEvent.bKeyDown ? "down" : "up",
|
||||
KeyEvent.wVirtualScanCode );
|
||||
DPRINT("KeyRaw: %s %04x\n",
|
||||
(KeyInput.Flags & KEY_BREAK) ? "up" : "down",
|
||||
KeyInput.MakeCode );
|
||||
|
||||
if (Status == STATUS_ALERTED && !InputThreadsRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Win32K: Failed to read from keyboard.\n");
|
||||
return; //(Status);
|
||||
}
|
||||
|
||||
DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
|
||||
/* Update modifier state */
|
||||
fsModifiers = IntKeyboardGetModifiers(&KeyInput);
|
||||
|
||||
fsModifiers = 0;
|
||||
if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
|
||||
fsModifiers |= MOD_ALT;
|
||||
|
||||
if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
|
||||
fsModifiers |= MOD_CONTROL;
|
||||
|
||||
if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
|
||||
fsModifiers |= MOD_SHIFT;
|
||||
|
||||
/* FIXME: Support MOD_WIN */
|
||||
|
||||
lParam = KeyEvent.wRepeatCount |
|
||||
((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
|
||||
|
||||
/* Bit 24 indicates if this is an extended key */
|
||||
if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
|
||||
if (fsModifiers)
|
||||
{
|
||||
lParam |= (1 << 24);
|
||||
}
|
||||
|
||||
if (fsModifiers & MOD_ALT)
|
||||
{
|
||||
/* Context mode. 1 if ALT if pressed while the key is pressed */
|
||||
lParam |= (1 << 29);
|
||||
}
|
||||
|
||||
if (! KeyEvent.bKeyDown)
|
||||
{
|
||||
/* Transition state. 1 for KEY_UP etc, 0 for KEY_DOWN */
|
||||
lParam |= (1 << 31);
|
||||
}
|
||||
|
||||
if (GetHotKey(InputWindowStation,
|
||||
fsModifiers,
|
||||
KeyEvent.wVirtualKeyCode,
|
||||
&Thread,
|
||||
&hWnd,
|
||||
&id))
|
||||
{
|
||||
if (KeyEvent.bKeyDown)
|
||||
if (KeyInput.Flags & KEY_BREAK)
|
||||
{
|
||||
DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
|
||||
MsqPostHotKeyMessage (Thread,
|
||||
hWnd,
|
||||
(WPARAM)id,
|
||||
MAKELPARAM((WORD)fsModifiers,
|
||||
(WORD)msg.wParam));
|
||||
ModifierState &= ~fsModifiers;
|
||||
}
|
||||
else
|
||||
{
|
||||
ModifierState |= fsModifiers;
|
||||
|
||||
if (ModifierState == fsModifiers &&
|
||||
(fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
|
||||
{
|
||||
/* First send out special notifications
|
||||
* (For alt, the message that turns on accelerator
|
||||
* display, not sure what for win. Both TODO though.)
|
||||
*/
|
||||
|
||||
/* Read the next key before sending this one */
|
||||
do
|
||||
{
|
||||
Status = NtReadFile (KeyboardDeviceHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&Iosb,
|
||||
&NextKeyInput,
|
||||
sizeof(KEYBOARD_INPUT_DATA),
|
||||
NULL,
|
||||
NULL);
|
||||
DPRINT("KeyRaw: %s %04x\n",
|
||||
(NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
|
||||
NextKeyInput.MakeCode );
|
||||
|
||||
if (Status == STATUS_ALERTED && !InputThreadsRunning)
|
||||
goto KeyboardEscape;
|
||||
|
||||
} while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
|
||||
NextKeyInput.MakeCode == KeyInput.MakeCode);
|
||||
/* ^ Ignore repeats, they'll be KEY_MAKE and the same
|
||||
* code. I'm not caring about the counting, not sure
|
||||
* if that matters. I think not.
|
||||
*/
|
||||
|
||||
/* If the ModifierState is now empty again, send a
|
||||
* special notification and eat both keypresses
|
||||
*/
|
||||
|
||||
fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
|
||||
|
||||
if (fsNextModifiers)
|
||||
ModifierState ^= fsNextModifiers;
|
||||
|
||||
if (ModifierState == 0)
|
||||
{
|
||||
if (fsModifiers == MOD_WIN)
|
||||
IntKeyboardSendWinKeyMsg();
|
||||
else if (fsModifiers == MOD_ALT)
|
||||
IntKeyboardSendAltKeyMsg();
|
||||
continue;
|
||||
}
|
||||
|
||||
NumKeys = 2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the target thread whose locale is in effect */
|
||||
if (!IntGetScreenDC())
|
||||
for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
|
||||
NumKeys--)
|
||||
{
|
||||
FocusQueue = W32kGetPrimitiveMessageQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
FocusQueue = IntGetFocusMessageQueue();
|
||||
}
|
||||
lParam = 0;
|
||||
|
||||
if (!FocusQueue) continue;
|
||||
IntKeyboardUpdateLeds(KeyboardDeviceHandle,
|
||||
&KeyInput,
|
||||
IndicatorTrans);
|
||||
|
||||
if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT))
|
||||
msg.message = WM_SYSKEYDOWN;
|
||||
else if(KeyEvent.bKeyDown)
|
||||
msg.message = WM_KEYDOWN;
|
||||
else if(fsModifiers & MOD_ALT)
|
||||
msg.message = WM_SYSKEYUP;
|
||||
else
|
||||
msg.message = WM_KEYUP;
|
||||
/* While we are working, we set up lParam. The format is:
|
||||
* 0-15: The number of times this key has autorepeated
|
||||
* 16-23: The keyboard scancode
|
||||
* 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
|
||||
* Note that E1 is only used for PAUSE (E1-1D-45) and
|
||||
* E0-45 happens not to be anything.
|
||||
* 29: Alt is pressed ('Context code')
|
||||
* 30: Previous state, if the key was down before this message
|
||||
* This is a cheap way to ignore autorepeat keys
|
||||
* 31: 1 if the key is being pressed
|
||||
*/
|
||||
|
||||
msg.wParam = KeyEvent.wVirtualKeyCode;
|
||||
msg.lParam = lParam;
|
||||
msg.hwnd = FocusQueue->FocusWindow;
|
||||
/* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
|
||||
* and it's the same key as the last one, increase the repeat
|
||||
* count.
|
||||
*/
|
||||
|
||||
FocusThread = FocusQueue->Thread;
|
||||
if (!(KeyInput.Flags & KEY_BREAK))
|
||||
{
|
||||
if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
|
||||
(KeyInput.MakeCode == LastMakeCode))
|
||||
{
|
||||
RepeatCount++;
|
||||
lParam |= (1 << 30);
|
||||
}
|
||||
else
|
||||
{
|
||||
RepeatCount = 0;
|
||||
LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
|
||||
LastMakeCode = KeyInput.MakeCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LastFlags = 0;
|
||||
LastMakeCode = 0; /* Should never match */
|
||||
lParam |= (1 << 30) | (1 << 31);
|
||||
}
|
||||
|
||||
if (FocusThread && FocusThread->Tcb.Win32Thread &&
|
||||
FocusThread->Tcb.Win32Thread->KeyboardLayout)
|
||||
{
|
||||
lParam |= RepeatCount;
|
||||
|
||||
lParam |= (KeyInput.MakeCode & 0xff) << 16;
|
||||
|
||||
if (KeyInput.Flags & (KEY_E0 | KEY_E1))
|
||||
lParam |= (1 << 24);
|
||||
|
||||
if (ModifierState & MOD_ALT)
|
||||
{
|
||||
lParam |= (1 << 29);
|
||||
|
||||
if (!(KeyInput.Flags & KEY_BREAK))
|
||||
msg.message = WM_SYSKEYDOWN;
|
||||
else
|
||||
msg.message = WM_SYSKEYUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(KeyInput.Flags & KEY_BREAK))
|
||||
msg.message = WM_KEYDOWN;
|
||||
else
|
||||
msg.message = WM_KEYUP;
|
||||
}
|
||||
|
||||
/* Find the target thread whose locale is in effect */
|
||||
if (!IntGetScreenDC())
|
||||
FocusQueue = W32kGetPrimitiveMessageQueue();
|
||||
else
|
||||
FocusQueue = IntGetFocusMessageQueue();
|
||||
|
||||
/* This might cause us to lose hot keys, which are important
|
||||
* (ctrl-alt-del secure attention sequence). Not sure if it
|
||||
* can happen though.
|
||||
*/
|
||||
if (!FocusQueue) continue;
|
||||
|
||||
msg.lParam = lParam;
|
||||
msg.hwnd = FocusQueue->FocusWindow;
|
||||
|
||||
FocusThread = FocusQueue->Thread;
|
||||
|
||||
if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
|
||||
FocusThread->Tcb.Win32Thread->KeyboardLayout))
|
||||
continue;
|
||||
|
||||
/* This function uses lParam to fill wParam according to the
|
||||
* keyboard layout in use.
|
||||
*/
|
||||
W32kKeyProcessMessage(&msg,
|
||||
FocusThread->Tcb.Win32Thread->KeyboardLayout);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
if (GetHotKey(InputWindowStation,
|
||||
ModifierState,
|
||||
msg.wParam,
|
||||
&Thread,
|
||||
&hWnd,
|
||||
&id))
|
||||
{
|
||||
if (KeyEvent.bKeyDown)
|
||||
{
|
||||
DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
|
||||
MsqPostHotKeyMessage (Thread,
|
||||
hWnd,
|
||||
(WPARAM)id,
|
||||
MAKELPARAM((WORD)ModifierState,
|
||||
(WORD)msg.wParam));
|
||||
}
|
||||
continue; /* Eat key up motion too */
|
||||
}
|
||||
|
||||
/*
|
||||
* Post a keyboard message.
|
||||
*/
|
||||
MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
|
||||
/*
|
||||
* Post a keyboard message.
|
||||
*/
|
||||
MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardEscape:
|
||||
DPRINT( "KeyboardInput Thread Stopped...\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
|
||||
{
|
||||
|
|
|
@ -683,10 +683,10 @@ ifneq ($(DBG),1)
|
|||
MK_CFLAGS += -Os -Wno-strict-aliasing -ftracer -momit-leaf-frame-pointer
|
||||
MK_CFLAGS += -mpreferred-stack-boundary=2
|
||||
|
||||
CC_VERSION=$(word 1,$(shell gcc -dumpversion))
|
||||
ifeq ($(CC_VERSION),3.4.3)
|
||||
#CC_VERSION=$(word 1,$(shell gcc -dumpversion))
|
||||
#ifeq ($(CC_VERSION),3.4.3)
|
||||
MK_CFLAGS += -funit-at-a-time -fweb
|
||||
endif
|
||||
#endif
|
||||
|
||||
#
|
||||
# Remove Symbols if no debugging is used at all
|
||||
|
|
|
@ -529,7 +529,7 @@ typedef VOID
|
|||
IN PVOID Context,
|
||||
IN ULONG Count);
|
||||
|
||||
typedef NTSTATUS
|
||||
typedef VOID
|
||||
(DDKAPI *PDRIVER_STARTIO)(
|
||||
IN struct _DEVICE_OBJECT *DeviceObject,
|
||||
IN struct _IRP *Irp);
|
||||
|
@ -1432,14 +1432,14 @@ typedef struct _CM_KEYBOARD_DEVICE_DATA {
|
|||
USHORT KeyboardFlags;
|
||||
} CM_KEYBOARD_DEVICE_DATA, *PCM_KEYBOARD_DEVICE_DATA;
|
||||
|
||||
#define KEYBOARD_INSERT_ON 0x80
|
||||
#define KEYBOARD_CAPS_LOCK_ON 0x40
|
||||
#define KEYBOARD_NUM_LOCK_ON 0x20
|
||||
#define KEYBOARD_SCROLL_LOCK_ON 0x10
|
||||
#define KEYBOARD_ALT_KEY_DOWN 0x08
|
||||
#define KEYBOARD_CTRL_KEY_DOWN 0x04
|
||||
#define KEYBOARD_LEFT_SHIFT_DOWN 0x02
|
||||
#define KEYBOARD_RIGHT_SHIFT_DOWN 0x01
|
||||
#define KEYBOARD_INSERT_ON 0x08
|
||||
#define KEYBOARD_CAPS_LOCK_ON 0x04
|
||||
#define KEYBOARD_NUM_LOCK_ON 0x02
|
||||
#define KEYBOARD_SCROLL_LOCK_ON 0x01
|
||||
#define KEYBOARD_ALT_KEY_DOWN 0x80
|
||||
#define KEYBOARD_CTRL_KEY_DOWN 0x40
|
||||
#define KEYBOARD_LEFT_SHIFT_DOWN 0x20
|
||||
#define KEYBOARD_RIGHT_SHIFT_DOWN 0x10
|
||||
|
||||
typedef struct _CM_MCA_POS_DATA {
|
||||
USHORT AdapterId;
|
||||
|
|
Loading…
Reference in a new issue