mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 12:23:31 +00:00
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:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user