i8042prt driver by tinus.

svn path=/trunk/; revision=14926
This commit is contained in:
Alex Ionescu 2005-05-01 20:38:29 +00:00
parent 82b7f31f61
commit a70444fab1
31 changed files with 4527 additions and 142 deletions

View file

@ -84,7 +84,7 @@ DRIVERS_LIB = bzip2 oskittcp ip csq
DEVICE_DRIVERS = beep blue debugout null serial bootvid
# Kernel mode input drivers
INPUT_DRIVERS = keyboard mouclass psaux sermouse
INPUT_DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
# Kernel mode file system drivers
# cdfs ext2 fs_rec ms np vfat

View file

@ -558,8 +558,14 @@ for(;;);
/* Load keyboard driver */
#if 0
if (!LoadDriver(SourcePath, "keyboard.sys"))
return;
#endif
if (!LoadDriver(SourcePath, "i8042prt.sys"))
return;
if (!LoadDriver(SourcePath, "kbdclass.sys"))
return;
/* Load screen driver */
if (!LoadDriver(SourcePath, "blue.sys"))

View file

@ -575,11 +575,28 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Fs_Rec","Type",0x00010001,0x00000008
;HKLM,"SYSTEM\CurrentControlSet\Services\Ide","Type",0x00010001,0x00000001
; Keyboard driver
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ErrorControl",0x00010001,0x00000000
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Group",0x00000000,"Keyboard Port"
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system32\drivers\keyboard.sys"
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
;HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
; i8042 port driver
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Group",0x00000000,"Keyboard Port"
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","ImagePath",0x00020000,"system32\drivers\i8042prt.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","SampleRate",0x00010001,0x00000060
HKLM,"SYSTEM\CurrentControlSet\Services\i8042Prt\Parameters","BreakOnSysRq",0x00010001,0x00000001
; Keyboard class driver
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Group",0x00000000,"Keyboard Class"
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ImagePath",0x00020000,"system32\drivers\kbdclass.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Type",0x00010001,0x00000001
; Serial port enumerator
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
@ -840,12 +857,12 @@ HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Start",0x00010001,0x00000002
HKLM,"SYSTEM\CurrentControlSet\Services\PlugPlay","Type",0x00010001,0x00000010
; PS/2 mouse port driver
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ErrorControl",0x00010001,0x00000000
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Group",0x00000000,"Pointer Port"
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","ImagePath",0x00020000,"system32\drivers\psaux.sys"
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Start",0x00010001,0x00000004
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux","Type",0x00010001,0x00000001
;HKLM,"SYSTEM\CurrentControlSet\Services\Psaux\Parameters","DisableExtensionDetection",0x00010001,0x00000000
; RPC service
HKLM,"SYSTEM\CurrentControlSet\Services\Rpcss","ErrorControl",0x00010001,0x00000001

View file

@ -22,7 +22,9 @@ cdrom.sys = 3
class2.sys = 3
disk.sys = 3
floppy.sys = 3
keyboard.sys = 3
;keyboard.sys = 3
i8042prt.sys = 3
kbdclass.sys = 3
l_intl.nls = 2
ntfs.sys = 3
ntoskrnl.exe = 2
@ -96,14 +98,16 @@ Default = "XT-, AT- or extended keyboard (83-105 keys)"
[Mouse]
;<id> = <user friendly name>,<spare>,<service key name>
msps2 = "Microsoft PS2 Mouse",,psaux
i8042ps2 = "PS2 Mouse",,i8042prt
;msps2 = "Microsoft PS2 Mouse",,psaux
msser = "Microsoft Serial Mouse",,sermouse
mswhs = "Microsoft Serial Wheel Mouse",,sermouse
none = "No Mouse"
[Map.Mouse]
;<id> = <pnp id string>
msps2 = "MICROSOFT PS2 MOUSE"
i8042ps2 = "MICROSOFT PS2 MOUSE"
;msps2 = "MICROSOFT PS2 MOUSE"
msser = "MICROSOFT SERIAL MOUSE"
mswhs = "MICROSOFT MOUSE WITH WHEEL"
none = "NO MOUSE"

View file

@ -6,7 +6,7 @@ PATH_TO_TOP = ../..
include $(PATH_TO_TOP)/rules.mak
DRIVERS = keyboard mouclass psaux sermouse
DRIVERS = keyboard mouclass psaux sermouse i8042prt kbdclass
all: $(DRIVERS)

View 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.

View 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);
}

View 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_

View 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>

View 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);
}

View 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

View 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;
}

View 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");
}
}

View 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");
}

View 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);
}

View 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_

View 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>

View 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

View file

@ -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);
}

View file

@ -204,18 +204,18 @@ typedef struct _INTERNAL_I8042_HOOK_KEYBOARD {
//
// Write function
//
//UNIMPLEMENTED IN PI8042_ISR_WRITE_PORT IsrWritePort;
IN PI8042_ISR_WRITE_PORT IsrWritePort;
//
// Queue the current packet (ie the one passed into the isr callback hook)
// to be reported to the class driver
//
//UNIMPLEMENTED IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
IN PI8042_QUEUE_PACKET QueueKeyboardPacket;
//
// Context for IsrWritePort, QueueKeyboardPacket
//
//UNIMPLEMENTED IN PVOID CallContext;
IN PVOID CallContext;
} INTERNAL_I8042_HOOK_KEYBOARD, *PINTERNAL_I8042_HOOK_KEYBOARD;

View file

@ -203,17 +203,17 @@ typedef struct _KDP_DEBUG_MODE
/* KD Internal Debug Services */
typedef enum _KDP_DEBUG_SERVICE
{
DumpNonPagedPool = 0,
ManualBugCheck,
DumpNonPagedPoolStats,
DumpNewNonPagedPool,
DumpNewNonPagedPoolStats,
DumpAllThreads,
DumpUserThreads,
KdSpare1,
KdSpare2,
KdSpare3,
EnterDebugger
DumpNonPagedPool = 0x1e, /* a */
ManualBugCheck = 0x30, /* b */
DumpNonPagedPoolStats = 0x2e, /* c */
DumpNewNonPagedPool = 0x20, /* d */
DumpNewNonPagedPoolStats = 0x12, /* e */
DumpAllThreads = 0x21, /* f */
DumpUserThreads = 0x22, /* g */
KdSpare1 = 0x23, /* h */
KdSpare2 = 0x17, /* i */
KdSpare3 = 0x24, /* j */
EnterDebugger = 0x25 /* k */
} KDP_DEBUG_SERVICE;
/* Dispatch Table for Wrapper Functions */

View file

@ -371,7 +371,7 @@ CreateFreeLoaderIniForReactos(PWCHAR IniPath,
NULL,
INSERT_LAST,
L"Options",
L"/DEBUGPORT=SCREEN /NOGUIBOOT");
L"/DEBUGPORT=COM1 /NOGUIBOOT");
/* Save the ini file */
IniCacheSave(IniCache, IniPath);

View file

@ -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);
}

View 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;
}

View 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 */

View file

@ -23,10 +23,10 @@ TARGET_CFLAGS = -D__NTAPP__ -I$(PATH_TO_TOP)/lib/zlib -Wall -Werror -Wno-format
TARGET_OBJECTS = bootsup.o cabinet.o console.o drivesup.o filequeue.o \
filesup.o format.o fslist.o genlist.o infcache.o \
inicache.o partlist.o progress.o registry.o settings.o \
usetup.o
usetup.o keytrans.o
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk
# EOF
# EOF

View file

@ -58,6 +58,7 @@ EngDeviceIoControl(HANDLE hDevice,
nInBufferSize,
lpOutBuffer,
nOutBufferSize, FALSE, &Event, &Iosb);
DPRINT1("IRP: %x\n", Irp);
Status = IoCallDriver(DeviceObject, Irp);

View file

@ -5,6 +5,7 @@
/* ntuser */
#define TAG_MOUSE TAG('M', 'O', 'U', 'S') /* mouse */
#define TAG_KEYBOARD TAG('K', 'B', 'D', ' ') /* keyboard */
#define TAG_ACCEL TAG('A', 'C', 'C', 'L') /* accelerator */
#define TAG_HOOK TAG('W', 'N', 'H', 'K') /* hook */
#define TAG_HOTKEY TAG('H', 'O', 'T', 'K') /* hotkey */

View file

@ -31,6 +31,7 @@
#include <w32k.h>
#include <rosrtl/string.h>
#include <ddk/ntddkbd.h>
/* GLOBALS *******************************************************************/
@ -219,6 +220,185 @@ MouseThreadMain(PVOID StartContext)
}
}
/* Returns a value that indicates if the key is a modifier key, and
* which one.
*/
STATIC UINT STDCALL
IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
{
if (InputData->Flags & KEY_E1)
return 0;
if (!(InputData->Flags & KEY_E0))
{
switch (InputData->MakeCode)
{
case 0x2a: /* left shift */
case 0x36: /* right shift */
return MOD_SHIFT;
case 0x1d: /* left control */
return MOD_CONTROL;
case 0x38: /* left alt */
return MOD_ALT;
default:
return 0;
}
}
else
{
switch (InputData->MakeCode)
{
case 0x1d: /* right control */
return MOD_CONTROL;
case 0x38: /* right alt */
return MOD_ALT;
case 0x5b: /* left gui (windows) */
case 0x5c: /* right gui (windows) */
return MOD_WIN;
default:
return 0;
}
}
}
/* Asks the keyboard driver to send a small table that shows which
* lights should connect with which scancodes
*/
STATIC NTSTATUS STDCALL
IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
{
NTSTATUS Status;
DWORD Size = 0;
IO_STATUS_BLOCK Block;
PKEYBOARD_INDICATOR_TRANSLATION Ret;
Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
Ret = ExAllocatePoolWithTag(PagedPool,
Size,
TAG_KEYBOARD);
while (Ret)
{
Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
NULL, 0,
Ret, Size);
if (Status != STATUS_BUFFER_TOO_SMALL)
break;
ExFreePool(Ret);
Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
Ret = ExAllocatePoolWithTag(PagedPool,
Size,
TAG_KEYBOARD);
}
if (!Ret)
return STATUS_INSUFFICIENT_RESOURCES;
if (Status != STATUS_SUCCESS)
{
ExFreePool(Ret);
return Status;
}
*IndicatorTrans = Ret;
return Status;
}
/* Sends the keyboard commands to turn on/off the lights.
*/
STATIC NTSTATUS STDCALL
IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
PKEYBOARD_INPUT_DATA KeyInput,
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
{
NTSTATUS Status;
UINT Count;
static KEYBOARD_INDICATOR_PARAMETERS Indicators;
IO_STATUS_BLOCK Block;
if (!IndicatorTrans)
return STATUS_NOT_SUPPORTED;
if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
return STATUS_SUCCESS;
for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
{
if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
{
Indicators.LedFlags ^=
IndicatorTrans->IndicatorList[Count].IndicatorFlags;
/* Update the lights on the hardware */
Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_SET_INDICATORS,
&Indicators, sizeof(Indicators),
NULL, 0);
return Status;
}
}
return STATUS_SUCCESS;
}
STATIC VOID STDCALL
IntKeyboardSendWinKeyMsg()
{
PWINDOW_OBJECT Window;
MSG Mesg;
NTSTATUS Status;
Status = ObmReferenceObjectByHandle(InputWindowStation->HandleTable,
InputWindowStation->ShellWindow,
otWindow,
(PVOID *)&Window);
if (!NT_SUCCESS(Status))
{
DPRINT1("Couldn't find window to send Windows key message!\n");
return;
}
Mesg.hwnd = InputWindowStation->ShellWindow;
Mesg.message = WM_SYSCOMMAND;
Mesg.wParam = SC_TASKLIST;
Mesg.lParam = 0;
/* The QS_HOTKEY is just a guess */
MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
ObmDereferenceObject(Window);
}
STATIC VOID STDCALL
IntKeyboardSendAltKeyMsg()
{
MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
}
STATIC VOID STDCALL
KeyboardThreadMain(PVOID StartContext)
{
@ -229,6 +409,12 @@ KeyboardThreadMain(PVOID StartContext)
MSG msg;
PUSER_MESSAGE_QUEUE FocusQueue;
struct _ETHREAD *FocusThread;
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
UINT ModifierState = 0;
USHORT LastMakeCode = 0;
USHORT LastFlags = 0;
UINT RepeatCount = 0;
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
InitializeObjectAttributes(&KeyboardObjectAttributes,
@ -248,6 +434,9 @@ KeyboardThreadMain(PVOID StartContext)
return; //(Status);
}
IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
&IndicatorTrans);
for (;;)
{
/*
@ -267,8 +456,11 @@ KeyboardThreadMain(PVOID StartContext)
while (InputThreadsRunning)
{
KEY_EVENT_RECORD KeyEvent;
BOOLEAN NumKeys = 1;
KEYBOARD_INPUT_DATA KeyInput;
KEYBOARD_INPUT_DATA NextKeyInput;
LPARAM lParam = 0;
UINT fsModifiers;
UINT fsModifiers, fsNextModifiers;
struct _ETHREAD *Thread;
HWND hWnd;
int id;
@ -278,124 +470,223 @@ KeyboardThreadMain(PVOID StartContext)
NULL,
NULL,
&Iosb,
&KeyEvent,
sizeof(KEY_EVENT_RECORD),
&KeyInput,
sizeof(KEYBOARD_INPUT_DATA),
NULL,
NULL);
DPRINT( "KeyRaw: %s %04x\n",
KeyEvent.bKeyDown ? "down" : "up",
KeyEvent.wVirtualScanCode );
DPRINT("KeyRaw: %s %04x\n",
(KeyInput.Flags & KEY_BREAK) ? "up" : "down",
KeyInput.MakeCode );
if (Status == STATUS_ALERTED && !InputThreadsRunning)
{
break;
}
break;
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to read from keyboard.\n");
return; //(Status);
}
DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
/* Update modifier state */
fsModifiers = IntKeyboardGetModifiers(&KeyInput);
fsModifiers = 0;
if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
fsModifiers |= MOD_ALT;
if (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)
{

View file

@ -683,10 +683,10 @@ ifneq ($(DBG),1)
MK_CFLAGS += -Os -Wno-strict-aliasing -ftracer -momit-leaf-frame-pointer
MK_CFLAGS += -mpreferred-stack-boundary=2
CC_VERSION=$(word 1,$(shell gcc -dumpversion))
ifeq ($(CC_VERSION),3.4.3)
#CC_VERSION=$(word 1,$(shell gcc -dumpversion))
#ifeq ($(CC_VERSION),3.4.3)
MK_CFLAGS += -funit-at-a-time -fweb
endif
#endif
#
# Remove Symbols if no debugging is used at all

View file

@ -529,7 +529,7 @@ typedef VOID
IN PVOID Context,
IN ULONG Count);
typedef NTSTATUS
typedef VOID
(DDKAPI *PDRIVER_STARTIO)(
IN struct _DEVICE_OBJECT *DeviceObject,
IN struct _IRP *Irp);
@ -1432,14 +1432,14 @@ typedef struct _CM_KEYBOARD_DEVICE_DATA {
USHORT KeyboardFlags;
} CM_KEYBOARD_DEVICE_DATA, *PCM_KEYBOARD_DEVICE_DATA;
#define KEYBOARD_INSERT_ON 0x80
#define KEYBOARD_CAPS_LOCK_ON 0x40
#define KEYBOARD_NUM_LOCK_ON 0x20
#define KEYBOARD_SCROLL_LOCK_ON 0x10
#define KEYBOARD_ALT_KEY_DOWN 0x08
#define KEYBOARD_CTRL_KEY_DOWN 0x04
#define KEYBOARD_LEFT_SHIFT_DOWN 0x02
#define KEYBOARD_RIGHT_SHIFT_DOWN 0x01
#define KEYBOARD_INSERT_ON 0x08
#define KEYBOARD_CAPS_LOCK_ON 0x04
#define KEYBOARD_NUM_LOCK_ON 0x02
#define KEYBOARD_SCROLL_LOCK_ON 0x01
#define KEYBOARD_ALT_KEY_DOWN 0x80
#define KEYBOARD_CTRL_KEY_DOWN 0x40
#define KEYBOARD_LEFT_SHIFT_DOWN 0x20
#define KEYBOARD_RIGHT_SHIFT_DOWN 0x10
typedef struct _CM_MCA_POS_DATA {
USHORT AdapterId;