Of course, I've added one level in directory structure in 24377. Delete the whole i8042prt driver and retry

(Sorry, this revision won't build)

svn path=/trunk/; revision=24378
This commit is contained in:
Hervé Poussineau
2006-10-03 18:03:28 +00:00
parent 273908b19f
commit 90b4dc09c7
23 changed files with 0 additions and 8208 deletions
-80
View File
@@ -1,80 +0,0 @@
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:
createclose.c: open/close devices functionnality
i8042prt.c: Main controller functionality, things shared by keyboards and mice
keyboard.c: keyboard functionality: detection, interrupt handling
misc.c: misc things, mostly related to Irp passing
mouse.c: mouse functionality: detection, interrupt handling, packet parsing for
standard ps2 and microsoft mice
pnp.c: Plug&Play functionnality
ps2pp.c: logitech ps2++ mouse packat parsing (basic)
readwrite.c: read/write to the i8042 controller
registry.c: registry reading
setup.c: add keyboard support during the 1st stage setup
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
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:
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.
@@ -1,55 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/createclose.c
* PURPOSE: IRP_MJ_CREATE, IRP_MJ_CLEANUP and IRP_MJ_CLOSE operations
* PROGRAMMERS: Copyright 2006 Hervé Poussineau ([email protected])
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS NTAPI
i8042Create(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("IRP_MJ_CREATE\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
i8042Cleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("IRP_MJ_CLEANUP\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
i8042Close(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("IRP_MJ_CLOSE\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
-524
View File
@@ -1,524 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/i8042prt.c
* PURPOSE: Driver entry function
* PROGRAMMERS: Copyright Victor Kirhenshtein ([email protected])
Copyright Jason Filby ([email protected])
Copyright Martijn Vernooij ([email protected])
Copyright 2006 Hervé Poussineau ([email protected])
*/
/* INCLUDES ******************************************************************/
#define INITGUID
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS NTAPI
i8042AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo)
{
PI8042_DRIVER_EXTENSION DriverExtension;
PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
PDEVICE_OBJECT Fdo = NULL;
ULONG DeviceExtensionSize;
NTSTATUS Status;
DPRINT("i8042AddDevice(%p %p)\n", DriverObject, Pdo);
DriverExtension = (PI8042_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject);
if (Pdo == NULL)
{
/* We're getting a NULL Pdo at the first call as
* we are a legacy driver. Ignore it */
return STATUS_SUCCESS;
}
/* Create new device object. As we don't know if the device would be a keyboard
* or a mouse, we have to allocate the biggest device extension. */
DeviceExtensionSize = MAX(sizeof(I8042_KEYBOARD_EXTENSION), sizeof(I8042_MOUSE_EXTENSION));
Status = IoCreateDevice(
DriverObject,
DeviceExtensionSize,
NULL,
Pdo->DeviceType,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Fdo);
if (!NT_SUCCESS(Status))
{
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
goto cleanup;
}
DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
DeviceExtension->Type = Unknown;
DeviceExtension->Fdo = Fdo;
DeviceExtension->Pdo = Pdo;
DeviceExtension->PortDeviceExtension = &DriverExtension->Port;
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
cleanup:
if (DeviceExtension && DeviceExtension->LowerDevice)
IoDetachDevice(DeviceExtension->LowerDevice);
if (Fdo)
IoDeleteDevice(Fdo);
return Status;
}
VOID NTAPI
i8042SendHookWorkItem(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context)
{
PI8042_HOOK_WORKITEM WorkItemData;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
PDEVICE_OBJECT TopOfStack = NULL;
ULONG IoControlCode;
PVOID InputBuffer;
ULONG InputBufferLength;
IO_STATUS_BLOCK IoStatus;
KEVENT Event;
PIRP NewIrp;
NTSTATUS Status;
DPRINT("i8042SendHookWorkItem(%p %p)\n", DeviceObject, Context);
WorkItemData = (PI8042_HOOK_WORKITEM)Context;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
PortDeviceExtension = FdoDeviceExtension->PortDeviceExtension;
switch (FdoDeviceExtension->Type)
{
case Keyboard:
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
InputBuffer = &DeviceExtension->KeyboardHook;
InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
break;
}
case Mouse:
{
PI8042_MOUSE_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_MOUSE_EXTENSION)FdoDeviceExtension;
IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
InputBuffer = &DeviceExtension->MouseHook;
InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
break;
}
default:
{
DPRINT1("Unknown FDO type %u\n", FdoDeviceExtension->Type);
ASSERT(FALSE);
WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
goto cleanup;
}
}
KeInitializeEvent(&Event, NotificationEvent, FALSE);
TopOfStack = IoGetAttachedDeviceReference(DeviceObject);
NewIrp = IoBuildDeviceIoControlRequest(
IoControlCode,
TopOfStack,
InputBuffer,
InputBufferLength,
NULL,
0,
TRUE,
&Event,
&IoStatus);
if (!NewIrp)
{
DPRINT("IoBuildDeviceIoControlRequest() failed\n");
WorkItemData->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
Status = IoCallDriver(TopOfStack, NewIrp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(
&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatus.Status;
}
if (!NT_SUCCESS(Status))
{
DPRINT("IoCallDriver() failed with status 0x%08lx\n", Status);
goto cleanup;
}
if (FdoDeviceExtension->Type == Keyboard)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
/* Call the hooked initialization if it exists */
if (DeviceExtension->KeyboardHook.InitializationRoutine)
{
Status = DeviceExtension->KeyboardHook.InitializationRoutine(
DeviceExtension->KeyboardHook.Context,
PortDeviceExtension,
i8042SynchReadPort,
i8042SynchWritePortKbd,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT("KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status);
WorkItemData->Irp->IoStatus.Status = Status;
goto cleanup;
}
}
}
#if 0
else
{
/* Mouse doesn't have this, but we need to send a
* reset to start the detection.
*/
KIRQL Irql;
Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
i8042Write(PortDeviceExtension, PortDeviceExtension->ControlPort, CTRL_WRITE_MOUSE);
i8042Write(PortDeviceExtension, PortDeviceExtension->DataPort, MOU_CMD_RESET);
KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
#endif
WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
cleanup:
if (TopOfStack != NULL)
ObDereferenceObject(TopOfStack);
WorkItemData->Irp->IoStatus.Information = 0;
IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
IoFreeWorkItem(WorkItemData->WorkItem);
ExFreePool(WorkItemData);
}
static VOID NTAPI
i8042StartIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
switch (DeviceExtension->Type)
{
case Keyboard:
i8042KbdStartIo(DeviceObject, Irp);
break;
default:
DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
ASSERT(FALSE);
break;
}
}
/* Write the current byte of the packet. Returns FALSE in case
* of problems.
*/
static BOOLEAN
i8042PacketWrite(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
UCHAR Port = DeviceExtension->PacketPort;
if (Port)
{
if (!i8042Write(DeviceExtension,
DeviceExtension->ControlPort,
Port))
{
/* something is really wrong! */
DPRINT1("Failed to send packet byte!\n");
return FALSE;
}
}
return i8042Write(DeviceExtension,
DeviceExtension->DataPort,
DeviceExtension->Packet.Bytes[DeviceExtension->Packet.CurrentByte]);
}
BOOLEAN
i8042PacketIsr(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Output)
{
if (DeviceExtension->Packet.State == Idle)
return FALSE;
switch (Output)
{
case KBD_RESEND:
DeviceExtension->PacketResends++;
if (DeviceExtension->PacketResends > DeviceExtension->Settings.ResendIterations)
{
DeviceExtension->Packet.State = Idle;
DeviceExtension->PacketComplete = TRUE;
DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
DeviceExtension->PacketResends = 0;
return TRUE;
}
DeviceExtension->Packet.CurrentByte--;
break;
case KBD_NACK:
DeviceExtension->Packet.State = Idle;
DeviceExtension->PacketComplete = TRUE;
DeviceExtension->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
DeviceExtension->PacketResends = 0;
return TRUE;
default:
DeviceExtension->PacketResends = 0;
}
if (DeviceExtension->Packet.CurrentByte >= DeviceExtension->Packet.ByteCount)
{
DeviceExtension->Packet.State = Idle;
DeviceExtension->PacketComplete = TRUE;
DeviceExtension->PacketResult = STATUS_SUCCESS;
return TRUE;
}
if (!i8042PacketWrite(DeviceExtension))
{
DeviceExtension->Packet.State = Idle;
DeviceExtension->PacketComplete = TRUE;
DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
return TRUE;
}
DeviceExtension->Packet.CurrentByte++;
return TRUE;
}
/*
* This function starts a packet. It must be called with the
* correct DIRQL.
*/
NTSTATUS
i8042StartPacket(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
IN PUCHAR Bytes,
IN ULONG ByteCount,
IN PIRP Irp)
{
KIRQL Irql;
NTSTATUS Status;
Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
if (DeviceExtension->Packet.State != Idle)
{
Status = STATUS_DEVICE_BUSY;
goto done;
}
switch (FdoDeviceExtension->Type)
{
case Keyboard: DeviceExtension->PacketPort = 0; break;
case Mouse: DeviceExtension->PacketPort = CTRL_WRITE_MOUSE; break;
default:
DPRINT1("Unknown FDO type %u\n", FdoDeviceExtension->Type);
ASSERT(FALSE);
Status = STATUS_INTERNAL_ERROR;
goto done;
}
DeviceExtension->Packet.Bytes = Bytes;
DeviceExtension->Packet.CurrentByte = 0;
DeviceExtension->Packet.ByteCount = ByteCount;
DeviceExtension->Packet.State = SendingBytes;
DeviceExtension->PacketResult = Status = STATUS_PENDING;
DeviceExtension->CurrentIrp = Irp;
DeviceExtension->CurrentIrpDevice = FdoDeviceExtension->Fdo;
if (!i8042PacketWrite(DeviceExtension))
{
Status = STATUS_IO_TIMEOUT;
DeviceExtension->Packet.State = Idle;
DeviceExtension->PacketResult = STATUS_ABANDONED;
goto done;
}
DeviceExtension->Packet.CurrentByte++;
done:
KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
if (Status != STATUS_PENDING)
{
DeviceExtension->CurrentIrp = NULL;
DeviceExtension->CurrentIrpDevice = NULL;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}
static NTSTATUS NTAPI
IrpStub(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
KEBUGCHECK(0);
return STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS NTAPI
i8042DeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
DPRINT("i8042DeviceControl(%p %p)\n", DeviceObject, Irp);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
switch (DeviceExtension->Type)
{
case Keyboard:
return i8042KbdDeviceControl(DeviceObject, Irp);
break;
default:
return IrpStub(DeviceObject, Irp);
}
return Status;
}
static NTSTATUS NTAPI
i8042InternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
ULONG ControlCode;
NTSTATUS Status;
DPRINT("i8042InternalDeviceControl(%p %p)\n", DeviceObject, Irp);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
switch (DeviceExtension->Type)
{
case Unknown:
{
ControlCode = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode;
switch (ControlCode)
{
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
break;
case IOCTL_INTERNAL_MOUSE_CONNECT:
Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
break;
default:
DPRINT1("Unknown IO control code 0x%lx\n", ControlCode);
ASSERT(FALSE);
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
break;
}
case Keyboard:
Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
break;
case Mouse:
Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
break;
default:
DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
ASSERT(FALSE);
Status = STATUS_INTERNAL_ERROR;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
return Status;
}
NTSTATUS NTAPI
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
PI8042_DRIVER_EXTENSION DriverExtension;
ULONG i;
NTSTATUS Status;
Status = IoAllocateDriverObjectExtension(
DriverObject,
DriverObject,
sizeof(I8042_DRIVER_EXTENSION),
(PVOID*)&DriverExtension);
if (!NT_SUCCESS(Status))
{
DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
return Status;
}
RtlZeroMemory(DriverExtension, sizeof(I8042_DRIVER_EXTENSION));
KeInitializeSpinLock(&DriverExtension->Port.SpinLock);
Status = RtlDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
RegistryPath,
&DriverExtension->RegistryPath);
if (!NT_SUCCESS(Status))
{
DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
return Status;
}
Status = ReadRegistryEntries(RegistryPath, &DriverExtension->Port.Settings);
if (!NT_SUCCESS(Status))
{
DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
return Status;
}
DriverObject->DriverExtension->AddDevice = i8042AddDevice;
DriverObject->DriverStartIo = i8042StartIo;
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = IrpStub;
DriverObject->MajorFunction[IRP_MJ_CREATE] = i8042Create;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = i8042Cleanup;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = i8042Close;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = i8042DeviceControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = i8042InternalDeviceControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = i8042Pnp;
if (IsFirstStageSetup())
return i8042AddLegacyKeyboard(DriverObject, RegistryPath);
return STATUS_SUCCESS;
}
-488
View File
@@ -1,488 +0,0 @@
#ifndef _I8042PRT_H_
#define _I8042PRT_H_
#include <ntifs.h>
#include <kbdmou.h>
#include <ntdd8042.h>
#include <ntddkbd.h>
#include <bugcodes.h>
#include <poclass.h>
/*-----------------------------------------------------
* Structures
* --------------------------------------------------*/
typedef enum
{
dsStopped,
dsStarted,
dsPaused,
dsRemoved,
dsSurpriseRemoved
} DEVICE_STATE;
typedef struct _I8042_SETTINGS
{
/* Registry settings */
ULONG KeyboardDataQueueSize; /* done */
UNICODE_STRING KeyboardDeviceBaseName;
ULONG MouseDataQueueSize; /* done */
ULONG MouseResolution;
ULONG MouseSynchIn100ns;
ULONG NumberOfButtons;
UNICODE_STRING PointerDeviceBaseName;
ULONG PollStatusIterations; /* done */
ULONG OverrideKeyboardType;
ULONG OverrideKeyboardSubtype;
ULONG PollingIterations; /* done */
ULONG PollingIterationsMaximum;
ULONG ResendIterations; /* done */
ULONG SampleRate;
ULONG CrashOnCtrlScroll; /* done */
} I8042_SETTINGS, *PI8042_SETTINGS;
typedef enum _MOUSE_TIMEOUT_STATE
{
NoChange,
TimeoutStart,
TimeoutCancel
} MOUSE_TIMEOUT_STATE, *PMOUSE_TIMEOUT_STATE;
typedef struct _INTERRUPT_DATA
{
PKINTERRUPT Object;
ULONG Vector;
KIRQL Dirql;
KINTERRUPT_MODE InterruptMode;
BOOLEAN ShareInterrupt;
KAFFINITY Affinity;
} INTERRUPT_DATA, *PINTERRUPT_DATA;
#define WHEEL_DELTA 120
struct _I8042_KEYBOARD_EXTENSION;
typedef struct _I8042_KEYBOARD_EXTENSION *PI8042_KEYBOARD_EXTENSION;
struct _I8042_MOUSE_EXTENSION;
typedef struct _I8042_MOUSE_EXTENSION *PI8042_MOUSE_EXTENSION;
/* PORT_DEVICE_EXTENSION.Flags */
#define KEYBOARD_PRESENT 0x01 /* A keyboard is attached */
#define MOUSE_PRESENT 0x02 /* A mouse is attached */
#define KEYBOARD_CONNECTED 0x04 /* Keyboard received IOCTL_INTERNAL_KEYBOARD_CONNECT */
#define MOUSE_CONNECTED 0x08 /* Mouse received IOCTL_INTERNAL_MOUSE_CONNECT */
#define KEYBOARD_STARTED 0x04 /* Keyboard FDO received IRP_MN_START_DEVICE */
#define MOUSE_STARTED 0x08 /* Mouse FDO received IRP_MN_START_DEVICE */
#define KEYBOARD_INITIALIZED 0x10 /* Keyboard interrupt is connected */
#define MOUSE_INITIALIZED 0x20 /* Mouse interrupt is connected */
typedef struct _PORT_DEVICE_EXTENSION
{
PUCHAR DataPort; /* Usually 0x60 */
PUCHAR ControlPort; /* Usually 0x64 */
I8042_SETTINGS Settings;
ULONG Flags;
PI8042_KEYBOARD_EXTENSION KeyboardExtension;
INTERRUPT_DATA KeyboardInterrupt;
PI8042_MOUSE_EXTENSION MouseExtension;
INTERRUPT_DATA MouseInterrupt;
PKINTERRUPT HighestDIRQLInterrupt;
KSPIN_LOCK SpinLock;
KIRQL HighestDirql;
OUTPUT_PACKET Packet;
ULONG PacketResends;
BOOLEAN PacketComplete;
NTSTATUS PacketResult;
UCHAR PacketBuffer[16];
UCHAR PacketPort;
PIRP CurrentIrp;
PDEVICE_OBJECT CurrentIrpDevice;
} PORT_DEVICE_EXTENSION, *PPORT_DEVICE_EXTENSION;
typedef struct _I8042_DRIVER_EXTENSION
{
UNICODE_STRING RegistryPath;
PORT_DEVICE_EXTENSION Port;
} I8042_DRIVER_EXTENSION, *PI8042_DRIVER_EXTENSION;
typedef enum _I8042_DEVICE_TYPE
{
Unknown,
Keyboard,
Mouse,
PhysicalDeviceObject
} I8042_DEVICE_TYPE, *PI8042_DEVICE_TYPE;
typedef struct _FDO_DEVICE_EXTENSION
{
I8042_DEVICE_TYPE Type;
// Associated device object (FDO)
PDEVICE_OBJECT Fdo;
// Associated device object (PDO)
PDEVICE_OBJECT Pdo;
// Lower device object
PDEVICE_OBJECT LowerDevice;
// Current state of the driver
DEVICE_STATE PnpState;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
typedef struct _I8042_KEYBOARD_EXTENSION
{
FDO_DEVICE_EXTENSION Common;
CONNECT_DATA KeyboardData;
INTERNAL_I8042_HOOK_KEYBOARD KeyboardHook;
KDPC DpcKeyboard;
KEYBOARD_INDICATOR_PARAMETERS KeyboardIndicators;
KEYBOARD_SCAN_STATE KeyboardScanState;
BOOLEAN KeyComplete;
PKEYBOARD_INPUT_DATA KeyboardBuffer;
ULONG KeysInBuffer;
/* Power keys items */
ULONG ReportedCaps;
ULONG NewCaps;
ULONG LastPowerKey;
UNICODE_STRING PowerInterfaceName;
PIO_WORKITEM PowerWorkItem;
PIRP PowerIrp;
/* Debug items */
ULONG ComboPosition;
PIO_WORKITEM DebugWorkItem;
#ifdef __REACTOS__
ULONG DebugKey;
BOOLEAN TabPressed;
#endif
} I8042_KEYBOARD_EXTENSION;
typedef enum _I8042_MOUSE_TYPE
{
GenericPS2,
Intellimouse,
IntellimouseExplorer,
Ps2pp
} I8042_MOUSE_TYPE, *PI8042_MOUSE_TYPE;
typedef struct _I8042_MOUSE_EXTENSION
{
FDO_DEVICE_EXTENSION Common;
CONNECT_DATA MouseData;
INTERNAL_I8042_HOOK_MOUSE MouseHook;
KDPC DpcMouse;
MOUSE_ATTRIBUTES MouseAttributes;
MOUSE_STATE MouseState;
BOOLEAN MouseComplete;
MOUSE_RESET_SUBSTATE MouseResetState;
PMOUSE_INPUT_DATA MouseBuffer;
ULONG MouseInBuffer;
USHORT MouseButtonState;
ULARGE_INTEGER MousePacketStartTime;
KTIMER TimerMouseTimeout;
KDPC DpcMouseTimeout;
MOUSE_TIMEOUT_STATE MouseTimeoutState;
BOOLEAN MouseTimeoutActive;
UCHAR MouseLogiBuffer[3];
I8042_MOUSE_TYPE MouseType;
} I8042_MOUSE_EXTENSION;
typedef struct _I8042_HOOK_WORKITEM
{
PIO_WORKITEM WorkItem;
PIRP Irp;
} I8042_HOOK_WORKITEM, *PI8042_HOOK_WORKITEM;
/*-----------------------------------------------------
* Some defines
* --------------------------------------------------*/
#define MAX(a, b) ((a) >= (b) ? (a) : (b))
#define KEYBOARD_POWER_CODE 0x5E
#define KEYBOARD_SLEEP_CODE 0x5F
#define KEYBOARD_WAKE_CODE 0x63
/*-----------------------------------------------------
* Controller commands
* --------------------------------------------------*/
#define KBD_READ_MODE 0x20
#define KBD_WRITE_MODE 0x60
#define KBD_LINE_TEST 0xAB
#define MOUSE_LINE_TEST 0xA9
#define CTRL_SELF_TEST 0xAA
#define CTRL_WRITE_MOUSE 0xD4
/*-----------------------------------------------------
* Keyboard commands
* --------------------------------------------------*/
#define KBD_CMD_SET_LEDS 0xED
#define KBD_CMD_GET_ID 0xF2
/*-----------------------------------------------------
* Keyboard responses
* --------------------------------------------------*/
#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 MOU_OBF 0x20
#define KBD_PERR 0x80
/*-----------------------------------------------------
* Controller command byte bits
* --------------------------------------------------*/
#define CCB_KBD_INT_ENAB 0x01
#define CCB_MOUSE_INT_ENAB 0x02
#define CCB_SYSTEM_FLAG 0x04
#define CCB_KBD_DISAB 0x10
#define CCB_MOUSE_DISAB 0x20
#define CCB_TRANSLATE 0x40
/*-----------------------------------------------------
* LED bits
* --------------------------------------------------*/
#define KBD_LED_SCROLL 0x01
#define KBD_LED_NUM 0x02
#define KBD_LED_CAPS 0x04
/*-----------------------------------------------------
* Mouse commands
* --------------------------------------------------*/
#define MOU_CMD_GET_ID 0xF2
#define MOU_CMD_RESET 0xFF
/*-----------------------------------------------------
* Mouse responses
* --------------------------------------------------*/
#define MOUSE_ACK 0xFA
#define MOUSE_ERROR 0xFC
#define MOUSE_NACK 0xFE
/*-----------------------------------------------------
* Prototypes
* --------------------------------------------------*/
/* createclose.c */
VOID NTAPI
i8042SendHookWorkItem(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context);
NTSTATUS NTAPI
i8042Create(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS NTAPI
i8042Cleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS NTAPI
i8042Close(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
/* keyboard.c */
NTSTATUS NTAPI
i8042SynchWritePortKbd(
IN PVOID Context,
IN UCHAR Value,
IN BOOLEAN WaitForAck);
BOOLEAN
i8042KbdStartIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
i8042KbdDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
i8042KbdInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
BOOLEAN NTAPI
i8042KbdInterruptService(
IN PKINTERRUPT Interrupt,
PVOID Context);
/* i8042prt.c */
NTSTATUS NTAPI
i8042AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo);
BOOLEAN
i8042PacketIsr(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Output);
NTSTATUS
i8042StartPacket(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
IN PUCHAR Bytes,
IN ULONG ByteCount,
IN PIRP Irp);
/* misc.c */
NTSTATUS NTAPI
ForwardIrpAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
/* mouse.c */
VOID
i8042MouHandle(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Output);
VOID
i8042MouHandleButtons(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN USHORT Mask);
NTSTATUS
i8042MouInitialize(
IN PI8042_MOUSE_EXTENSION DeviceExtension);
NTSTATUS
i8042MouInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
BOOLEAN NTAPI
i8042MouInterruptService(
IN PKINTERRUPT Interrupt,
PVOID Context);
VOID NTAPI
i8042MouQueuePacket(
IN PVOID Context);
/* pnp.c */
BOOLEAN
i8042ChangeMode(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR FlagsToDisable,
IN UCHAR FlagsToEnable);
NTSTATUS NTAPI
i8042Pnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
/* ps2pp.c */
VOID
i8042MouHandlePs2pp(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Input);
/* readwrite.c */
VOID
i8042Flush(
IN PPORT_DEVICE_EXTENSION DeviceExtension);
VOID
i8042IsrWritePort(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Value,
IN UCHAR SelectCmd OPTIONAL);
NTSTATUS
i8042ReadData(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR StatusFlags,
OUT PUCHAR Data);
#define i8042ReadKeyboardData(DeviceExtension, Data) \
i8042ReadData(DeviceExtension, KBD_OBF, Data)
#define i8042ReadMouseData(DeviceExtension, Data) \
i8042ReadData(DeviceExtension, MOU_OBF, Data)
NTSTATUS
i8042ReadDataWait(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
OUT PUCHAR Data);
NTSTATUS
i8042ReadStatus(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
OUT PUCHAR Status);
NTSTATUS NTAPI
i8042SynchReadPort(
IN PVOID Context,
IN PUCHAR Value,
IN BOOLEAN WaitForAck);
NTSTATUS NTAPI
i8042SynchWritePort(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Port,
IN UCHAR Value,
IN BOOLEAN WaitForAck);
BOOLEAN
i8042Write(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN PUCHAR addr,
IN UCHAR data);
/* registry.c */
NTSTATUS
ReadRegistryEntries(
IN PUNICODE_STRING RegistryPath,
OUT PI8042_SETTINGS Settings);
/* setup.c */
BOOLEAN
IsFirstStageSetup(
VOID);
NTSTATUS
i8042AddLegacyKeyboard(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
#endif // _I8042PRT_H_
@@ -1,18 +0,0 @@
<module name="i8042prt" type="kernelmodedriver" installbase="system32/drivers" installname="i8042prt.sys">
<bootstrap base="reactos" />
<define name="__USE_W32API" />
<define name="__REACTOS__" />
<library>ntoskrnl</library>
<library>hal</library>
<file>createclose.c</file>
<file>i8042prt.c</file>
<file>keyboard.c</file>
<file>misc.c</file>
<file>mouse.c</file>
<file>pnp.c</file>
<file>ps2pp.c</file>
<file>readwrite.c</file>
<file>registry.c</file>
<file>setup.c</file>
<file>i8042prt.rc</file>
</module>
@@ -1,5 +0,0 @@
#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>
@@ -1,83 +0,0 @@
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.
@@ -1,927 +0,0 @@
/*
* 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 ([email protected])
* Jason Filby ([email protected])
* Tinus
*/
/* INCLUDES ****************************************************************/
#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
UNICODE_STRING I8042RegistryPath;
/* FUNCTIONS *****************************************************************/
/*
* FUNCTION: Write data to a port, waiting first for it to become ready
*/
BOOLEAN I8042Write(PDEVICE_EXTENSION DevExt, PUCHAR addr, UCHAR data)
{
ULONG ResendIterations = DevExt->Settings.PollingIterations;
while ((KBD_IBF & READ_PORT_UCHAR(I8042_CTRL_PORT)) &&
(ResendIterations--))
{
KeStallExecutionProcessor(50);
}
if (ResendIterations) {
WRITE_PORT_UCHAR(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, UCHAR 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(UCHAR *Data)
{
UCHAR Status;
Status=READ_PORT_UCHAR(I8042_CTRL_PORT);
// If data is available
if ((Status & KBD_OBF)) {
Data[0]=READ_PORT_UCHAR((PUCHAR)I8042_DATA_PORT);
DPRINT("Read: %x (status: %x)\n", Data[0], Status);
// If the data is valid (not timeout, not parity error)
if (0 == (Status & KBD_PERR))
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS I8042ReadStatus(UCHAR *Status)
{
Status[0]=READ_PORT_UCHAR(I8042_CTRL_PORT);
return STATUS_SUCCESS;
}
/*
* FUNCTION: Read data from port 0x60
*/
NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *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()
{
UCHAR Ignore;
while (STATUS_SUCCESS == I8042ReadData(&Ignore)) {
DPRINT("Data flushed\n"); /* 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;
ULONG ResendIterations = DevExt->Settings.ResendIterations + 1;
do {
if (Port)
if (!I8042Write(DevExt, I8042_DATA_PORT, Port))
{
DPRINT1("Failed to write Port\n");
return STATUS_IO_TIMEOUT;
}
if (!I8042Write(DevExt, I8042_DATA_PORT, Value))
{
DPRINT1("Failed to write Value\n");
return STATUS_IO_TIMEOUT;
}
if (WaitForAck) {
Status = I8042ReadDataWait(DevExt, &Ack);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to read Ack\n");
return Status;
}
if (Ack == KBD_ACK)
return STATUS_SUCCESS;
if (Ack != KBD_RESEND)
{
DPRINT1("Unexpected Ack 0x%x\n", Ack);
return STATUS_UNEXPECTED_IO_ERROR;
}
} else {
return STATUS_SUCCESS;
}
DPRINT("Reiterating\n");
ResendIterations--;
} while (ResendIterations);
return STATUS_IO_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_IO_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_IO_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_IO_TIMEOUT;
return TRUE;
}
DevExt->Packet.CurrentByte++;
return TRUE;
}
VOID I8042PacketDpc(PDEVICE_EXTENSION DevExt)
{
BOOLEAN 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;
}
#if 0
Status = IoCallDriver(
WorkItemData->Target,
NewIrp);
if (STATUS_PENDING == Status)
KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
#endif
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 (!NT_SUCCESS(Status)) {
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");
}
static VOID STDCALL I8042StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
if (!I8042StartIoKbd(DeviceObject, Irp)) {
DPRINT1("Unhandled StartIo!\n");
}
}
static 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;
}
static 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 = 0;
ULONG Counter;
DevExt->MouseExists = FALSE;
DevExt->KeyboardExists = FALSE;
I8042Flush();
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST)) {
DPRINT1("Writing KBD_SELF_TEST command failed\n");
return STATUS_IO_TIMEOUT;
}
// Wait longer?
Counter = 10;
do {
Status = I8042ReadDataWait(DevExt, &Value);
} while ((Counter--) && (STATUS_IO_TIMEOUT == Status));
if (!NT_SUCCESS(Status)) {
DPRINT1("Failed to read KBD_SELF_TEST response, status 0x%x\n",
Status);
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_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value |= CCB_KBD_DISAB | CCB_MOUSE_DISAB; /* disable keyboard/mouse */
Value &= ~(CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB);
/* don't enable keyboard and 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;
}
/*
* We used to send a KBD_LINE_TEST command here, but on at least HP
* Pavilion notebooks the response to that command was incorrect.
* So now we just assume that a keyboard is attached.
*/
DevExt->KeyboardExists = TRUE;
if (I8042Write(DevExt, I8042_CTRL_PORT, MOUSE_LINE_TEST))
{
Status = I8042ReadDataWait(DevExt, &Value);
if (NT_SUCCESS(Status) && Value == 0)
DevExt->MouseExists = TRUE;
}
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL I8042Initialize(PDEVICE_EXTENSION DevExt)
{
NTSTATUS Status;
Status = I8042BasicDetect(DevExt);
if (!NT_SUCCESS(Status)) {
DPRINT1("Basic keyboard detection failed: %x\n", Status);
return Status;
}
if (DevExt->MouseExists) {
DPRINT("Aux port detected\n");
DevExt->MouseExists = I8042DetectMouse(DevExt);
}
if (!DevExt->KeyboardExists) {
DPRINT("Keyboard port not detected\n");
if (DevExt->Settings.Headless)
/* Act as if it exists regardless */
DevExt->KeyboardExists = TRUE;
} else {
DPRINT("Keyboard port detected\n");
DevExt->KeyboardExists = I8042DetectKeyboard(DevExt);
}
if (DevExt->KeyboardExists) {
DPRINT("Keyboard detected\n");
I8042KeyboardEnable(DevExt);
I8042KeyboardEnableInterrupt(DevExt);
}
if (DevExt->MouseExists) {
DPRINT("Mouse detected\n");
I8042MouseEnable(DevExt);
}
return STATUS_SUCCESS;
}
static NTSTATUS
AddRegistryEntry(
IN PCWSTR PortTypeName,
IN PUNICODE_STRING DeviceName,
IN PCWSTR RegistryPath)
{
UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hDeviceMapKey = (HANDLE)-1;
HANDLE hPortKey = (HANDLE)-1;
UNICODE_STRING PortTypeNameU;
NTSTATUS Status;
InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
if (!NT_SUCCESS(Status))
{
DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
Status = STATUS_SUCCESS;
cleanup:
if (hDeviceMapKey != (HANDLE)-1)
ZwClose(hDeviceMapKey);
if (hPortKey != (HANDLE)-1)
ZwClose(hPortKey);
return Status;
}
static NTSTATUS STDCALL I8042AddDevice(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT Pdo)
{
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPort8042");
UNICODE_STRING MouseName = RTL_CONSTANT_STRING(L"\\Device\\PointerPort8042");
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");
if (Pdo != NULL)
{
/* Device detected by pnpmgr. Ignore it, as we already have
* detected the keyboard and mouse at first call */
return STATUS_UNSUCCESSFUL;
}
Status = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
NULL,
FILE_DEVICE_8042_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Fdo);
if (!NT_SUCCESS(Status))
return Status;
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);
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
if (!NT_SUCCESS(STATUS_SUCCESS)) {
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);
if (NT_SUCCESS(Status))
{
AddRegistryEntry(L"KeyboardPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
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);
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
}
else
DevExt->KeyboardExists = FALSE;
}
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);
if (NT_SUCCESS(Status))
{
AddRegistryEntry(L"PointerPort", &MouseName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\i8042prt");
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) {
ExFreePoolWithTag(DevExt->KeyboardBuffer, TAG_I8042);
DPRINT1("No memory for mouse buffer\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
InsertTailList(&DevExt->BusDevices, &FdoDevExt->BusDevices);
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
}
else
DevExt->MouseExists = FALSE;
}
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");
I8042RegistryPath.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters");
I8042RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
I8042RegistryPath.MaximumLength,
TAG_I8042);
if (I8042RegistryPath.Buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyUnicodeString(&I8042RegistryPath, RegistryPath);
RtlAppendUnicodeToString(&I8042RegistryPath, L"\\Parameters");
I8042RegistryPath.Buffer[I8042RegistryPath.Length / sizeof(WCHAR)] = 0;
DriverObject->MajorFunction[IRP_MJ_CREATE] = I8042CreateDispatch;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
I8042InternalDeviceControl;
DriverObject->DriverStartIo = I8042StartIo;
DriverObject->DriverExtension->AddDevice = I8042AddDevice;
return(STATUS_SUCCESS);
}
@@ -1,378 +0,0 @@
#ifndef _I8042DRV_H
#define _I8042DRV_H
#include <ntddk.h>
#include <kbdmou.h>
#include <ntdd8042.h>
#ifdef _MSC_VER
#define STDCALL
#define DDKAPI
#endif
#define KEYBOARD_IRQ 1
#define MOUSE_IRQ 12
#define KBD_BUFFER_SIZE 32
#define WHEEL_DELTA 120
/*-----------------------------------------------------
* 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
{
ULONG Headless; /* done */
ULONG CrashScroll;
ULONG CrashSysRq; /* done */
ULONG ReportResetErrors;
ULONG PollStatusIterations; /* done */
ULONG ResendIterations; /* done */
ULONG PollingIterations;
ULONG PollingIterationsMaximum;
ULONG OverrideKeyboardType;
ULONG OverrideKeyboardSubtype;
ULONG MouseResendStallTime;
ULONG MouseSynchIn100ns; /* done */
ULONG MouseResolution; /* done */
ULONG NumberOfButtons;
ULONG 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;
ULARGE_INTEGER MousePacketStartTime;
UCHAR MouseLogiBuffer[3];
UCHAR MouseLogitechID;
I8042_MOUSE_TYPE MouseType;
OUTPUT_PACKET Packet;
ULONG 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(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
#define TAG_I8042 TAG('8', '0', '4', '2')
#define KBD_WRAP_MASK 0x1F
#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 ((PUCHAR)0x60)
#define I8042_CTRL_PORT ((PUCHAR)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
/*
* Controller command byte bits
*/
#define CCB_KBD_INT_ENAB 0x01
#define CCB_MOUSE_INT_ENAB 0x02
#define CCB_SYSTEM_FLAG 0x04
#define CCB_IGN_KEY_LOCK 0x08
#define CCB_KBD_DISAB 0x10
#define CCB_MOUSE_DISAB 0x20
#define CCB_TRANSLATE 0x40
/*
* 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 */
extern UNICODE_STRING I8042RegistryPath;
NTSTATUS I8042ReadData(UCHAR *Data);
NTSTATUS I8042ReadStatus(UCHAR *Status);
NTSTATUS I8042ReadDataWait(PDEVICE_EXTENSION DevExt, UCHAR *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, PUCHAR addr, UCHAR data);
NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath);
/* 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,
UCHAR Output);
BOOLEAN STDCALL I8042MouseEnable(PDEVICE_EXTENSION DevExt);
BOOLEAN STDCALL I8042MouseDisable(PDEVICE_EXTENSION DevExt);
BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt);
/* ps2pp.c */
VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR Input);
#endif // _KEYBOARD_H_
@@ -1,14 +0,0 @@
<module name="i8042prt" type="kernelmodedriver" installbase="system32/drivers" installname="i8042prt.sys">
<bootstrap base="reactos" />
<include base="i8042prt">.</include>
<define name="__USE_W32API" />
<define name="__REACTOS__" />
<library>ntoskrnl</library>
<library>hal</library>
<file>i8042prt.c</file>
<file>keyboard.c</file>
<file>mouse.c</file>
<file>ps2pp.c</file>
<file>registry.c</file>
<file>i8042prt.rc</file>
</module>
@@ -1,5 +0,0 @@
#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>
@@ -1,776 +0,0 @@
/*
* 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 ([email protected])
* Jason Filby ([email protected])
* Tinus
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
static UCHAR 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)
{
UCHAR Output;
UCHAR PortStatus;
NTSTATUS Status;
PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
BOOLEAN HookContinue = FALSE, HookReturn;
ULONG 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) {
DPRINT("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;
((PSERVICE_CALLBACK_ROUTINE) 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 UCHAR I8042GetTypematicByte(USHORT Rate, USHORT Delay)
{
UCHAR 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;
}
/* This is all pretty confusing. There's more than one way to
* disable/enable the keyboard. You can send KBD_ENABLE to the
* keyboard, and it will start scanning keys. Sending KBD_DISABLE
* will disable the key scanning but also reset the parameters to
* defaults.
*
* You can also send 0xAE to the controller for enabling the
* keyboard clock line and 0xAD for disabling it. Then it'll
* automatically get turned on at the next command. The last
* way is by modifying the bit that drives the clock line in the
* 'command byte' of the controller. This is almost, but not quite,
* the same as the AE/AD thing. The difference can be used to detect
* some really old broken keyboard controllers which I hope won't be
* necessary.
*
* We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
* some kvm switches.
*/
BOOLEAN STDCALL I8042KeyboardEnable(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Enable keyboard\n");
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value &= ~CCB_KBD_DISAB; // don't disable keyboard
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;
}
static BOOLEAN STDCALL I8042KeyboardDefaultsAndDisable(PDEVICE_EXTENSION DevExt)
{
UCHAR Value;
NTSTATUS Status;
DPRINT("Disabling keyboard\n");
if (!I8042Write(DevExt, I8042_CTRL_PORT, KBD_READ_MODE)) {
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value |= CCB_KBD_DISAB; // disable keyboard
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 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 (!NT_SUCCESS(Status)) {
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value &= ~CCB_KBD_DISAB; // don't disable keyboard
Value |= CCB_KBD_INT_ENAB; // 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;
UCHAR Value2;
ULONG RetryCount = 10;
DPRINT("Detecting keyboard\n");
I8042KeyboardDefaultsAndDisable(DevExt);
do {
I8042Flush();
Status = I8042SynchWritePort(DevExt, 0, KBD_GET_ID, TRUE);
} while (STATUS_IO_TIMEOUT == Status && RetryCount--);
if (!NT_SUCCESS(Status)) {
DPRINT1("Can't write GET_ID (%x)\n", Status);
/* Could be an AT keyboard */
DevExt->KeyboardIsAT = TRUE;
goto detectsetleds;
}
Status = I8042ReadDataWait(DevExt, &Value);
if (!NT_SUCCESS(Status)) {
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;
}
Status = I8042ReadDataWait(DevExt, &Value2);
if (!NT_SUCCESS(Status)) {
DPRINT("Partial ID\n");
return FALSE;
}
DPRINT("Keyboard ID: 0x%x 0x%x\n", Value, Value2);
detectsetleds:
I8042Flush(); /* Flush any bytes left over from GET_ID */
Status = I8042SynchWritePort(DevExt, 0, KBD_SET_LEDS, TRUE);
if (!NT_SUCCESS(Status)) {
DPRINT("Can't write SET_LEDS (%x)\n", Status);
return FALSE;
}
Status = I8042SynchWritePort(DevExt, 0, 0, TRUE);
if (!NT_SUCCESS(Status)) {
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 (!NT_SUCCESS(Status)) {
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);
#define EnterDebugger ((PVOID)0x25)
static VOID STDCALL I8042DebugWorkItem(PDEVICE_OBJECT DeviceObject,
PVOID Context)
{
ULONG Key;
PFDO_DEVICE_EXTENSION FdoDevExt = DeviceObject->DeviceExtension;
PDEVICE_EXTENSION DevExt = FdoDevExt->PortDevExt;
Key = InterlockedExchange((PLONG)&DevExt->DebugKey, 0);
DPRINT("Debug key: %x\n", Key);
if (!Key)
return;
#ifdef __REACTOS__
/* We hope kernel would understand this. If
* that's not the case, nothing would happen.
*/
KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
#endif /* __REACTOS__ */
}
@@ -1,948 +0,0 @@
/*
* 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 ([email protected])
* Jason Filby ([email protected])
* Tinus
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/*
* These functions are callbacks for filter driver custom interrupt
* service routines.
*/
static VOID STDCALL I8042IsrWritePortMouse(PVOID Context,
UCHAR Value)
{
I8042IsrWritePort(Context, Value, 0xD4);
}
#if 0
static NTSTATUS STDCALL I8042SynchWritePortMouse(PVOID Context,
UCHAR Value,
BOOLEAN WaitForAck)
{
return I8042SynchWritePort((PDEVICE_EXTENSION)Context,
0xD4,
Value,
WaitForAck);
}
#endif
/* Test if packets are taking too long to come in. If they do, we
* might have gotten out of sync and should just drop what we have.
*
* If we want to be totally right, we'd also have to keep a count of
* errors, and totally reset the mouse after too much of them (can
* happen if the user is using a KVM switch and an OS on another port
* resets the mouse, or if the user hotplugs the mouse, or if we're just
* generally unlucky). Also note the input parsing routine where we
* drop invalid input packets.
*/
static VOID STDCALL I8042MouseInputTestTimeout(PDEVICE_EXTENSION DevExt)
{
ULARGE_INTEGER Now;
if (DevExt->MouseState == MouseExpectingACK ||
DevExt->MouseState == MouseResetting)
return;
Now.QuadPart = KeQueryInterruptTime();
if (DevExt->MouseState != MouseIdle) {
/* Check if the last byte came too long ago */
if (Now.QuadPart - DevExt->MousePacketStartTime.QuadPart >
DevExt->Settings.MouseSynchIn100ns) {
DPRINT("Mouse input packet timeout\n");
DevExt->MouseState = MouseIdle;
}
}
if (DevExt->MouseState == MouseIdle)
DevExt->MousePacketStartTime.QuadPart = Now.QuadPart;
}
/*
* 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)
*/
static 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;
}
static BOOLEAN STDCALL I8042MouseResetIsr(PDEVICE_EXTENSION DevExt,
UCHAR Status,
PUCHAR Value)
{
BOOLEAN ToReturn = FALSE;
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,
(UCHAR)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,
(UCHAR)(DevExt->Settings.MouseResolution & 0xff));
DPRINT("%x\n", DevExt->Settings.MouseResolution);
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 = (USHORT)(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,
UCHAR 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 * -WHEEL_DELTA);
}
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)
{
UCHAR Output, PortStatus;
NTSTATUS Status;
PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION) Context;
ULONG 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;
}
I8042MouseInputTestTimeout(DevExt);
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;
((PSERVICE_CALLBACK_ROUTINE) 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.
*/
#if 0
static 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;
}
#endif
/*
* 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 (!NT_SUCCESS(Status)) {
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 (!NT_SUCCESS(Status)) {
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;
}
BOOLEAN STDCALL I8042DetectMouse(PDEVICE_EXTENSION DevExt)
{
BOOLEAN Ok = TRUE;
NTSTATUS Status;
UCHAR Value;
UCHAR ExpectedReply[] = { 0xFA, 0xAA, 0x00 };
unsigned ReplyByte;
if (! I8042Write(DevExt, I8042_CTRL_PORT, 0xD4) ||
! I8042Write(DevExt, I8042_DATA_PORT, 0xFF))
{
DPRINT1("Failed to write reset command to mouse\n");
Ok = FALSE;
}
for (ReplyByte = 0;
ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]) && Ok;
ReplyByte++)
{
Status = I8042ReadDataWait(DevExt, &Value);
if (! NT_SUCCESS(Status))
{
DPRINT1("No ACK after mouse reset, status 0x%08x\n",
Status);
Ok = FALSE;
}
else if (Value != ExpectedReply[ReplyByte])
{
DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
Value, ExpectedReply[ReplyByte]);
Ok = FALSE;
}
}
if (! Ok)
{
/* There is probably no mouse present. On some systems,
the probe locks the entire keyboard controller. Let's
try to get access to the keyboard again by sending a
reset */
I8042Flush();
I8042Write(DevExt, I8042_CTRL_PORT, KBD_SELF_TEST);
I8042ReadDataWait(DevExt, &Value);
I8042Flush();
}
DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
return Ok;
}
@@ -1,137 +0,0 @@
/*
* 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 ****************************************************************/
#ifndef NDEBUG
#define NDEBUG
#endif
#include <debug.h>
#include "i8042prt.h"
VOID I8042MouseHandlePs2pp(PDEVICE_EXTENSION DevExt, UCHAR 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");
}
}
@@ -1,211 +0,0 @@
/*
* 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 ([email protected])
* Jason Filby ([email protected])
* Tinus
*/
/* INCLUDES ****************************************************************/
#ifndef NDEBUG
#define NDEBUG
#endif
#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[19];
NTSTATUS Status;
ULONG DefaultHeadless = 0;
ULONG DefaultCrashScroll = 0;
ULONG DefaultCrashSysRq = 0;
ULONG DefaultReportResetErrors = 0;
ULONG DefaultPollStatusIterations = 1;
ULONG DefaultResendIterations = 3;
ULONG DefaultPollingIterations = 12000;
ULONG DefaultPollingIterationsMaximum = 12000;
ULONG DefaultKeyboardDataQueueSize = 100;
ULONG DefaultOverrideKeyboardType = 0;
ULONG DefaultOverrideKeyboardSubtype = 0;
ULONG DefaultMouseDataQueueSize = 100;
ULONG DefaultMouseResendStallTime = 1000;
ULONG DefaultMouseSynchIn100ns = 20000000;
ULONG DefaultMouseResolution = 3;
ULONG DefaultSampleRate = 60;
ULONG DefaultNumberOfButtons = 2;
ULONG DefaultEnableWheelDetection = 1;
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[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parameters[15].Name = L"SampleRate";
Parameters[15].EntryContext = &DevExt->MouseAttributes.SampleRate;
Parameters[15].DefaultType = REG_DWORD;
Parameters[15].DefaultData = &DefaultSampleRate;
Parameters[15].DefaultLength = sizeof(ULONG);
Parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parameters[16].Name = L"NumberOfButtons";
Parameters[16].EntryContext = &DevExt->Settings.NumberOfButtons;
Parameters[16].DefaultType = REG_DWORD;
Parameters[16].DefaultData = &DefaultNumberOfButtons;
Parameters[16].DefaultLength = sizeof(ULONG);
Parameters[17].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parameters[17].Name = L"EnableWheelDetection";
Parameters[17].EntryContext = &DevExt->Settings.EnableWheelDetection;
Parameters[17].DefaultType = REG_DWORD;
Parameters[17].DefaultData = &DefaultEnableWheelDetection;
Parameters[17].DefaultLength = sizeof(ULONG);
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
I8042RegistryPath.Buffer,
Parameters,
NULL,
NULL);
if (!NT_SUCCESS(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;
DPRINT1 ("Can't read registry: %x\n", Status);
while (Current->Name) {
*((PULONG)Current->EntryContext) =
*((PULONG)Current->DefaultData);
Current++;
}
DPRINT1 ("Manually set defaults\n");
}
if (DevExt->Settings.MouseResolution > 3)
DevExt->Settings.MouseResolution = 3;
DPRINT("Done reading registry\n");
}
-875
View File
@@ -1,875 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/keyboard.c
* PURPOSE: Keyboard specific functions
* PROGRAMMERS: Copyright Victor Kirhenshtein ([email protected])
Copyright Jason Filby ([email protected])
Copyright Martijn Vernooij ([email protected])
Copyright 2006 Hervé Poussineau ([email protected])
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
/* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */
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}}};
/* FUNCTIONS *****************************************************************/
#ifdef __REACTOS__
/* Debug stuff */
VOID NTAPI
KdpServiceDispatcher(IN ULONG Code, IN PVOID Context1, IN PVOID Context2);
#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
static VOID NTAPI
i8042DebugWorkItem(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
ULONG Key;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
Key = InterlockedExchange((PLONG)&DeviceExtension->DebugKey, 0);
DPRINT("Debug key: 0x%02x\n", Key);
if (!Key)
return;
/* We hope kernel would understand this. If
* that's not the case, nothing would happen.
*/
KdpServiceDispatcher(TAG('R', 'o', 's', ' '), (PVOID)Key, NULL);
}
#endif
/*
* These functions are callbacks for filter driver custom interrupt
* service routines.
*/
/*static VOID NTAPI
i8042KbdIsrWritePort(
IN PVOID Context,
IN UCHAR Value)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
if (DeviceExtension->KeyboardHook.IsrWritePort)
{
DeviceExtension->KeyboardHook.IsrWritePort(
DeviceExtension->KeyboardHook.CallContext,
Value);
}
else
i8042IsrWritePort(Context, Value, 0);
}*/
static VOID NTAPI
i8042KbdQueuePacket(
IN PVOID Context)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
if (DeviceExtension->KeyboardHook.QueueKeyboardPacket)
{
DeviceExtension->KeyboardHook.QueueKeyboardPacket(
DeviceExtension->KeyboardHook.CallContext);
return;
}
DeviceExtension->KeyComplete = TRUE;
DeviceExtension->KeysInBuffer++;
if (DeviceExtension->KeysInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize)
{
DPRINT1("Keyboard buffer overflow\n");
DeviceExtension->KeysInBuffer--;
}
DPRINT("Irq completes key\n");
KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
}
/*
* These functions are callbacks for filter driver custom
* initialization routines.
*/
NTSTATUS NTAPI
i8042SynchWritePortKbd(
IN PVOID Context,
IN UCHAR Value,
IN BOOLEAN WaitForAck)
{
return i8042SynchWritePort(
(PPORT_DEVICE_EXTENSION)Context,
0,
Value,
WaitForAck);
}
/*
* Process the keyboard internal device requests
* returns FALSE if it doesn't understand the
* call so someone else can handle it.
*/
BOOLEAN
i8042KbdStartIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
PI8042_KEYBOARD_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
BOOLEAN Result = FALSE;
Stack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_KEYBOARD_SET_INDICATORS:
{
DPRINT("IOCTL_KEYBOARD_SET_INDICATORS\n");
PortDeviceExtension->PacketBuffer[0] = KBD_CMD_SET_LEDS;
PortDeviceExtension->PacketBuffer[1] = 0;
if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON)
PortDeviceExtension->PacketBuffer[1] |= KBD_LED_CAPS;
if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON)
PortDeviceExtension->PacketBuffer[1] |= KBD_LED_NUM;
if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON)
PortDeviceExtension->PacketBuffer[1] |= KBD_LED_SCROLL;
i8042StartPacket(
PortDeviceExtension,
&DeviceExtension->Common,
PortDeviceExtension->PacketBuffer,
2,
Irp);
break;
}
default:
{
DPRINT("Unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
}
}
return Result;
}
static VOID
i8042PacketDpc(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
BOOLEAN FinishIrp = FALSE;
KIRQL Irql;
NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */
/* If the interrupt happens before this is setup, the key
* was already in the buffer. Too bad! */
if (!DeviceExtension->HighestDIRQLInterrupt)
return;
Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
if (DeviceExtension->Packet.State == Idle
&& DeviceExtension->PacketComplete)
{
FinishIrp = TRUE;
Result = DeviceExtension->PacketResult;
DeviceExtension->PacketComplete = FALSE;
}
KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
if (!FinishIrp)
return;
if (DeviceExtension->CurrentIrp)
{
DeviceExtension->CurrentIrp->IoStatus.Status = Result;
IoCompleteRequest(DeviceExtension->CurrentIrp, IO_NO_INCREMENT);
IoStartNextPacket(DeviceExtension->CurrentIrpDevice, FALSE);
DeviceExtension->CurrentIrp = NULL;
DeviceExtension->CurrentIrpDevice = NULL;
}
}
static VOID NTAPI
i8042PowerWorkItem(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
NTSTATUS Status;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
/* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */
/* Register GUID_DEVICE_SYS_BUTTON interface and report capability */
if (DeviceExtension->NewCaps != DeviceExtension->ReportedCaps)
{
if (DeviceExtension->PowerInterfaceName.MaximumLength == 0)
{
/* We have never registred this interface ; do it */
Status = IoRegisterDeviceInterface(
DeviceExtension->Common.Pdo,
&GUID_DEVICE_SYS_BUTTON,
NULL,
&DeviceExtension->PowerInterfaceName);
if (!NT_SUCCESS(Status))
{
/* We can't do more yet, ignore the keypress... */
DPRINT("IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n",
Status);
DeviceExtension->PowerInterfaceName.MaximumLength = 0;
return;
}
}
else
{
/* Disable the interface. Once activated again, capabilities would be asked again */
Status = IoSetDeviceInterfaceState(
&DeviceExtension->PowerInterfaceName,
FALSE);
if (!NT_SUCCESS(Status))
{
/* Ignore the key press... */
DPRINT("Disabling interface %wZ failed with status 0x%08lx\n",
&DeviceExtension->PowerInterfaceName, Status);
return;
}
}
/* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS,
* so we can report new capability */
Status = IoSetDeviceInterfaceState(
&DeviceExtension->PowerInterfaceName,
TRUE);
if (!NT_SUCCESS(Status))
{
/* Ignore the key press... */
DPRINT("Enabling interface %wZ failed with status 0x%08lx\n",
&DeviceExtension->PowerInterfaceName, Status);
return;
}
}
/* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
if (DeviceExtension->PowerIrp)
{
PULONG pEvent = (PULONG)DeviceExtension->PowerIrp->AssociatedIrp.SystemBuffer;
DeviceExtension->PowerIrp->IoStatus.Status = STATUS_SUCCESS;
DeviceExtension->PowerIrp->IoStatus.Information = sizeof(ULONG);
*pEvent = DeviceExtension->LastPowerKey;
IoCompleteRequest(DeviceExtension->PowerIrp, IO_NO_INCREMENT);
DeviceExtension->PowerIrp = NULL;
}
}
/* Return TRUE if it was a power key */
static BOOLEAN
HandlePowerKeys(
IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
{
PKEYBOARD_INPUT_DATA InputData;
ULONG KeyPress;
InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer - 1;
if (!(InputData->Flags & KEY_E0))
return FALSE;
if (InputData->Flags & KEY_BREAK)
/* We already took care of the key press */
return TRUE;
switch (InputData->MakeCode)
{
case 0x52: /* VK_INSERT */
DPRINT1("FIXME: Remove debug code\n");
case KEYBOARD_POWER_CODE:
KeyPress = SYS_BUTTON_POWER;
break;
case KEYBOARD_SLEEP_CODE:
KeyPress = SYS_BUTTON_SLEEP;
break;
case KEYBOARD_WAKE_CODE:
KeyPress = SYS_BUTTON_WAKE;
break;
default:
return FALSE;
}
/* Our work can only be done at passive level, so use a workitem */
DeviceExtension->NewCaps |= KeyPress;
DeviceExtension->LastPowerKey = KeyPress;
IoQueueWorkItem(
DeviceExtension->PowerWorkItem,
&i8042PowerWorkItem,
DelayedWorkQueue,
DeviceExtension);
return TRUE;
}
static VOID NTAPI
i8042KbdDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
ULONG KeysTransferred = 0;
ULONG KeysInBufferCopy;
KIRQL Irql;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeferredContext;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
if (HandlePowerKeys(DeviceExtension))
{
DeviceExtension->KeyComplete = FALSE;
return;
}
i8042PacketDpc(PortDeviceExtension);
if (!DeviceExtension->KeyComplete)
return;
/* We got the interrupt as it was being enabled, too bad */
if (!PortDeviceExtension->HighestDIRQLInterrupt)
return;
Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
DeviceExtension->KeyComplete = FALSE;
KeysInBufferCopy = DeviceExtension->KeysInBuffer;
KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
#ifdef __REACTOS__
if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
{
PKEYBOARD_INPUT_DATA InputData;
InputData = DeviceExtension->KeyboardBuffer + KeysInBufferCopy - 1;
/* Test for TAB + key combination */
if (InputData->MakeCode == 0x0F)
DeviceExtension->TabPressed = !(InputData->Flags & KEY_BREAK);
else if (DeviceExtension->TabPressed)
{
DeviceExtension->DebugKey = InputData->MakeCode;
DeviceExtension->TabPressed = FALSE;
IoQueueWorkItem(
DeviceExtension->DebugWorkItem,
&i8042DebugWorkItem,
DelayedWorkQueue,
DeviceExtension);
}
}
#endif
DPRINT("Send a key\n");
if (!DeviceExtension->KeyboardData.ClassService)
return;
DPRINT("Sending %lu key(s)\n", KeysInBufferCopy);
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->KeyboardData.ClassService)(
DeviceExtension->KeyboardData.ClassDeviceObject,
DeviceExtension->KeyboardBuffer,
DeviceExtension->KeyboardBuffer + KeysInBufferCopy,
&KeysTransferred);
Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
DeviceExtension->KeysInBuffer -= KeysTransferred;
KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
/*
* Runs the keyboard IOCTL dispatch.
*/
NTSTATUS
i8042KbdDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
PI8042_KEYBOARD_EXTENSION DeviceExtension;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_GET_SYS_BUTTON_CAPS:
{
/* Part of GUID_DEVICE_SYS_BUTTON interface */
PULONG pCaps;
DPRINT("IOCTL_GET_SYS_BUTTON_CAPS\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
Status = STATUS_INVALID_PARAMETER;
else
{
pCaps = (PULONG)Irp->AssociatedIrp.SystemBuffer;
*pCaps = DeviceExtension->NewCaps;
DeviceExtension->ReportedCaps = DeviceExtension->NewCaps;
Irp->IoStatus.Information = sizeof(ULONG);
Status = STATUS_SUCCESS;
}
break;
}
case IOCTL_GET_SYS_BUTTON_EVENT:
{
/* Part of GUID_DEVICE_SYS_BUTTON interface */
PIRP WaitingIrp;
DPRINT("IOCTL_GET_SYS_BUTTON_EVENT\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
Status = STATUS_INVALID_PARAMETER;
else
{
/* FIXME: Race condition here:
* If an interrupt comes before we can mark the Irp
* as pending, it might be possible to complete the
* Irp before pending it, leading to a crash! */
WaitingIrp = InterlockedCompareExchangePointer(
&DeviceExtension->PowerIrp,
Irp,
NULL);
/* Check if an Irp is already pending */
if (WaitingIrp != NULL)
{
/* Unable to have a 2nd pending IRP for this IOCTL */
DPRINT("Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
Status = STATUS_INVALID_PARAMETER;
}
else
{
Status = STATUS_PENDING;
}
}
break;
}
default:
{
DPRINT("IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Status = Status;
if (Status == STATUS_PENDING)
IoMarkIrpPending(Irp);
else
IoCompleteRequest(Irp, IO_NO_INCREMENT);
/* Special case for IOCTL_GET_SYS_BUTTON_CAPS */
if (Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_SYS_BUTTON_CAPS
&& DeviceExtension->PowerIrp)
{
/* Also complete the pending IOCTL_GET_SYS_BUTTON_EVENT Irp */
PULONG pEvent = (PULONG)DeviceExtension->PowerIrp->AssociatedIrp.SystemBuffer;
DeviceExtension->PowerIrp->IoStatus.Status = STATUS_SUCCESS;
DeviceExtension->PowerIrp->IoStatus.Information = sizeof(ULONG);
*pEvent = DeviceExtension->LastPowerKey;
DeviceExtension->LastPowerKey = 0;
IoCompleteRequest(DeviceExtension->PowerIrp, IO_NO_INCREMENT);
DeviceExtension->PowerIrp = NULL;
}
return Status;
}
/*
* Runs the keyboard IOCTL_INTERNAL dispatch.
*/
NTSTATUS
i8042KbdInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
PI8042_KEYBOARD_EXTENSION DeviceExtension;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
{
SIZE_T Size;
PIO_WORKITEM WorkItem = NULL;
PI8042_HOOK_WORKITEM WorkItemData = NULL;
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
{
Status = STATUS_INVALID_PARAMETER;
goto cleanup;
}
DeviceExtension->KeyboardData =
*((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
/* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */
WorkItem = IoAllocateWorkItem(DeviceObject);
if (!WorkItem)
{
DPRINT("IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
WorkItemData = ExAllocatePool(
NonPagedPool,
sizeof(I8042_HOOK_WORKITEM));
if (!WorkItemData)
{
DPRINT("ExAllocatePool() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
WorkItemData->WorkItem = WorkItem;
WorkItemData->Irp = Irp;
/* Initialize extension */
DeviceExtension->Common.Type = Keyboard;
Size = DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize * sizeof(KEYBOARD_INPUT_DATA);
DeviceExtension->KeyboardBuffer = ExAllocatePool(
NonPagedPool,
Size);
if (!DeviceExtension->KeyboardBuffer)
{
DPRINT("ExAllocatePool() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
RtlZeroMemory(DeviceExtension->KeyboardBuffer, Size);
KeInitializeDpc(
&DeviceExtension->DpcKeyboard,
i8042KbdDpcRoutine,
DeviceExtension);
DeviceExtension->PowerWorkItem = IoAllocateWorkItem(DeviceObject);
if (!DeviceExtension->PowerWorkItem)
{
DPRINT("IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
DeviceExtension->DebugWorkItem = IoAllocateWorkItem(DeviceObject);
if (!DeviceExtension->DebugWorkItem)
{
DPRINT("IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
DeviceExtension->Common.PortDeviceExtension->KeyboardExtension = DeviceExtension;
DeviceExtension->Common.PortDeviceExtension->Flags |= KEYBOARD_CONNECTED;
IoMarkIrpPending(Irp);
IoQueueWorkItem(WorkItem,
i8042SendHookWorkItem,
DelayedWorkQueue,
WorkItemData);
Status = STATUS_PENDING;
break;
cleanup:
if (DeviceExtension->KeyboardBuffer)
ExFreePool(DeviceExtension->KeyboardBuffer);
if (DeviceExtension->PowerWorkItem)
IoFreeWorkItem(DeviceExtension->PowerWorkItem);
if (DeviceExtension->DebugWorkItem)
IoFreeWorkItem(DeviceExtension->DebugWorkItem);
if (WorkItem)
IoFreeWorkItem(WorkItem);
if (WorkItemData)
ExFreePool(WorkItemData);
break;
}
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
{
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n");
/* MSDN says that operation is to implemented.
* To implement it, we just have to do:
* DeviceExtension->KeyboardData.ClassService = NULL;
*/
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD:
{
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
/* Nothing to do here */
Status = STATUS_SUCCESS;
break;
}
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
{
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
/* We should check the UnitID, but it's kind of pointless as
* all keyboards are supposed to have the same one
*/
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&IndicatorTranslation,
sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));
Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
Status = STATUS_SUCCESS;
}
break;
}
case IOCTL_KEYBOARD_QUERY_INDICATORS:
{
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&DeviceExtension->KeyboardIndicators,
sizeof(KEYBOARD_INDICATOR_PARAMETERS));
Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION);
Status = STATUS_SUCCESS;
}
break;
}
case IOCTL_KEYBOARD_SET_INDICATORS:
{
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n");
if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
RtlCopyMemory(
&DeviceExtension->KeyboardIndicators,
Irp->AssociatedIrp.SystemBuffer,
sizeof(KEYBOARD_INDICATOR_PARAMETERS));
Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
}
break;
}
default:
{
DPRINT("IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Status = Status;
if (Status != STATUS_PENDING)
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/*
* Call the customization hook. The ToReturn 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)
*/
static BOOLEAN
i8042KbdCallIsrHook(
IN PI8042_KEYBOARD_EXTENSION DeviceExtension,
IN UCHAR Status,
IN UCHAR Input,
OUT PBOOLEAN ToReturn)
{
BOOLEAN HookReturn, HookContinue;
HookContinue = FALSE;
if (DeviceExtension->KeyboardHook.IsrRoutine)
{
HookReturn = DeviceExtension->KeyboardHook.IsrRoutine(
DeviceExtension->KeyboardHook.Context,
DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer,
&DeviceExtension->Common.PortDeviceExtension->Packet,
Status,
&Input,
&HookContinue,
&DeviceExtension->KeyboardScanState);
if (!HookContinue)
{
*ToReturn = HookReturn;
return TRUE;
}
}
return FALSE;
}
BOOLEAN NTAPI
i8042KbdInterruptService(
IN PKINTERRUPT Interrupt,
PVOID Context)
{
PI8042_KEYBOARD_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
PKEYBOARD_INPUT_DATA InputData;
ULONG Counter;
UCHAR PortStatus, Output;
BOOLEAN ToReturn = FALSE;
NTSTATUS Status;
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer;
Counter = PortDeviceExtension->Settings.PollStatusIterations;
while (Counter)
{
Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
if (!NT_SUCCESS(Status))
{
DPRINT("i8042ReadStatus() failed with status 0x%08lx\n", Status);
return FALSE;
}
Status = i8042ReadKeyboardData(PortDeviceExtension, &Output);
if (NT_SUCCESS(Status))
break;
KeStallExecutionProcessor(1);
Counter--;
}
if (Counter == 0)
{
DPRINT("Spurious i8042 keyboard interrupt\n");
return FALSE;
}
DPRINT("Got: 0x%02x\n", Output);
if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
{
/* Test for CTRL + SCROLL LOCK twice */
static UCHAR ScanCodes[] = { 0x1d, 0x46, 0x46, 0 };
if (!(Output & 0x80))
{
if ((Output & 0x7f) == ScanCodes[DeviceExtension->ComboPosition])
{
DeviceExtension->ComboPosition++;
if (ScanCodes[DeviceExtension->ComboPosition] == 0)
KeBugCheck(MANUALLY_INITIATED_CRASH);
}
else if ((Output & 0x7f) == ScanCodes[0])
DeviceExtension->ComboPosition = 1;
else
DeviceExtension->ComboPosition = 0;
}
}
if (i8042KbdCallIsrHook(DeviceExtension, PortStatus, Output, &ToReturn))
return ToReturn;
if (i8042PacketIsr(PortDeviceExtension, Output))
{
if (PortDeviceExtension->PacketComplete)
{
DPRINT("Packet complete\n");
KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
}
DPRINT("Irq eaten by packet\n");
return TRUE;
}
DPRINT("Irq is keyboard input\n");
if (DeviceExtension->KeyboardScanState == Normal)
{
switch (Output)
{
case 0xe0:
DeviceExtension->KeyboardScanState = GotE0;
return TRUE;
case 0xe1:
DeviceExtension->KeyboardScanState = GotE1;
return TRUE;
default:
break;
}
}
/* Update InputData */
InputData->Flags = 0;
switch (DeviceExtension->KeyboardScanState)
{
case GotE0:
InputData->Flags |= KEY_E0;
break;
case GotE1:
InputData->Flags |= KEY_E1;
break;
default:
break;
}
DeviceExtension->KeyboardScanState = Normal;
if (Output & 0x80)
InputData->Flags |= KEY_BREAK;
else
InputData->Flags |= KEY_MAKE;
InputData->MakeCode = Output & 0x7f;
InputData->Reserved = 0;
i8042KbdQueuePacket(DeviceExtension);
return TRUE;
}
-68
View File
@@ -1,68 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/misc.c
* PURPOSE: Misceallenous operations
* PROGRAMMERS: Copyright 2006 Hervé Poussineau ([email protected])
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
static NTSTATUS NTAPI
ForwardIrpAndWaitCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
if (Irp->PendingReturned)
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
KEVENT Event;
NTSTATUS Status;
ASSERT(LowerDevice);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
DPRINT("Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName);
IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
Status = IoCallDriver(LowerDevice, Irp);
if (Status == STATUS_PENDING)
{
Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
if (NT_SUCCESS(Status))
Status = Irp->IoStatus.Status;
}
return Status;
}
NTSTATUS NTAPI
ForwardIrpAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
ASSERT(LowerDevice);
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}
File diff suppressed because it is too large Load Diff
-663
View File
@@ -1,663 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/pnp.c
* PURPOSE: IRP_MJ_PNP operations
* PROGRAMMERS: Copyright 2006 Hervé Poussineau ([email protected])
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
/* This is all pretty confusing. There's more than one way to
* disable/enable the keyboard. You can send KBD_ENABLE to the
* keyboard, and it will start scanning keys. Sending KBD_DISABLE
* will disable the key scanning but also reset the parameters to
* defaults.
*
* You can also send 0xAE to the controller for enabling the
* keyboard clock line and 0xAD for disabling it. Then it'll
* automatically get turned on at the next command. The last
* way is by modifying the bit that drives the clock line in the
* 'command byte' of the controller. This is almost, but not quite,
* the same as the AE/AD thing. The difference can be used to detect
* some really old broken keyboard controllers which I hope won't be
* necessary.
*
* We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse
* some kvm switches.
*/
BOOLEAN
i8042ChangeMode(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR FlagsToDisable,
IN UCHAR FlagsToEnable)
{
UCHAR Value;
NTSTATUS Status;
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_READ_MODE))
{
DPRINT1("Can't read i8042 mode\n");
return FALSE;
}
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (!NT_SUCCESS(Status))
{
DPRINT1("No response after read i8042 mode\n");
return FALSE;
}
Value &= ~FlagsToDisable;
Value |= FlagsToEnable;
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE))
{
DPRINT1("Can't set i8042 mode\n");
return FALSE;
}
if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
{
DPRINT1("Can't send i8042 mode\n");
return FALSE;
}
return TRUE;
}
static NTSTATUS
i8042BasicDetect(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
NTSTATUS Status;
UCHAR Value = 0;
/* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
if (!i8042ChangeMode(DeviceExtension, CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB, CCB_KBD_DISAB | CCB_MOUSE_DISAB))
return STATUS_IO_DEVICE_ERROR;
i8042Flush(DeviceExtension);
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST))
{
DPRINT1("Writing CTRL_SELF_TEST command failed\n");
return STATUS_IO_TIMEOUT;
}
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status);
return Status;
}
if (Value != 0x55)
{
DPRINT1("Got 0x%02x instead of 0x55\n", Value);
return STATUS_IO_DEVICE_ERROR;
}
/*
* We used to send a KBD_LINE_TEST (0xAB) command here, but on at least HP
* Pavilion notebooks the response to that command was incorrect.
* So now we just assume that a keyboard is attached.
*/
DeviceExtension->Flags |= KEYBOARD_PRESENT;
if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST))
{
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (NT_SUCCESS(Status) && Value == 0)
DeviceExtension->Flags |= MOUSE_PRESENT;
}
if (IsFirstStageSetup())
/* Ignore the mouse */
DeviceExtension->Flags &= ~MOUSE_PRESENT;
return STATUS_SUCCESS;
}
static BOOLEAN
i8042DetectKeyboard(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
NTSTATUS Status;
/* Set LEDs (that is not fatal if some error occurs) */
Status = i8042SynchWritePort(DeviceExtension, 0, KBD_CMD_SET_LEDS, TRUE);
if (NT_SUCCESS(Status))
{
Status = i8042SynchWritePort(DeviceExtension, 0, 0, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT("Can't finish SET_LEDS (0x%08lx)\n", Status);
return FALSE;
}
}
else
{
DPRINT("Warning: can't write SET_LEDS (0x%08lx)\n", Status);
}
/* Turn on translation */
if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE))
return FALSE;
return TRUE;
}
static BOOLEAN
i8042DetectMouse(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
BOOLEAN Ok = FALSE;
NTSTATUS Status;
UCHAR Value;
UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA, 0x00 };
UCHAR ReplyByte;
i8042Flush(DeviceExtension);
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_WRITE_MOUSE)
||!i8042Write(DeviceExtension, DeviceExtension->DataPort, MOU_CMD_RESET))
{
DPRINT1("Failed to write reset command to mouse\n");
goto cleanup;
}
for (ReplyByte = 0;
ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]);
ReplyByte++)
{
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (!NT_SUCCESS(Status))
{
DPRINT1("No ACK after mouse reset, status 0x%08lx\n", Status);
goto cleanup;
}
else if (Value != ExpectedReply[ReplyByte])
{
DPRINT1("Unexpected reply: 0x%02x (expected 0x%02x)\n",
Value, ExpectedReply[ReplyByte]);
goto cleanup;
}
}
Ok = TRUE;
cleanup:
if (!Ok)
{
/* There is probably no mouse present. On some systems,
the probe locks the entire keyboard controller. Let's
try to get access to the keyboard again by sending a
reset */
i8042Flush(DeviceExtension);
i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST);
i8042ReadDataWait(DeviceExtension, &Value);
i8042Flush(DeviceExtension);
}
DPRINT("Mouse %sdetected\n", Ok ? "" : "not ");
return Ok;
}
static NTSTATUS
i8042ConnectKeyboardInterrupt(
IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
{
PPORT_DEVICE_EXTENSION PortDeviceExtension;
KIRQL DirqlMax;
NTSTATUS Status;
DPRINT("i8042ConnectKeyboardInterrupt()\n");
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
DirqlMax = MAX(
PortDeviceExtension->KeyboardInterrupt.Dirql,
PortDeviceExtension->MouseInterrupt.Dirql);
DPRINT("KeyboardInterrupt.Vector %lu\n",
PortDeviceExtension->KeyboardInterrupt.Vector);
DPRINT("KeyboardInterrupt.Dirql %lu\n",
PortDeviceExtension->KeyboardInterrupt.Dirql);
DPRINT("KeyboardInterrupt.DirqlMax %lu\n",
DirqlMax);
DPRINT("KeyboardInterrupt.InterruptMode %s\n",
PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
DPRINT("KeyboardInterrupt.ShareInterrupt %s\n",
PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no");
DPRINT("KeyboardInterrupt.Affinity 0x%lx\n",
PortDeviceExtension->KeyboardInterrupt.Affinity);
Status = IoConnectInterrupt(
&PortDeviceExtension->KeyboardInterrupt.Object,
i8042KbdInterruptService,
DeviceExtension, &PortDeviceExtension->SpinLock,
PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax,
PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt,
PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT("IoConnectInterrupt() failed with status 0x%08x\n", Status);
return Status;
}
if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql)
PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED;
return STATUS_SUCCESS;
}
static NTSTATUS
i8042ConnectMouseInterrupt(
IN PI8042_MOUSE_EXTENSION DeviceExtension)
{
PPORT_DEVICE_EXTENSION PortDeviceExtension;
KIRQL DirqlMax;
NTSTATUS Status;
DPRINT("i8042ConnectMouseInterrupt()\n");
Status = i8042MouInitialize(DeviceExtension);
if (!NT_SUCCESS(Status))
return Status;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
DirqlMax = MAX(
PortDeviceExtension->KeyboardInterrupt.Dirql,
PortDeviceExtension->MouseInterrupt.Dirql);
DPRINT("MouseInterrupt.Vector %lu\n",
PortDeviceExtension->MouseInterrupt.Vector);
DPRINT("MouseInterrupt.Dirql %lu\n",
PortDeviceExtension->MouseInterrupt.Dirql);
DPRINT("MouseInterrupt.DirqlMax %lu\n",
DirqlMax);
DPRINT("MouseInterrupt.InterruptMode %s\n",
PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
DPRINT("MouseInterrupt.ShareInterrupt %s\n",
PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no");
DPRINT("MouseInterrupt.Affinity 0x%lx\n",
PortDeviceExtension->MouseInterrupt.Affinity);
Status = IoConnectInterrupt(
&PortDeviceExtension->MouseInterrupt.Object,
i8042MouInterruptService,
DeviceExtension, &PortDeviceExtension->SpinLock,
PortDeviceExtension->MouseInterrupt.Vector, PortDeviceExtension->MouseInterrupt.Dirql, DirqlMax,
PortDeviceExtension->MouseInterrupt.InterruptMode, PortDeviceExtension->MouseInterrupt.ShareInterrupt,
PortDeviceExtension->MouseInterrupt.Affinity, FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT("IoConnectInterrupt() failed with status 0x%08x\n", Status);
goto cleanup;
}
if (DirqlMax == PortDeviceExtension->MouseInterrupt.Dirql)
PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->MouseInterrupt.Object;
PortDeviceExtension->Flags |= MOUSE_INITIALIZED;
Status = STATUS_SUCCESS;
cleanup:
if (!NT_SUCCESS(Status))
{
PortDeviceExtension->Flags &= ~MOUSE_INITIALIZED;
if (PortDeviceExtension->MouseInterrupt.Object)
{
IoDisconnectInterrupt(PortDeviceExtension->MouseInterrupt.Object);
PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
}
}
return Status;
}
static NTSTATUS
EnableInterrupts(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
UCHAR FlagsToDisable = 0;
UCHAR FlagsToEnable = 0;
i8042Flush(DeviceExtension);
/* Select the devices we have */
if (DeviceExtension->Flags & KEYBOARD_PRESENT)
{
FlagsToDisable |= CCB_KBD_DISAB;
FlagsToEnable |= CCB_KBD_INT_ENAB;
}
if (DeviceExtension->Flags & MOUSE_PRESENT)
{
FlagsToDisable |= CCB_MOUSE_DISAB;
FlagsToEnable |= CCB_MOUSE_INT_ENAB;
}
if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable))
return STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
static NTSTATUS
StartProcedure(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
NTSTATUS Status;
if (DeviceExtension->DataPort == 0)
{
/* Unable to do something at the moment */
return STATUS_SUCCESS;
}
if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT)))
{
/* Try to detect them */
DPRINT("Check if the controller is really a i8042\n");
Status = i8042BasicDetect(DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT("i8042BasicDetect() failed with status 0x%08lx\n", Status);
return STATUS_UNSUCCESSFUL;
}
DPRINT("Detecting keyboard\n");
if (!i8042DetectKeyboard(DeviceExtension))
return STATUS_UNSUCCESSFUL;
DPRINT("Detecting mouse\n");
if (!i8042DetectMouse(DeviceExtension))
return STATUS_UNSUCCESSFUL;
DPRINT("Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO");
DPRINT("Mouse present : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO");
}
/* Connect interrupts */
if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
DeviceExtension->Flags & KEYBOARD_CONNECTED &&
DeviceExtension->Flags & KEYBOARD_STARTED &&
!(DeviceExtension->Flags & (MOUSE_PRESENT | KEYBOARD_INITIALIZED)))
{
/* No mouse, and the keyboard is ready */
Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
if (NT_SUCCESS(Status))
{
DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
Status = EnableInterrupts(DeviceExtension);
}
}
else if (DeviceExtension->Flags & MOUSE_PRESENT &&
DeviceExtension->Flags & MOUSE_CONNECTED &&
DeviceExtension->Flags & MOUSE_STARTED &&
!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_INITIALIZED)))
{
/* No keyboard, and the mouse is ready */
Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
if (NT_SUCCESS(Status))
{
DeviceExtension->Flags |= MOUSE_INITIALIZED;
Status = EnableInterrupts(DeviceExtension);
}
}
else if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
DeviceExtension->Flags & KEYBOARD_CONNECTED &&
DeviceExtension->Flags & KEYBOARD_STARTED &&
DeviceExtension->Flags & MOUSE_PRESENT &&
DeviceExtension->Flags & MOUSE_CONNECTED &&
DeviceExtension->Flags & MOUSE_STARTED &&
!(DeviceExtension->Flags & (KEYBOARD_INITIALIZED | MOUSE_INITIALIZED)))
{
/* The keyboard and mouse are ready */
Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
if (NT_SUCCESS(Status))
{
DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
if (NT_SUCCESS(Status))
{
DeviceExtension->Flags |= MOUSE_INITIALIZED;
Status = EnableInterrupts(DeviceExtension);
}
}
}
else
{
/* Nothing to do */
Status = STATUS_SUCCESS;
}
return Status;
}
static NTSTATUS
i8042PnpStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PCM_RESOURCE_LIST AllocatedResources,
IN PCM_RESOURCE_LIST AllocatedResourcesTranslated)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor, ResourceDescriptorTranslated;
INTERRUPT_DATA InterruptData;
BOOLEAN FoundDataPort = FALSE;
BOOLEAN FoundControlPort = FALSE;
BOOLEAN FoundIrq = FALSE;
ULONG i;
NTSTATUS Status;
DPRINT("i8042PnpStartDevice(%p)\n", DeviceObject);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
PortDeviceExtension = DeviceExtension->PortDeviceExtension;
ASSERT(DeviceExtension->PnpState == dsStopped);
if (!AllocatedResources)
{
DPRINT("No allocated resources sent to driver\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if (AllocatedResources->Count != 1)
{
DPRINT("Wrong number of allocated resources sent to driver\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if (AllocatedResources->List[0].PartialResourceList.Version != 1
|| AllocatedResources->List[0].PartialResourceList.Revision != 1
|| AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1
|| AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1)
{
DPRINT("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
AllocatedResources->List[0].PartialResourceList.Version,
AllocatedResources->List[0].PartialResourceList.Revision,
AllocatedResourcesTranslated->List[0].PartialResourceList.Version,
AllocatedResourcesTranslated->List[0].PartialResourceList.Revision);
return STATUS_REVISION_MISMATCH;
}
/* Get Irq and optionally control port and data port */
for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
{
ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
switch (ResourceDescriptor->Type)
{
case CmResourceTypePort:
{
if (ResourceDescriptor->u.Port.Length == 1)
{
/* We assume that the first ressource will
* be the control port and the second one
* will be the data port...
*/
if (!FoundDataPort)
{
PortDeviceExtension->DataPort = (PUCHAR)ResourceDescriptor->u.Port.Start.u.LowPart;
DPRINT("Found data port: 0x%lx\n", PortDeviceExtension->DataPort);
FoundDataPort = TRUE;
}
else if (!FoundControlPort)
{
PortDeviceExtension->ControlPort = (PUCHAR)ResourceDescriptor->u.Port.Start.u.LowPart;
DPRINT("Found control port: 0x%lx\n", PortDeviceExtension->ControlPort);
FoundControlPort = TRUE;
}
else
{
DPRINT("Too much I/O ranges provided\n", ResourceDescriptor->u.Port.Length);
return STATUS_INVALID_PARAMETER;
}
}
else
DPRINT1("Invalid I/O range length: 0x%lx\n", ResourceDescriptor->u.Port.Length);
break;
}
case CmResourceTypeInterrupt:
{
if (FoundIrq)
return STATUS_INVALID_PARAMETER;
InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level;
InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector;
InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity;
if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
InterruptData.InterruptMode = Latched;
else
InterruptData.InterruptMode = LevelSensitive;
InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared);
DPRINT("Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Vector);
FoundIrq = TRUE;
break;
}
default:
DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
}
}
if (!FoundIrq)
{
DPRINT("Interrupt resource was not found in allocated resources list\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort))
{
DPRINT("Some required resources were not found in allocated resources list\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort))
{
DPRINT("Too much resources were provided in allocated resources list\n");
return STATUS_INVALID_PARAMETER;
}
switch (DeviceExtension->Type)
{
case Keyboard:
{
RtlCopyMemory(
&PortDeviceExtension->KeyboardInterrupt,
&InterruptData,
sizeof(INTERRUPT_DATA));
PortDeviceExtension->Flags |= KEYBOARD_STARTED;
Status = StartProcedure(PortDeviceExtension);
break;
}
case Mouse:
{
RtlCopyMemory(
&PortDeviceExtension->MouseInterrupt,
&InterruptData,
sizeof(INTERRUPT_DATA));
PortDeviceExtension->Flags |= MOUSE_STARTED;
Status = StartProcedure(PortDeviceExtension);
break;
}
default:
{
DPRINT1("Unknown FDO type %u\n", DeviceExtension->Type);
ASSERT(FALSE);
Status = STATUS_INVALID_DEVICE_REQUEST;
}
}
if (NT_SUCCESS(Status))
DeviceExtension->PnpState = dsStarted;
return Status;
}
NTSTATUS NTAPI
i8042Pnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
ULONG MinorFunction;
I8042_DEVICE_TYPE DeviceType;
ULONG_PTR Information = 0;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
MinorFunction = Stack->MinorFunction;
DeviceType = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type;
switch (MinorFunction)
{
case IRP_MN_START_DEVICE: /* 0x0 */
{
DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
/* Call lower driver (if any) */
if (DeviceType != PhysicalDeviceObject)
{
Status = ForwardIrpAndWait(DeviceObject, Irp);
if (NT_SUCCESS(Status))
Status = i8042PnpStartDevice(
DeviceObject,
Stack->Parameters.StartDevice.AllocatedResources,
Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
}
else
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
{
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case RemovalRelations:
{
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
default:
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
break;
}
default:
{
DPRINT1("IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
-141
View File
@@ -1,141 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/ps2pp.c
* PURPOSE: ps2pp protocol handling
* PROGRAMMERS: Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
* Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
VOID
i8042MouHandlePs2pp(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Input)
{
UCHAR PktType;
PMOUSE_INPUT_DATA MouseInput;
MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->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 (DeviceExtension->MouseState)
{
case MouseIdle:
case XMovement:
DeviceExtension->MouseLogiBuffer[DeviceExtension->MouseState] = Input;
DeviceExtension->MouseState++;
break;
case YMovement:
DeviceExtension->MouseLogiBuffer[2] = Input;
DeviceExtension->MouseState = MouseIdle;
/* first check if it's a normal packet */
if (!(DeviceExtension->MouseLogiBuffer[0] & 0xC0))
{
DeviceExtension->MouseState = MouseIdle;
i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[0]);
i8042MouHandle(DeviceExtension, DeviceExtension->MouseLogiBuffer[1]);
i8042MouHandle(DeviceExtension, DeviceExtension->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 (((DeviceExtension->MouseLogiBuffer[0] & 0x48) != 0x48) ||
(((DeviceExtension->MouseLogiBuffer[1] & 0x0C) >> 2) !=
(DeviceExtension->MouseLogiBuffer[2] & 0x03)))
{
DPRINT1("Ps2pp packet fails sanity checks\n");
return;
}
/* Now get the packet type */
PktType = ((DeviceExtension->MouseLogiBuffer[0] & 0x30) >> 4) &
((DeviceExtension->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 (DeviceExtension->MouseLogiBuffer[2] & 0x10)
MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
if (DeviceExtension->MouseLogiBuffer[2] & 0x20)
MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
if (DeviceExtension->MouseLogiBuffer[2] & 0x0F)
{
MouseInput->ButtonFlags |= MOUSE_WHEEL;
if (DeviceExtension->MouseLogiBuffer[2] & 0x08)
MouseInput->ButtonData = (DeviceExtension->MouseLogiBuffer[2] & 0x07) - 8;
else
MouseInput->ButtonData = DeviceExtension->MouseLogiBuffer[2] & 0x07;
}
i8042MouHandleButtons(
DeviceExtension,
MOUSE_BUTTON_4_DOWN | MOUSE_BUTTON_5_DOWN);
i8042MouQueuePacket(DeviceExtension);
return;
default:
/* These are for things that would probably
* be handled by logitechs own driver.
*/
return;
}
default:
DPRINT1("Unexpected input state for ps2pp!\n");
}
}
-218
View File
@@ -1,218 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/readwrite.c
* PURPOSE: Read/write port functions
* PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
VOID
i8042Flush(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
UCHAR Ignore;
while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_OBF | MOU_OBF, &Ignore))) {
DPRINT("Data flushed\n"); /* drop */
}
}
VOID
i8042IsrWritePort(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Value,
IN UCHAR SelectCmd OPTIONAL)
{
if (SelectCmd)
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, SelectCmd))
return;
i8042Write(DeviceExtension, DeviceExtension->DataPort, Value);
}
/*
* FUNCTION: Read data from port 0x60
*/
NTSTATUS
i8042ReadData(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR StatusFlags,
OUT PUCHAR Data)
{
UCHAR PortStatus;
NTSTATUS Status;
Status = i8042ReadStatus(DeviceExtension, &PortStatus);
if (!NT_SUCCESS(Status))
return Status;
// If data is available
if (PortStatus & StatusFlags)
{
*Data = READ_PORT_UCHAR(DeviceExtension->DataPort);
DPRINT("Read: 0x%02x (status: 0x%x)\n", Data[0], PortStatus);
// If the data is valid (not timeout, not parity error)
if ((PortStatus & KBD_PERR) == 0)
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
i8042ReadStatus(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
OUT PUCHAR Status)
{
ASSERT(DeviceExtension->ControlPort != NULL);
*Status = READ_PORT_UCHAR(DeviceExtension->ControlPort);
return STATUS_SUCCESS;
}
/*
* FUNCTION: Read data from data port
*/
NTSTATUS
i8042ReadDataWait(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
OUT PUCHAR Data)
{
ULONG Counter;
NTSTATUS Status;
Counter = DeviceExtension->Settings.PollingIterations;
while (Counter--)
{
Status = i8042ReadKeyboardData(DeviceExtension, Data);
if (NT_SUCCESS(Status))
return Status;
KeStallExecutionProcessor(50);
}
/* Timed out */
return STATUS_IO_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.
*/
NTSTATUS NTAPI
i8042SynchReadPort(
IN PVOID Context,
OUT PUCHAR Value,
IN BOOLEAN WaitForAck)
{
PPORT_DEVICE_EXTENSION DeviceExtension;
DeviceExtension = (PPORT_DEVICE_EXTENSION)Context;
return i8042ReadDataWait(DeviceExtension, Value);
}
/*
* These functions are callbacks for filter driver custom
* initialization routines.
*/
NTSTATUS NTAPI
i8042SynchWritePort(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Port,
IN UCHAR Value,
IN BOOLEAN WaitForAck)
{
NTSTATUS Status;
UCHAR Ack;
ULONG ResendIterations;
ResendIterations = DeviceExtension->Settings.ResendIterations + 1;
do
{
if (Port)
if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Port))
{
DPRINT1("Failed to write Port\n");
return STATUS_IO_TIMEOUT;
}
if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
{
DPRINT1("Failed to write Value\n");
return STATUS_IO_TIMEOUT;
}
if (WaitForAck)
{
Status = i8042ReadDataWait(DeviceExtension, &Ack);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to read Ack\n");
return Status;
}
if (Ack == KBD_ACK)
return STATUS_SUCCESS;
if (Ack != KBD_RESEND)
{
DPRINT1("Unexpected Ack 0x%02x\n", Ack);
return STATUS_UNEXPECTED_IO_ERROR;
}
}
else
{
return STATUS_SUCCESS;
}
DPRINT("Reiterating\n");
ResendIterations--;
} while (ResendIterations);
return STATUS_IO_TIMEOUT;
}
/*
* FUNCTION: Write data to a port, waiting first for it to become ready
*/
BOOLEAN
i8042Write(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN PUCHAR addr,
IN UCHAR data)
{
ULONG ResendIterations;
ASSERT(addr);
ASSERT(DeviceExtension->ControlPort != NULL);
ResendIterations = DeviceExtension->Settings.ResendIterations;
while ((KBD_IBF & READ_PORT_UCHAR(DeviceExtension->ControlPort)) &&
(ResendIterations--))
{
KeStallExecutionProcessor(50);
}
if (ResendIterations)
{
WRITE_PORT_UCHAR(addr, data);
DPRINT("Sent 0x%x to port 0x%x\n", data, addr);
return TRUE;
}
return FALSE;
}
-251
View File
@@ -1,251 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/i8042prt.c
* PURPOSE: Reading the registry
* PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS
ReadRegistryEntries(
IN PUNICODE_STRING RegistryPath,
OUT PI8042_SETTINGS Settings)
{
UNICODE_STRING ParametersRegistryKey;
RTL_QUERY_REGISTRY_TABLE Parameters[16];
NTSTATUS Status;
ULONG DefaultKeyboardDataQueueSize = 0x64;
UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardPort");
ULONG DefaultMouseDataQueueSize = 0x64;
ULONG DefaultMouseResolution = 3;
ULONG DefaultMouseSynchIn100ns = 20000000;
ULONG DefaultNumberOfButtons = 2;
UNICODE_STRING DefaultPointerDeviceBaseName = RTL_CONSTANT_STRING(L"PointerPort");
ULONG DefaultPollStatusIterations = 1;
ULONG DefaultOverrideKeyboardType = 4;
ULONG DefaultOverrideKeyboardSubtype = 0;
ULONG DefaultPollingIterations = 12000;
ULONG DefaultPollingIterationsMaximum = 12000;
ULONG DefaultResendIterations = 0x3;
ULONG DefaultSampleRate = 60;
ULONG DefaultCrashOnCtrlScroll;
/* Default value for CrashOnCtrlScroll depends if we're
* running a debug build or a normal build.
*/
#ifdef DBG
DefaultCrashOnCtrlScroll = 1;
#else
DefaultCrashOnCtrlScroll = 0;
#endif
ParametersRegistryKey.Length = 0;
ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
ParametersRegistryKey.Buffer = ExAllocatePool(PagedPool, ParametersRegistryKey.MaximumLength);
if (!ParametersRegistryKey.Buffer)
{
DPRINT("ExAllocatePool() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
RtlZeroMemory(Parameters, sizeof(Parameters));
Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[0].Name = L"KeyboardDataQueueSize";
Parameters[0].EntryContext = &Settings->KeyboardDataQueueSize;
Parameters[0].DefaultType = REG_DWORD;
Parameters[0].DefaultData = &DefaultKeyboardDataQueueSize;
Parameters[0].DefaultLength = sizeof(ULONG);
Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[1].Name = L"KeyboardDeviceBaseName";
Parameters[1].EntryContext = &Settings->KeyboardDeviceBaseName;
Parameters[1].DefaultType = REG_SZ;
Parameters[1].DefaultData = &DefaultKeyboardDeviceBaseName;
Parameters[1].DefaultLength = 0;
Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[2].Name = L"MouseDataQueueSize";
Parameters[2].EntryContext = &Settings->MouseDataQueueSize;
Parameters[2].DefaultType = REG_DWORD;
Parameters[2].DefaultData = &DefaultMouseDataQueueSize;
Parameters[2].DefaultLength = sizeof(ULONG);
Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[3].Name = L"MouseResolution";
Parameters[3].EntryContext = &Settings->MouseResolution;
Parameters[3].DefaultType = REG_DWORD;
Parameters[3].DefaultData = &DefaultMouseResolution;
Parameters[3].DefaultLength = sizeof(ULONG);
Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[4].Name = L"MouseSynchIn100ns";
Parameters[4].EntryContext = &Settings->MouseSynchIn100ns;
Parameters[4].DefaultType = REG_DWORD;
Parameters[4].DefaultData = &DefaultMouseSynchIn100ns;
Parameters[4].DefaultLength = sizeof(ULONG);
Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[5].Name = L"NumberOfButtons";
Parameters[5].EntryContext = &Settings->NumberOfButtons;
Parameters[5].DefaultType = REG_DWORD;
Parameters[5].DefaultData = &DefaultNumberOfButtons;
Parameters[5].DefaultLength = sizeof(ULONG);
Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[6].Name = L"PointerDeviceBaseName";
Parameters[6].EntryContext = &Settings->PointerDeviceBaseName;
Parameters[6].DefaultType = REG_SZ;
Parameters[6].DefaultData = &DefaultPointerDeviceBaseName;
Parameters[6].DefaultLength = 0;
Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[7].Name = L"PollStatusIterations";
Parameters[7].EntryContext = &Settings->PollStatusIterations;
Parameters[7].DefaultType = REG_DWORD;
Parameters[7].DefaultData = &DefaultPollStatusIterations;
Parameters[7].DefaultLength = sizeof(ULONG);
Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[8].Name = L"OverrideKeyboardType";
Parameters[8].EntryContext = &Settings->OverrideKeyboardType;
Parameters[8].DefaultType = REG_DWORD;
Parameters[8].DefaultData = &DefaultOverrideKeyboardType;
Parameters[8].DefaultLength = sizeof(ULONG);
Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[9].Name = L"OverrideKeyboardSubtype";
Parameters[9].EntryContext = &Settings->OverrideKeyboardSubtype;
Parameters[9].DefaultType = REG_DWORD;
Parameters[9].DefaultData = &DefaultOverrideKeyboardSubtype;
Parameters[9].DefaultLength = sizeof(ULONG);
Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[10].Name = L"PollingIterations";
Parameters[10].EntryContext = &Settings->PollingIterations;
Parameters[10].DefaultType = REG_DWORD;
Parameters[10].DefaultData = &DefaultPollingIterations;
Parameters[10].DefaultLength = sizeof(ULONG);
Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[11].Name = L"PollingIterationsMaximum";
Parameters[11].EntryContext = &Settings->PollingIterationsMaximum;
Parameters[11].DefaultType = REG_DWORD;
Parameters[11].DefaultData = &DefaultPollingIterationsMaximum;
Parameters[11].DefaultLength = sizeof(ULONG);
Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[12].Name = L"ResendIterations";
Parameters[12].EntryContext = &Settings->ResendIterations;
Parameters[12].DefaultType = REG_DWORD;
Parameters[12].DefaultData = &DefaultResendIterations;
Parameters[12].DefaultLength = sizeof(ULONG);
Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[13].Name = L"SampleRate";
Parameters[13].EntryContext = &Settings->SampleRate;
Parameters[13].DefaultType = REG_DWORD;
Parameters[13].DefaultData = &DefaultSampleRate;
Parameters[13].DefaultLength = sizeof(ULONG);
Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[14].Name = L"CrashOnCtrlScroll";
Parameters[14].EntryContext = &Settings->CrashOnCtrlScroll;
Parameters[14].DefaultType = REG_DWORD;
Parameters[14].DefaultData = &DefaultCrashOnCtrlScroll;
Parameters[14].DefaultLength = sizeof(ULONG);
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParametersRegistryKey.Buffer,
Parameters,
NULL,
NULL);
if (NT_SUCCESS(Status))
{
/* Check values */
if (Settings->KeyboardDataQueueSize < 1)
Settings->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
if (Settings->MouseDataQueueSize < 1)
Settings->MouseDataQueueSize = DefaultMouseDataQueueSize;
if (Settings->NumberOfButtons < 1)
Settings->NumberOfButtons = DefaultNumberOfButtons;
if (Settings->PollingIterations < 0x400)
Settings->PollingIterations = DefaultPollingIterations;
if (Settings->PollingIterationsMaximum < 0x400)
Settings->PollingIterationsMaximum = DefaultPollingIterationsMaximum;
if (Settings->ResendIterations < 1)
Settings->ResendIterations = DefaultResendIterations;
}
else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
/* Registry path doesn't exist. Set defaults */
Settings->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
Settings->MouseDataQueueSize = DefaultMouseDataQueueSize;
Settings->MouseResolution = DefaultMouseResolution;
Settings->MouseSynchIn100ns = DefaultMouseSynchIn100ns;
Settings->NumberOfButtons = DefaultNumberOfButtons;
Settings->PollStatusIterations = DefaultPollStatusIterations;
Settings->OverrideKeyboardType = DefaultOverrideKeyboardType;
Settings->OverrideKeyboardSubtype = DefaultOverrideKeyboardSubtype;
Settings->PollingIterations = DefaultPollingIterations;
Settings->PollingIterationsMaximum = DefaultPollingIterationsMaximum;
Settings->ResendIterations = DefaultResendIterations;
Settings->SampleRate = DefaultSampleRate;
Settings->CrashOnCtrlScroll = DefaultCrashOnCtrlScroll;
Status = RtlDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&DefaultKeyboardDeviceBaseName,
&Settings->KeyboardDeviceBaseName);
if (!NT_SUCCESS(Status))
{
DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
}
else
{
Status = RtlDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&DefaultPointerDeviceBaseName,
&Settings->PointerDeviceBaseName);
if (!NT_SUCCESS(Status))
DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
}
}
if (NT_SUCCESS(Status))
{
DPRINT("KeyboardDataQueueSize : 0x%lx\n", Settings->KeyboardDataQueueSize);
DPRINT("KeyboardDeviceBaseName : %wZ\n", &Settings->KeyboardDeviceBaseName);
DPRINT("MouseDataQueueSize : 0x%lx\n", Settings->MouseDataQueueSize);
DPRINT("MouseResolution : 0x%lx\n", Settings->MouseResolution);
DPRINT("MouseSynchIn100ns : %lu\n", Settings->MouseSynchIn100ns);
DPRINT("NumberOfButtons : 0x%lx\n", Settings->NumberOfButtons);
DPRINT("PointerDeviceBaseName : %wZ\n", &Settings->PointerDeviceBaseName);
DPRINT("PollStatusIterations : 0x%lx\n", Settings->PollStatusIterations);
DPRINT("OverrideKeyboardType : 0x%lx\n", Settings->OverrideKeyboardType);
DPRINT("OverrideKeyboardSubtype : 0x%lx\n", Settings->OverrideKeyboardSubtype);
DPRINT("PollingIterations : 0x%lx\n", Settings->PollingIterations);
DPRINT("PollingIterationsMaximum : %lu\n", Settings->PollingIterationsMaximum);
DPRINT("ResendIterations : 0x%lx\n", Settings->ResendIterations);
DPRINT("SampleRate : %lu\n", Settings->SampleRate);
}
return Status;
}
-273
View File
@@ -1,273 +0,0 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/setup.c
* PURPOSE: Create a legacy PDO during ReactOS installation
* PROGRAMMERS: Copyright 2006 Hervé Poussineau (hpoussin@reactos.org)
*/
/* NOTE:
* All this file is a big hack and should be removed one day...
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
#define KEYBOARD_DATA_PORT 0x60
#define KEYBOARD_CONTROL_PORT 0x64
#define KEYBOARD_IRQ 1
/* FUNCTIONS *****************************************************************/
BOOLEAN
IsFirstStageSetup(
VOID)
{
UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\Setup");
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hSetupKey = (HANDLE)NULL;
NTSTATUS Status;
BOOLEAN ret = TRUE;
InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&hSetupKey, KEY_QUERY_VALUE, &ObjectAttributes);
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
ret = TRUE;
else
ret = FALSE;
if (hSetupKey != (HANDLE)NULL)
ZwClose(hSetupKey);
DPRINT("IsFirstStageSetup() returns %s\n", ret ? "YES" : "NO");
return ret;
}
static VOID NTAPI
SendStartDevice(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Context,
IN ULONG Count)
{
PDEVICE_OBJECT Pdo;
PCM_RESOURCE_LIST AllocatedResources = NULL;
PCM_RESOURCE_LIST AllocatedResourcesTranslated = NULL;
PDEVICE_OBJECT TopDeviceObject = NULL;
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PIO_STACK_LOCATION Stack;
ULONG ResourceListSize;
NTSTATUS Status;
Pdo = (PDEVICE_OBJECT)Context;
DPRINT("SendStartDevice(%p)\n", Pdo);
/* Create default resource list */
ResourceListSize = sizeof(CM_RESOURCE_LIST) + 3 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
AllocatedResources = ExAllocatePool(PagedPool, ResourceListSize);
if (!AllocatedResources)
{
DPRINT("ExAllocatePool() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
AllocatedResources->Count = 1;
AllocatedResources->List[0].PartialResourceList.Version = 1;
AllocatedResources->List[0].PartialResourceList.Revision = 1;
AllocatedResources->List[0].PartialResourceList.Count = 3;
/* Data port */
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].Flags = 0; /* FIXME */
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.u.HighPart = 0;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.u.LowPart = KEYBOARD_DATA_PORT;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = 1;
/* Control port */
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].Type = CmResourceTypePort;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].ShareDisposition = CmResourceShareDeviceExclusive;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].Flags = 0; /* FIXME */
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Start.u.HighPart = 0;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Start.u.LowPart = KEYBOARD_CONTROL_PORT;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[1].u.Port.Length = 1;
/* Interrupt */
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].Type = CmResourceTypeInterrupt;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].ShareDisposition = CmResourceShareDeviceExclusive;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level = 0;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector = KEYBOARD_IRQ;
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Affinity = (KAFFINITY)-1;
/* Create default resource list translated */
AllocatedResourcesTranslated = ExAllocatePool(PagedPool, ResourceListSize);
if (!AllocatedResources)
{
DPRINT("ExAllocatePool() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
RtlCopyMemory(AllocatedResourcesTranslated, AllocatedResources, ResourceListSize);
AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector = HalGetInterruptVector(
Internal, 0,
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level,
AllocatedResources->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Vector,
(PKIRQL)&AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Level,
&AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[2].u.Interrupt.Affinity);
/* Send IRP_MN_START_DEVICE */
TopDeviceObject = IoGetAttachedDeviceReference(Pdo);
KeInitializeEvent(
&Event,
NotificationEvent,
FALSE);
Irp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
TopDeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
Irp->IoStatus.Information = 0;
Stack = IoGetNextIrpStackLocation(Irp);
Stack->MinorFunction = IRP_MN_START_DEVICE;
Stack->Parameters.StartDevice.AllocatedResources = AllocatedResources;
Stack->Parameters.StartDevice.AllocatedResourcesTranslated = AllocatedResourcesTranslated;
Status = IoCallDriver(TopDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(
&Event,
Executive,
KernelMode,
FALSE,
NULL);
Status = IoStatusBlock.Status;
}
if (!NT_SUCCESS(Status))
{
DPRINT("IoCallDriver() failed with status 0x%08lx\n", Status);
goto cleanup;
}
cleanup:
if (TopDeviceObject)
ObDereferenceObject(TopDeviceObject);
if (AllocatedResources)
ExFreePool(AllocatedResources);
if (AllocatedResourcesTranslated)
ExFreePool(AllocatedResourcesTranslated);
}
static NTSTATUS
AddRegistryEntry(
IN PCWSTR PortTypeName,
IN PUNICODE_STRING DeviceName,
IN PCWSTR RegistryPath)
{
UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hDeviceMapKey = (HANDLE)-1;
HANDLE hPortKey = (HANDLE)-1;
UNICODE_STRING PortTypeNameU;
NTSTATUS Status;
InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
if (!NT_SUCCESS(Status))
{
DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
goto cleanup;
}
Status = STATUS_SUCCESS;
cleanup:
if (hDeviceMapKey != (HANDLE)-1)
ZwClose(hDeviceMapKey);
if (hPortKey != (HANDLE)-1)
ZwClose(hPortKey);
return Status;
}
NTSTATUS
i8042AddLegacyKeyboard(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING KeyboardName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardPort8042");
PI8042_DEVICE_TYPE DeviceExtension = NULL;
PDEVICE_OBJECT Pdo = NULL;
NTSTATUS Status;
DPRINT("i8042AddLegacyKeyboard()\n");
/* Create a named PDO */
Status = IoCreateDevice(
DriverObject,
sizeof(I8042_DEVICE_TYPE),
&KeyboardName,
FILE_DEVICE_8042_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Pdo);
if (!NT_SUCCESS(Status))
{
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
goto cleanup;
}
/* Initialize device extension */
DeviceExtension = (PI8042_DEVICE_TYPE)Pdo->DeviceExtension;
RtlZeroMemory(DeviceExtension, sizeof(I8042_DEVICE_TYPE));
*DeviceExtension = PhysicalDeviceObject;
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
/* Add FDO at the top of the PDO */
Status = i8042AddDevice(DriverObject, Pdo);
if (!NT_SUCCESS(Status))
{
DPRINT("i8042AddDevice() failed with status 0x%08lx\n", Status);
goto cleanup;
}
/* We will send the IRP_MN_START_DEVICE later, once kbdclass is loaded */
AddRegistryEntry(L"KeyboardPort", &KeyboardName, RegistryPath->Buffer);
IoRegisterBootDriverReinitialization(
DriverObject,
SendStartDevice,
Pdo);
Status = STATUS_SUCCESS;
cleanup:
if (!NT_SUCCESS(Status))
{
if (Pdo)
IoDeleteDevice(Pdo);
}
return Status;
}