Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.

This commit is contained in:
Colin Finck 2017-10-03 07:45:34 +00:00
parent b94e2d8ca0
commit c2c66aff7d
24198 changed files with 0 additions and 37285 deletions

View file

@ -0,0 +1,5 @@
add_subdirectory(i8042prt)
add_subdirectory(kbdclass)
add_subdirectory(mouclass)
add_subdirectory(sermouse)

View file

@ -0,0 +1,23 @@
list(APPEND SOURCE
createclose.c
hwhacks.c
i8042prt.c
keyboard.c
misc.c
mouse.c
pnp.c
ps2pp.c
readwrite.c
registry.c
i8042prt.h)
add_library(i8042prt SHARED
${SOURCE}
guid.c
i8042prt.rc)
set_module_type(i8042prt kernelmodedriver)
add_importlibs(i8042prt ntoskrnl hal)
add_pch(i8042prt i8042prt.h SOURCE)
add_cd_file(TARGET i8042prt DESTINATION reactos/system32/drivers NO_CAB FOR all)

View file

@ -0,0 +1,80 @@
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.

View file

@ -0,0 +1,57 @@
/*
* 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-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS NTAPI
i8042Create(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
TRACE_(I8042PRT, "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)
{
UNREFERENCED_PARAMETER(DeviceObject);
TRACE_(I8042PRT, "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)
{
UNREFERENCED_PARAMETER(DeviceObject);
TRACE_(I8042PRT, "IRP_MJ_CLOSE\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,102 @@
#pragma once
enum DMI_DEVICE_TYPE
{
DMI_DEV_TYPE_ANY = 0,
DMI_DEV_TYPE_OTHER,
DMI_DEV_TYPE_UNKNOWN,
DMI_DEV_TYPE_VIDEO,
DMI_DEV_TYPE_SCSI,
DMI_DEV_TYPE_ETHERNET,
DMI_DEV_TYPE_TOKENRING,
DMI_DEV_TYPE_SOUND,
DMI_DEV_TYPE_PATA,
DMI_DEV_TYPE_SATA,
DMI_DEV_TYPE_SAS,
DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2,
DMI_DEV_TYPE_DEV_ONBOARD = -3,
};
enum DMI_ENTRY_TYPE
{
DMI_ENTRY_BIOS = 0,
DMI_ENTRY_SYSTEM = 1,
DMI_ENTRY_BASEBOARD = 2,
DMI_ENTRY_CHASSIS = 3,
DMI_ENTRY_PROCESSOR = 4,
DMI_ENTRY_MEM_CONTROLLER = 5,
DMI_ENTRY_MEM_MODULE = 6,
DMI_ENTRY_CACHE = 7,
DMI_ENTRY_PORT_CONNECTOR = 8,
DMI_ENTRY_SYSTEM_SLOT = 9,
DMI_ENTRY_ONBOARD_DEVICE = 10,
DMI_ENTRY_OEMSTRINGS = 11,
DMI_ENTRY_SYSCONF = 12,
DMI_ENTRY_BIOS_LANG = 13,
DMI_ENTRY_GROUP_ASSOC = 14,
DMI_ENTRY_SYSTEM_EVENT_LOG = 15,
DMI_ENTRY_PHYS_MEM_ARRAY = 16,
DMI_ENTRY_MEM_DEVICE = 17,
DMI_ENTRY_32_MEM_ERROR = 18,
DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR = 19,
DMI_ENTRY_MEM_DEV_MAPPED_ADDR = 20,
DMI_ENTRY_BUILTIN_POINTING_DEV,
DMI_ENTRY_PORTABLE_BATTERY,
DMI_ENTRY_SYSTEM_RESET,
DMI_ENTRY_HW_SECURITY,
DMI_ENTRY_SYSTEM_POWER_CONTROLS = 25,
DMI_ENTRY_VOLTAGE_PROBE,
DMI_ENTRY_COOLING_DEV,
DMI_ENTRY_TEMP_PROBE,
DMI_ENTRY_ELECTRICAL_CURRENT_PROBE,
DMI_ENTRY_OOB_REMOTE_ACCESS = 30,
DMI_ENTRY_BIS_ENTRY,
DMI_ENTRY_SYSTEM_BOOT = 32,
DMI_ENTRY_MGMT_DEV,
DMI_ENTRY_MGMT_DEV_COMPONENT,
DMI_ENTRY_MGMT_DEV_THRES = 35,
DMI_ENTRY_MEM_CHANNEL = 36,
DMI_ENTRY_IPMI_DEV = 37,
DMI_ENTRY_SYS_POWER_SUPPLY = 38,
DMI_ENTRY_ADDITIONAL = 39,
DMI_ENTRY_ONBOARD_DEV_EXT = 40,
DMI_ENTRY_MGMT_CONTROLLER_HOST = 41,
DMI_ENTRY_INACTIVE = 126,
DMI_ENTRY_END_OF_TABLE = 127,
};
enum _DMI_FIELD_OFFSETS
{
/* Type = 0: DMI_ENTRY_BIOS */
DMI_BIOS_VENDOR = 0x04,
DMI_BIOS_VERSION = 0x05,
DMI_BIOS_DATE = 0x08,
DMI_BIOS_SIZE = 0x14,
/* Type = 1: DMI_ENTRY_SYSTEM */
DMI_SYS_VENDOR = 0x04,
DMI_SYS_PRODUCT = 0x05,
DMI_SYS_VERSION = 0x06,
DMI_SYS_SERIAL = 0x07,
DMI_SYS_SIZE = 0x1b,
/* Type = 2: DMI_ENTRY_BASEBOARD */
DMI_BOARD_VENDOR = 0x04,
DMI_BOARD_NAME = 0x05,
DMI_BOARD_VERSION = 0x06,
DMI_BOARD_SERIAL = 0x07,
DMI_BOARD_ASSET_TAG = 0x08,
DMI_BOARD_SIZE = 0x10,
};
typedef struct _DMI_HEADER
{
UCHAR Type;
UCHAR Length;
USHORT Handle;
} DMI_HEADER, *PDMI_HEADER;

View file

@ -0,0 +1,7 @@
/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
#include <wdm.h>
#include <initguid.h>
#include <poclass.h>
/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */

View file

@ -0,0 +1,280 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/hwhacks.c
* PURPOSE: Mouse specific functions
* PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
* REFERENCES: - http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
* -
*/
#include "i8042prt.h"
#include <wmiguid.h>
#include <wmidata.h>
#include <wmistr.h>
#include "dmi.h"
#define NDEBUG
#include <debug.h>
const GUID MSSmBios_RawSMBiosTables_GUID = SMBIOS_DATA_GUID;
PVOID i8042SMBiosTables;
ULONG i8042HwFlags;
enum _ID_STRINGS
{
ID_NONE = 0,
BIOS_VENDOR,
BIOS_VERSION,
BIOS_DATE,
SYS_VENDOR,
SYS_PRODUCT,
SYS_VERSION,
SYS_SERIAL,
BOARD_VENDOR,
BOARD_NAME,
BOARD_VERSION,
BOARD_SERIAL,
BOARD_ASSET_TAG,
ID_STRINGS_MAX,
};
typedef struct _MATCHENTRY
{
ULONG Type;
PCHAR String;
} MATCHENTRY;
#define MAX_MATCH_ENTRIES 3
typedef struct _HARDWARE_TABLE
{
MATCHENTRY MatchEntries[MAX_MATCH_ENTRIES];
ULONG Flags;
} HARDWARE_TABLE;
const HARDWARE_TABLE i8042HardwareTable[] =
{
// { {{BOARD_VENDOR, "RIOWORKS"}, {BOARD_NAME, "HDAMB"}, {BOARD_VERSION, "Rev E"}}, FL_NOLOOP },
// { {{BOARD_VENDOR, "ASUSTeK Computer Inc."}, {BOARD_NAME, "G1S"}, {BOARD_VERSION, "1.0"}}, FL_NOLOOP },
{ {{SYS_VENDOR, "Microsoft Corporation"}, {SYS_PRODUCT, "Virtual Machine"}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Inspiron 6000 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D430 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D530 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D531 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D600 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D620 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D630 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude D810 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude E4300 "}}, FL_INITHACK },
{ {{SYS_VENDOR, "Dell Inc."}, {SYS_PRODUCT, "Latitude E4310 "}}, FL_INITHACK },
};
static
PCHAR
GetDmiString(
_In_ PDMI_HEADER Header,
_In_ ULONG FieldOffset)
{
ULONG StringIndex;
PCHAR String;
StringIndex = ((PUCHAR)Header)[FieldOffset];
if (StringIndex == 0)
{
return NULL;
}
String = (PCHAR)Header + Header->Length;
while (--StringIndex != 0)
{
while (*String != 0)
String++;
String++;
}
return String;
}
static
VOID
i8042ParseSMBiosTables(
_In_reads_bytes_(TableSize) PVOID SMBiosTables,
_In_ ULONG TableSize)
{
PMSSmBios_RawSMBiosTables BiosTablesHeader = SMBiosTables;
PDMI_HEADER Header;
ULONG Remaining, i, j;
PCHAR Data;
PCHAR Strings[ID_STRINGS_MAX] = { 0 };
Header = (PDMI_HEADER)(&BiosTablesHeader->SMBiosData);
Remaining = BiosTablesHeader->Size;
while (Remaining >= sizeof(*Header))
{
if (Header->Type == DMI_ENTRY_END_OF_TABLE)
break;
switch (Header->Type)
{
case DMI_ENTRY_BIOS:
if (Remaining < DMI_BIOS_SIZE)
return;
Strings[BIOS_VENDOR] = GetDmiString(Header, DMI_BIOS_VENDOR);
Strings[BIOS_VERSION] = GetDmiString(Header, DMI_BIOS_VERSION);
Strings[BIOS_DATE] = GetDmiString(Header, DMI_BIOS_DATE);
break;
case DMI_ENTRY_SYSTEM:
if (Remaining < DMI_SYS_SIZE)
return;
Strings[SYS_VENDOR] = GetDmiString(Header, DMI_SYS_VENDOR);
Strings[SYS_PRODUCT] = GetDmiString(Header, DMI_SYS_PRODUCT);
Strings[SYS_VERSION] = GetDmiString(Header, DMI_SYS_VERSION);
Strings[SYS_SERIAL] = GetDmiString(Header, DMI_SYS_SERIAL);
break;
case DMI_ENTRY_BASEBOARD:
if (Remaining < DMI_BOARD_SIZE)
return;
Strings[BOARD_VENDOR] = GetDmiString(Header, DMI_BOARD_VENDOR);
Strings[BOARD_NAME] = GetDmiString(Header, DMI_BOARD_NAME);
Strings[BOARD_VERSION] = GetDmiString(Header, DMI_BOARD_VERSION);
Strings[BOARD_SERIAL] = GetDmiString(Header, DMI_BOARD_SERIAL);
Strings[BOARD_ASSET_TAG] = GetDmiString(Header, DMI_BOARD_ASSET_TAG);
break;
case DMI_ENTRY_CHASSIS:
case DMI_ENTRY_ONBOARD_DEVICE:
case DMI_ENTRY_OEMSTRINGS:
// DMI_ENTRY_IPMI_DEV?
// DMI_ENTRY_ONBOARD_DEV_EXT?
break;
}
Remaining -= Header->Length;
Data = (PCHAR)Header + Header->Length;
/* Now loop until we find 2 zeroes */
while ((Remaining >= 2) && ((Data[0] != 0) || (Data[1] != 0)))
{
Data++;
Remaining--;
}
if (Remaining < 2)
break;
/* Go to the next header */
Remaining -= 2;
Header = (PDMI_HEADER)((PUCHAR)Data + 2);
}
#if 0 // DBG
DbgPrint("i8042prt: Dumping DMI data:\n");
DbgPrint("BIOS_VENDOR: %s\n", Strings[BIOS_VENDOR]);
DbgPrint("BIOS_VERSION: %s\n", Strings[BIOS_VERSION]);
DbgPrint("BIOS_DATE: %s\n", Strings[BIOS_DATE]);
DbgPrint("SYS_VENDOR: %s\n", Strings[SYS_VENDOR]);
DbgPrint("SYS_PRODUCT: %s\n", Strings[SYS_PRODUCT]);
DbgPrint("SYS_VERSION: %s\n", Strings[SYS_VERSION]);
DbgPrint("SYS_SERIAL: %s\n", Strings[SYS_SERIAL]);
DbgPrint("BOARD_VENDOR: %s\n", Strings[BOARD_VENDOR]);
DbgPrint("BOARD_NAME: %s\n", Strings[BOARD_NAME]);
DbgPrint("BOARD_VERSION: %s\n", Strings[BOARD_VERSION]);
DbgPrint("BOARD_SERIAL: %s\n", Strings[BOARD_SERIAL]);
DbgPrint("BOARD_ASSET_TAG: %s\n", Strings[BOARD_ASSET_TAG]);
#endif
/* Now loop the hardware table to find a match */
for (i = 0; i < ARRAYSIZE(i8042HardwareTable); i++)
{
for (j = 0; j < MAX_MATCH_ENTRIES; j++)
{
ULONG Type = i8042HardwareTable[i].MatchEntries[j].Type;
if (Type != ID_NONE)
{
/* Check for a match */
if ((Strings[Type] == NULL) ||
strcmp(i8042HardwareTable[i].MatchEntries[j].String,
Strings[i8042HardwareTable[i].MatchEntries[j].Type]))
{
/* Does not match, try next entry */
break;
}
}
}
if (j == MAX_MATCH_ENTRIES)
{
/* All items matched! */
i8042HwFlags = i8042HardwareTable[i].Flags;
DPRINT("Found match for hw table index %u\n", i);
break;
}
}
}
VOID
NTAPI
i8042InitializeHwHacks(
VOID)
{
NTSTATUS Status;
PVOID DataBlockObject;
PWNODE_ALL_DATA AllData;
ULONG BufferSize;
/* Open the data block object for the SMBIOS table */
Status = IoWMIOpenBlock(&MSSmBios_RawSMBiosTables_GUID,
WMIGUID_QUERY,
&DataBlockObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
return;
}
/* Query the required buffer size */
BufferSize = 0;
Status = IoWMIQueryAllData(DataBlockObject, &BufferSize, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
return;
}
AllData = ExAllocatePoolWithTag(PagedPool, BufferSize, 'BTMS');
if (AllData == NULL)
{
DPRINT1("Failed to allocate %lu bytes for SMBIOS tables\n", BufferSize);
return;
}
/* Query the buffer data */
Status = IoWMIQueryAllData(DataBlockObject, &BufferSize, AllData);
if (!NT_SUCCESS(Status))
{
DPRINT1("IoWMIOpenBlock failed: 0x%08lx\n", Status);
ExFreePoolWithTag(AllData, 'BTMS');
return;
}
/* Parse the table */
i8042ParseSMBiosTables(AllData + 1,
AllData->WnodeHeader.BufferSize);
/* Free the buffer */
ExFreePoolWithTag(AllData, 'BTMS');
}

View file

@ -0,0 +1,566 @@
/*
* 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 (sauros@iname.com)
Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#include <debug.h>
/* FUNCTIONS *****************************************************************/
static DRIVER_STARTIO i8042StartIo;
static DRIVER_DISPATCH IrpStub;
_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
static DRIVER_DISPATCH i8042DeviceControl;
_Dispatch_type_(IRP_MJ_INTERNAL_DEVICE_CONTROL)
static DRIVER_DISPATCH i8042InternalDeviceControl;
_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
static DRIVER_DISPATCH i8042SystemControl;
_Dispatch_type_(IRP_MJ_POWER)
static DRIVER_DISPATCH i8042Power;
DRIVER_INITIALIZE DriverEntry;
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;
TRACE_(I8042PRT, "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))
{
WARN_(I8042PRT, "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);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
goto cleanup;
}
ExInterlockedInsertTailList(
&DriverExtension->DeviceListHead,
&DeviceExtension->ListEntry,
&DriverExtension->DeviceListLock);
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;
TRACE_(I8042PRT, "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:
{
ERR_(I8042PRT, "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)
{
WARN_(I8042PRT, "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))
{
WARN_(I8042PRT, "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))
{
WARN_(I8042PRT, "KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status);
WorkItemData->Irp->IoStatus.Status = Status;
goto cleanup;
}
}
}
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);
ExFreePoolWithTag(WorkItemData, I8042PRT_TAG);
}
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:
ERR_(I8042PRT, "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! */
WARN_(I8042PRT, "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:
ERR_(I8042PRT, "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)
{
NTSTATUS Status = Irp->IoStatus.Status;
UNREFERENCED_PARAMETER(DeviceObject);
/* Do nothing */
ASSERT(FALSE);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
static NTSTATUS NTAPI
i8042DeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
TRACE_(I8042PRT, "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);
}
}
static NTSTATUS NTAPI
i8042InternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
ULONG ControlCode;
NTSTATUS Status;
TRACE_(I8042PRT, "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:
ERR_(I8042PRT, "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:
ERR_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type);
ASSERT(FALSE);
Status = STATUS_INTERNAL_ERROR;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
return Status;
}
static NTSTATUS NTAPI
i8042Power(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PDEVICE_OBJECT LowerDevice = DeviceExtension->LowerDevice;
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(LowerDevice, Irp);
}
static NTSTATUS NTAPI
i8042SystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
return ForwardIrpAndForget(DeviceObject, Irp);
}
NTSTATUS NTAPI
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
PI8042_DRIVER_EXTENSION DriverExtension;
ULONG i;
NTSTATUS Status;
/* ROS Hack: ideally, we shouldn't have to initialize debug level this way,
but since the only way is to change it via KDBG, it's better to leave
it here too. */
#if 0
DbgSetDebugFilterState(
DPFLTR_I8042PRT_ID,
(1 << DPFLTR_ERROR_LEVEL) | (1 << DPFLTR_WARNING_LEVEL) |
(1 << DPFLTR_TRACE_LEVEL) /*| (1 << DPFLTR_INFO_LEVEL)*/ | DPFLTR_MASK,
TRUE);
#endif
Status = IoAllocateDriverObjectExtension(
DriverObject,
DriverObject,
sizeof(I8042_DRIVER_EXTENSION),
(PVOID*)&DriverExtension);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
return Status;
}
RtlZeroMemory(DriverExtension, sizeof(I8042_DRIVER_EXTENSION));
KeInitializeSpinLock(&DriverExtension->Port.SpinLock);
InitializeListHead(&DriverExtension->DeviceListHead);
KeInitializeSpinLock(&DriverExtension->DeviceListLock);
Status = DuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
RegistryPath,
&DriverExtension->RegistryPath);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
return Status;
}
Status = ReadRegistryEntries(RegistryPath, &DriverExtension->Port.Settings);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "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_POWER] = i8042Power;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = i8042SystemControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = i8042Pnp;
i8042InitializeHwHacks();
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,459 @@
#ifndef _I8042PRT_PCH_
#define _I8042PRT_PCH_
#include <ntifs.h>
#include <kbdmou.h>
#include <ntdd8042.h>
/*-----------------------------------------------------
* Structures
* --------------------------------------------------*/
#define I8042PRT_TAG '2408'
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 KEYBOARD_CONNECTED 0x02 /* Keyboard received IOCTL_INTERNAL_KEYBOARD_CONNECT */
#define KEYBOARD_STARTED 0x04 /* Keyboard FDO received IRP_MN_START_DEVICE */
#define KEYBOARD_INITIALIZED 0x08 /* Keyboard interrupt is connected */
#define MOUSE_PRESENT 0x10 /* A mouse is attached */
#define MOUSE_CONNECTED 0x20 /* Mouse received IOCTL_INTERNAL_MOUSE_CONNECT */
#define MOUSE_STARTED 0x40 /* Mouse FDO received IRP_MN_START_DEVICE */
#define MOUSE_INITIALIZED 0x80 /* 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;
LIST_ENTRY DeviceListHead;
KSPIN_LOCK DeviceListLock;
} 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;
// Linkage in I8042_DRIVER_EXTENSION.DeviceListHead
LIST_ENTRY ListEntry;
// 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; /* FIXME: IsrWritePort ignored */
KDPC DpcKeyboard;
KEYBOARD_ATTRIBUTES KeyboardAttributes;
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;
BOOLEAN TabPressed;
} 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 MOUSE_ENAB 0xA8
#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_SELF_TEST_OK 0x55
#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_ENAB 0xF4
#define MOU_CMD_RESET 0xFF
/*-----------------------------------------------------
* Mouse responses
* --------------------------------------------------*/
#define MOUSE_ACK 0xFA
#define MOUSE_ERROR 0xFC
#define MOUSE_NACK 0xFE
/*-----------------------------------------------------
* Prototypes
* --------------------------------------------------*/
/* createclose.c */
IO_WORKITEM_ROUTINE i8042SendHookWorkItem;
_Dispatch_type_(IRP_MJ_CREATE)
DRIVER_DISPATCH i8042Create;
_Dispatch_type_(IRP_MJ_CLEANUP)
DRIVER_DISPATCH i8042Cleanup;
_Dispatch_type_(IRP_MJ_CLOSE)
DRIVER_DISPATCH i8042Close;
/* keyboard.c */
NTSTATUS NTAPI
i8042SynchWritePortKbd(
IN PVOID Context,
IN UCHAR Value,
IN BOOLEAN WaitForAck);
DRIVER_STARTIO i8042KbdStartIo;
DRIVER_DISPATCH i8042KbdDeviceControl;
DRIVER_DISPATCH i8042KbdInternalDeviceControl;
KSERVICE_ROUTINE i8042KbdInterruptService;
/* i8042prt.c */
DRIVER_ADD_DEVICE i8042AddDevice;
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 */
DRIVER_DISPATCH ForwardIrpAndForget;
DRIVER_DISPATCH ForwardIrpAndWait;
NTSTATUS
DuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString);
/* 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);
DRIVER_DISPATCH i8042MouInternalDeviceControl;
KSERVICE_ROUTINE i8042MouInterruptService;
/* pnp.c */
BOOLEAN
i8042ChangeMode(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR FlagsToDisable,
IN UCHAR FlagsToEnable);
_Dispatch_type_(IRP_MJ_PNP)
DRIVER_DISPATCH i8042Pnp;
/* ps2pp.c */
VOID
i8042MouHandlePs2pp(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Input);
/* readwrite.c */
VOID
i8042Flush(
IN PPORT_DEVICE_EXTENSION DeviceExtension);
BOOLEAN
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,
OUT 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);
/* hwhacks.c */
VOID
NTAPI
i8042InitializeHwHacks(
VOID);
enum _FLAGS
{
FL_NOLOOP = 0x01,
FL_INITHACK = 0x02,
};
extern ULONG i8042HwFlags;
#endif /* _I8042PRT_PCH_ */

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "i8042 Port Device Driver"
#define REACTOS_STR_INTERNAL_NAME "i8042prt"
#define REACTOS_STR_ORIGINAL_FILENAME "i8042prt.sys"
#include <reactos/version.rc>

View file

@ -0,0 +1,939 @@
/*
* 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 (sauros@iname.com)
Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#include <poclass.h>
#include <ndk/kdfuncs.h>
#include <debug.h>
/* GLOBALS *******************************************************************/
static IO_WORKITEM_ROUTINE i8042PowerWorkItem;
static KDEFERRED_ROUTINE i8042KbdDpcRoutine;
/* 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 *****************************************************************/
/*
* 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;
DeviceExtension->KeyComplete = TRUE;
DeviceExtension->KeysInBuffer++;
if (DeviceExtension->KeysInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize)
{
WARN_(I8042PRT, "Keyboard buffer overflow\n");
DeviceExtension->KeysInBuffer--;
}
TRACE_(I8042PRT, "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
*/
VOID NTAPI
i8042KbdStartIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
PI8042_KEYBOARD_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_KEYBOARD_SET_INDICATORS:
{
TRACE_(I8042PRT, "IOCTL_KEYBOARD_SET_INDICATORS\n");
INFO_(I8042PRT, "Leds: {%s%s%s }\n",
DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON ? " CAPSLOCK" : "",
DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON ? " NUMLOCK" : "",
DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON ? " SCROLLLOCK" : "");
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:
{
ERR_(I8042PRT, "Unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
}
}
}
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;
PIRP WaitingIrp;
NTSTATUS Status;
UNREFERENCED_PARAMETER(DeviceObject);
__analysis_assume(Context != NULL);
DeviceExtension = 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)
{
WaitingIrp = InterlockedExchangePointer((PVOID)&DeviceExtension->PowerIrp, NULL);
if (WaitingIrp)
{
/* Cancel the current power irp, as capability changed */
WaitingIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
WaitingIrp->IoStatus.Information = sizeof(ULONG);
IoCompleteRequest(WaitingIrp, IO_NO_INCREMENT);
}
if (DeviceExtension->PowerInterfaceName.MaximumLength == 0)
{
/* We have never registered 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... */
WARN_(I8042PRT, "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... */
WARN_(I8042PRT, "Disabling interface %wZ failed with status 0x%08lx\n",
&DeviceExtension->PowerInterfaceName, Status);
return;
}
}
/* Enable the interface. This leads to receiving 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... */
WARN_(I8042PRT, "Enabling interface %wZ failed with status 0x%08lx\n",
&DeviceExtension->PowerInterfaceName, Status);
return;
}
}
/* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */
WaitingIrp = InterlockedExchangePointer((PVOID)&DeviceExtension->PowerIrp, NULL);
if (WaitingIrp)
{
PULONG pEvent = (PULONG)WaitingIrp->AssociatedIrp.SystemBuffer;
WaitingIrp->IoStatus.Status = STATUS_SUCCESS;
WaitingIrp->IoStatus.Information = sizeof(ULONG);
*pEvent = InterlockedExchange((PLONG)&DeviceExtension->LastPowerKey, 0);
IoCompleteRequest(WaitingIrp, IO_NO_INCREMENT);
}
}
/* 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;
switch (InputData->MakeCode)
{
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;
}
if (InputData->Flags & KEY_BREAK)
/* We already took care of the key press */
return TRUE;
/* Our work can only be done at passive level, so use a workitem */
DeviceExtension->NewCaps |= KeyPress;
InterlockedExchange((PLONG)&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;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
__analysis_assume(DeferredContext != NULL);
DeviceExtension = 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);
TRACE_(I8042PRT, "Send a key\n");
if (!DeviceExtension->KeyboardData.ClassService)
return;
INFO_(I8042PRT, "Sending %lu key(s)\n", KeysInBufferCopy);
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->KeyboardData.ClassService)(
DeviceExtension->KeyboardData.ClassDeviceObject,
DeviceExtension->KeyboardBuffer,
DeviceExtension->KeyboardBuffer + KeysInBufferCopy,
&KeysTransferred);
KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
DeviceExtension->KeysInBuffer -= KeysTransferred;
KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
/*
* Runs the keyboard IOCTL dispatch.
*/
NTSTATUS NTAPI
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;
TRACE_(I8042PRT, "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;
TRACE_(I8042PRT, "IOCTL_GET_SYS_BUTTON_EVENT\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG))
Status = STATUS_INVALID_PARAMETER;
else
{
WaitingIrp = InterlockedCompareExchangePointer(
(PVOID)&DeviceExtension->PowerIrp,
Irp,
NULL);
/* Check if an Irp is already pending */
if (WaitingIrp)
{
/* Unable to have a 2nd pending IRP for this IOCTL */
WARN_(I8042PRT, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n");
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
{
ULONG PowerKey;
PowerKey = InterlockedExchange((PLONG)&DeviceExtension->LastPowerKey, 0);
if (PowerKey != 0)
{
(VOID)InterlockedCompareExchangePointer((PVOID)&DeviceExtension->PowerIrp, NULL, Irp);
*(PULONG)Irp->AssociatedIrp.SystemBuffer = PowerKey;
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = sizeof(ULONG);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
{
TRACE_(I8042PRT, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n");
Status = STATUS_PENDING;
Irp->IoStatus.Status = Status;
IoMarkIrpPending(Irp);
}
}
return Status;
}
break;
}
default:
{
ERR_(I8042PRT, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}
VOID
NTAPI
i8042InitializeKeyboardAttributes(
PI8042_KEYBOARD_EXTENSION DeviceExtension)
{
PPORT_DEVICE_EXTENSION PortDeviceExtension;
PI8042_SETTINGS Settings;
PKEYBOARD_ATTRIBUTES KeyboardAttributes;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
Settings = &PortDeviceExtension->Settings;
KeyboardAttributes = &DeviceExtension->KeyboardAttributes;
KeyboardAttributes->KeyboardIdentifier.Type = (UCHAR)Settings->OverrideKeyboardType;
KeyboardAttributes->KeyboardIdentifier.Subtype = (UCHAR)Settings->OverrideKeyboardSubtype;
KeyboardAttributes->NumberOfFunctionKeys = 4;
KeyboardAttributes->NumberOfIndicators = 3;
KeyboardAttributes->NumberOfKeysTotal = 101;
KeyboardAttributes->InputDataQueueLength = Settings->KeyboardDataQueueSize;
KeyboardAttributes->KeyRepeatMinimum.UnitId = 0;
KeyboardAttributes->KeyRepeatMinimum.Rate = (USHORT)Settings->SampleRate;
KeyboardAttributes->KeyRepeatMinimum.Delay = 0;
KeyboardAttributes->KeyRepeatMinimum.UnitId = 0;
KeyboardAttributes->KeyRepeatMinimum.Rate = (USHORT)Settings->SampleRate;
KeyboardAttributes->KeyRepeatMinimum.Delay = 0;
}
/*
* Runs the keyboard IOCTL_INTERNAL dispatch.
*/
NTSTATUS NTAPI
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;
TRACE_(I8042PRT, "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)
{
WARN_(I8042PRT, "IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
WorkItemData = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(I8042_HOOK_WORKITEM),
I8042PRT_TAG);
if (!WorkItemData)
{
WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n");
Status = STATUS_NO_MEMORY;
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 = ExAllocatePoolWithTag(
NonPagedPool,
Size,
I8042PRT_TAG);
if (!DeviceExtension->KeyboardBuffer)
{
WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n");
Status = STATUS_NO_MEMORY;
goto cleanup;
}
RtlZeroMemory(DeviceExtension->KeyboardBuffer, Size);
KeInitializeDpc(
&DeviceExtension->DpcKeyboard,
i8042KbdDpcRoutine,
DeviceExtension);
DeviceExtension->PowerWorkItem = IoAllocateWorkItem(DeviceObject);
if (!DeviceExtension->PowerWorkItem)
{
WARN_(I8042PRT, "IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
DeviceExtension->DebugWorkItem = IoAllocateWorkItem(DeviceObject);
if (!DeviceExtension->DebugWorkItem)
{
WARN_(I8042PRT, "IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
DeviceExtension->Common.PortDeviceExtension->KeyboardExtension = DeviceExtension;
DeviceExtension->Common.PortDeviceExtension->Flags |= KEYBOARD_CONNECTED;
i8042InitializeKeyboardAttributes(DeviceExtension);
IoMarkIrpPending(Irp);
/* FIXME: DeviceExtension->KeyboardHook.IsrWritePort = ; */
DeviceExtension->KeyboardHook.QueueKeyboardPacket = i8042KbdQueuePacket;
DeviceExtension->KeyboardHook.CallContext = DeviceExtension;
IoQueueWorkItem(WorkItem,
i8042SendHookWorkItem,
DelayedWorkQueue,
WorkItemData);
Status = STATUS_PENDING;
break;
cleanup:
if (DeviceExtension->KeyboardBuffer)
ExFreePoolWithTag(DeviceExtension->KeyboardBuffer, I8042PRT_TAG);
if (DeviceExtension->PowerWorkItem)
IoFreeWorkItem(DeviceExtension->PowerWorkItem);
if (DeviceExtension->DebugWorkItem)
IoFreeWorkItem(DeviceExtension->DebugWorkItem);
if (WorkItem)
IoFreeWorkItem(WorkItem);
if (WorkItemData)
ExFreePoolWithTag(WorkItemData, I8042PRT_TAG);
break;
}
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
{
TRACE_(I8042PRT, "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:
{
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n");
/* Nothing to do here */
Status = STATUS_SUCCESS;
break;
}
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
{
PKEYBOARD_ATTRIBUTES KeyboardAttributes;
/* FIXME: KeyboardAttributes are not initialized anywhere */
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_ATTRIBUTES))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeyboardAttributes = Irp->AssociatedIrp.SystemBuffer;
*KeyboardAttributes = DeviceExtension->KeyboardAttributes;
Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES);
Status = STATUS_SUCCESS;
break;
}
case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
{
DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_KEYBOARD_SET_TYPEMATIC:
{
DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
{
TRACE_(I8042PRT, "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:
{
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&DeviceExtension->KeyboardIndicators,
sizeof(KEYBOARD_INDICATOR_PARAMETERS));
Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
Status = STATUS_SUCCESS;
}
break;
}
case IOCTL_KEYBOARD_SET_INDICATORS:
{
TRACE_(I8042PRT, "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:
{
ERR_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}
/*
* Call the customization hook. The ToReturn parameter is about whether
* we should go on with the interrupt. The return value is what
* we should return (indicating to the system whether 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 = 0, Output = 0;
BOOLEAN ToReturn = FALSE;
NTSTATUS Status;
UNREFERENCED_PARAMETER(Interrupt);
__analysis_assume(Context != NULL);
DeviceExtension = Context;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer;
Counter = PortDeviceExtension->Settings.PollStatusIterations;
while (Counter)
{
Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "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)
{
WARN_(I8042PRT, "Spurious i8042 keyboard interrupt\n");
return FALSE;
}
INFO_(I8042PRT, "Got: 0x%02x\n", Output);
if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
{
/* Test for CTRL + SCROLL LOCK twice */
static const UCHAR ScanCodes[] = { 0x1d, 0x46, 0xc6, 0x46, 0 };
if (Output == ScanCodes[DeviceExtension->ComboPosition])
{
DeviceExtension->ComboPosition++;
if (ScanCodes[DeviceExtension->ComboPosition] == 0)
KeBugCheck(MANUALLY_INITIATED_CRASH);
}
else if (Output == 0xfa)
{
/* Ignore ACK */
}
else if (Output == ScanCodes[0])
DeviceExtension->ComboPosition = 1;
else
DeviceExtension->ComboPosition = 0;
/* Test for TAB + key combination */
if (InputData->MakeCode == 0x0F)
DeviceExtension->TabPressed = !(InputData->Flags & KEY_BREAK);
else if (DeviceExtension->TabPressed)
{
DeviceExtension->TabPressed = FALSE;
/* Check which action to do */
if (InputData->MakeCode == 0x25)
{
/* k - Breakpoint */
DbgBreakPointWithStatus(DBG_STATUS_SYSRQ);
}
else if (InputData->MakeCode == 0x30)
{
/* b - Bugcheck */
KeBugCheck(MANUALLY_INITIATED_CRASH);
}
#if defined(KDBG)
else
{
/* Send request to the kernel debugger.
* Unknown requests will be ignored. */
KdSystemDebugControl(' soR',
(PVOID)(ULONG_PTR)InputData->MakeCode,
0,
NULL,
0,
NULL,
KernelMode);
}
#endif
}
}
if (i8042KbdCallIsrHook(DeviceExtension, PortStatus, Output, &ToReturn))
return ToReturn;
if (i8042PacketIsr(PortDeviceExtension, Output))
{
if (PortDeviceExtension->PacketComplete)
{
TRACE_(I8042PRT, "Packet complete\n");
KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL);
}
TRACE_(I8042PRT, "Irq eaten by packet\n");
return TRUE;
}
TRACE_(I8042PRT, "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;
DeviceExtension->KeyboardHook.QueueKeyboardPacket(DeviceExtension->KeyboardHook.CallContext);
return TRUE;
}

View file

@ -0,0 +1,114 @@
/*
* 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: Miscellaneous operations
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#include <debug.h>
/* FUNCTIONS *****************************************************************/
static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
static NTSTATUS NTAPI
ForwardIrpAndWaitCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
UNREFERENCED_PARAMETER(DeviceObject);
__analysis_assume(Context != NULL);
if (Irp->PendingReturned)
KeSetEvent(Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS NTAPI
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
KEVENT Event;
NTSTATUS Status;
PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
ASSERT(LowerDevice);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
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);
}
NTSTATUS
DuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString)
{
if (SourceString == NULL || DestinationString == NULL
|| SourceString->Length > SourceString->MaximumLength
|| (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL)
|| Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
{
return STATUS_INVALID_PARAMETER;
}
if ((SourceString->Length == 0)
&& (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
{
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
}
else
{
USHORT DestMaxLength = SourceString->Length;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestMaxLength += sizeof(UNICODE_NULL);
DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, I8042PRT_TAG);
if (DestinationString->Buffer == NULL)
return STATUS_NO_MEMORY;
RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = DestMaxLength;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
}
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,973 @@
/*
* PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/i8042prt/mouse.c
* PURPOSE: Mouse specific functions
* PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com)
Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Martijn Vernooij (o112w8r02@sneakemail.com)
Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
Copyright 2008 Colin Finck (mail@colinfinck.de)
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#include <debug.h>
/* FUNCTIONS *****************************************************************/
static KDEFERRED_ROUTINE i8042MouDpcRoutine;
static KDEFERRED_ROUTINE i8042DpcRoutineMouseTimeout;
/*
* These functions are callbacks for filter driver custom interrupt
* service routines.
*/
static VOID NTAPI
i8042MouIsrWritePort(
IN PVOID Context,
IN UCHAR Value)
{
PI8042_MOUSE_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
if (DeviceExtension->MouseHook.IsrWritePort != i8042MouIsrWritePort)
{
DeviceExtension->MouseHook.IsrWritePort(
DeviceExtension->MouseHook.CallContext,
Value);
}
else
i8042IsrWritePort(DeviceExtension->Common.PortDeviceExtension, Value, CTRL_WRITE_MOUSE);
}
static VOID NTAPI
i8042MouQueuePacket(
IN PVOID Context)
{
PI8042_MOUSE_EXTENSION DeviceExtension;
DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
DeviceExtension->MouseComplete = TRUE;
DeviceExtension->MouseInBuffer++;
if (DeviceExtension->MouseInBuffer >= DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize)
{
WARN_(I8042PRT, "Mouse buffer overflow\n");
DeviceExtension->MouseInBuffer--;
}
TRACE_(I8042PRT, "Irq completes mouse packet\n");
KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
}
VOID
i8042MouHandle(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Output)
{
PMOUSE_INPUT_DATA MouseInput;
CHAR Scroll;
MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
switch (DeviceExtension->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)) {
WARN_(I8042PRT, "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;
DeviceExtension->MouseState = XMovement;
break;
case XMovement:
if (MouseInput->LastX)
MouseInput->LastX = (LONG) Output - 256;
else
MouseInput->LastX = Output;
DeviceExtension->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 (DeviceExtension->MouseType == GenericPS2 ||
DeviceExtension->MouseType == Ps2pp)
{
i8042MouHandleButtons(
DeviceExtension,
MOUSE_LEFT_BUTTON_DOWN |
MOUSE_RIGHT_BUTTON_DOWN |
MOUSE_MIDDLE_BUTTON_DOWN);
DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext);
DeviceExtension->MouseState = MouseIdle;
}
else
{
DeviceExtension->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 (DeviceExtension->MouseType == IntellimouseExplorer)
{
if (Output & 16)
MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
if (Output & 32)
MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
}
i8042MouHandleButtons(
DeviceExtension,
MOUSE_LEFT_BUTTON_DOWN |
MOUSE_RIGHT_BUTTON_DOWN |
MOUSE_MIDDLE_BUTTON_DOWN |
MOUSE_BUTTON_4_DOWN |
MOUSE_BUTTON_5_DOWN);
DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext);
DeviceExtension->MouseState = MouseIdle;
break;
default:
ERR_(I8042PRT, "Unexpected state 0x%lx!\n", DeviceExtension->MouseState);
ASSERT(FALSE);
}
}
/*
* Updates ButtonFlags according to RawButtons and a saved state;
* Only takes in account the bits that are set in Mask
*/
VOID
i8042MouHandleButtons(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN USHORT Mask)
{
PMOUSE_INPUT_DATA MouseInput;
USHORT NewButtonData;
USHORT ButtonDiff;
MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
ButtonDiff = (NewButtonData ^ DeviceExtension->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);
INFO_(I8042PRT, "Left raw/up/down: %u/%u/%u\n",
MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
DeviceExtension->MouseButtonState =
(DeviceExtension->MouseButtonState & ~Mask) | (NewButtonData & Mask);
}
/* Does final initializations for the mouse. This method
* is called just before connecting the interrupt.
*/
NTSTATUS
i8042MouInitialize(
IN PI8042_MOUSE_EXTENSION DeviceExtension)
{
NTSTATUS Status;
UCHAR Value;
/* Enable the PS/2 mouse port */
i8042Write(DeviceExtension->Common.PortDeviceExtension, DeviceExtension->Common.PortDeviceExtension->ControlPort, MOUSE_ENAB);
/* Enable the mouse */
if(!i8042IsrWritePort(DeviceExtension->Common.PortDeviceExtension, MOU_ENAB, CTRL_WRITE_MOUSE))
{
WARN_(I8042PRT, "Failed to enable mouse!\n");
return STATUS_IO_DEVICE_ERROR;
}
Status = i8042ReadDataWait(DeviceExtension->Common.PortDeviceExtension, &Value);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "Failed to read the response of MOU_ENAB, status 0x%08lx\n", Status);
return Status;
}
if(Value == MOUSE_ACK)
{
INFO_(I8042PRT, "Mouse was enabled successfully!\n");
return STATUS_SUCCESS;
}
WARN_(I8042PRT, "Got 0x%02x instead of 0xFA\n", Value);
return STATUS_IO_DEVICE_ERROR;
}
static VOID NTAPI
i8042MouDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
PI8042_MOUSE_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
ULONG MouseTransferred = 0;
ULONG MouseInBufferCopy;
KIRQL Irql;
LARGE_INTEGER Timeout;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
__analysis_assume(DeferredContext != NULL);
DeviceExtension = DeferredContext;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
switch (DeviceExtension->MouseTimeoutState)
{
case TimeoutStart:
{
DeviceExtension->MouseTimeoutState = NoChange;
if (DeviceExtension->MouseTimeoutActive &&
!KeCancelTimer(&DeviceExtension->TimerMouseTimeout))
{
/* The timer fired already, give up */
DeviceExtension->MouseTimeoutActive = FALSE;
return;
}
Timeout.QuadPart = -15000000; /* 1.5 seconds, should be enough */
KeSetTimer(
&DeviceExtension->TimerMouseTimeout,
Timeout,
&DeviceExtension->DpcMouseTimeout);
DeviceExtension->MouseTimeoutActive = TRUE;
return;
}
case TimeoutCancel:
{
DeviceExtension->MouseTimeoutState = NoChange;
KeCancelTimer(&DeviceExtension->TimerMouseTimeout);
DeviceExtension->MouseTimeoutActive = FALSE;
}
default:
;/* nothing, don't want a warning */
}
/* Should be unlikely */
if (!DeviceExtension->MouseComplete)
return;
Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
DeviceExtension->MouseComplete = FALSE;
MouseInBufferCopy = DeviceExtension->MouseInBuffer;
KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
TRACE_(I8042PRT, "Send a mouse packet\n");
if (!DeviceExtension->MouseData.ClassService)
return;
INFO_(I8042PRT, "Sending %lu mouse move(s)\n", MouseInBufferCopy);
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->MouseData.ClassService)(
DeviceExtension->MouseData.ClassDeviceObject,
DeviceExtension->MouseBuffer,
DeviceExtension->MouseBuffer + MouseInBufferCopy,
&MouseTransferred);
Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
DeviceExtension->MouseInBuffer -= MouseTransferred;
if (DeviceExtension->MouseInBuffer)
RtlMoveMemory(
DeviceExtension->MouseBuffer,
DeviceExtension->MouseBuffer + MouseTransferred,
DeviceExtension->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
KeReleaseInterruptSpinLock(PortDeviceExtension->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.
*/
static VOID NTAPI
i8042DpcRoutineMouseTimeout(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
PI8042_MOUSE_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
KIRQL Irql;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
__analysis_assume(DeferredContext != NULL);
DeviceExtension = DeferredContext;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
WARN_(I8042PRT, "Mouse initialization timeout! (substate %x)\n",
DeviceExtension->MouseResetState);
PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
}
/*
* Runs the mouse IOCTL_INTERNAL dispatch.
*/
NTSTATUS NTAPI
i8042MouInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
PI8042_MOUSE_EXTENSION DeviceExtension;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
DeviceExtension = (PI8042_MOUSE_EXTENSION)DeviceObject->DeviceExtension;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_INTERNAL_MOUSE_CONNECT:
{
SIZE_T Size;
PIO_WORKITEM WorkItem = NULL;
PI8042_HOOK_WORKITEM WorkItemData = NULL;
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
{
Status = STATUS_INVALID_PARAMETER;
goto cleanup;
}
DeviceExtension->MouseData =
*((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
/* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
WorkItem = IoAllocateWorkItem(DeviceObject);
if (!WorkItem)
{
WARN_(I8042PRT, "IoAllocateWorkItem() failed\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
WorkItemData = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(I8042_HOOK_WORKITEM),
I8042PRT_TAG);
if (!WorkItemData)
{
WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n");
Status = STATUS_NO_MEMORY;
goto cleanup;
}
WorkItemData->WorkItem = WorkItem;
WorkItemData->Irp = Irp;
/* Initialize extension */
DeviceExtension->Common.Type = Mouse;
Size = DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA);
DeviceExtension->MouseBuffer = ExAllocatePoolWithTag(
NonPagedPool,
Size,
I8042PRT_TAG);
if (!DeviceExtension->MouseBuffer)
{
WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n");
Status = STATUS_NO_MEMORY;
goto cleanup;
}
RtlZeroMemory(DeviceExtension->MouseBuffer, Size);
DeviceExtension->MouseAttributes.InputDataQueueLength =
DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize;
KeInitializeDpc(
&DeviceExtension->DpcMouse,
i8042MouDpcRoutine,
DeviceExtension);
KeInitializeDpc(
&DeviceExtension->DpcMouseTimeout,
i8042DpcRoutineMouseTimeout,
DeviceExtension);
KeInitializeTimer(&DeviceExtension->TimerMouseTimeout);
DeviceExtension->Common.PortDeviceExtension->MouseExtension = DeviceExtension;
DeviceExtension->Common.PortDeviceExtension->Flags |= MOUSE_CONNECTED;
IoMarkIrpPending(Irp);
DeviceExtension->MouseState = MouseResetting;
DeviceExtension->MouseResetState = ExpectingReset;
DeviceExtension->MouseHook.IsrWritePort = i8042MouIsrWritePort;
DeviceExtension->MouseHook.QueueMousePacket = i8042MouQueuePacket;
DeviceExtension->MouseHook.CallContext = DeviceExtension;
IoQueueWorkItem(WorkItem,
i8042SendHookWorkItem,
DelayedWorkQueue,
WorkItemData);
Status = STATUS_PENDING;
break;
cleanup:
if (DeviceExtension->MouseBuffer)
ExFreePoolWithTag(DeviceExtension->MouseBuffer, I8042PRT_TAG);
if (WorkItem)
IoFreeWorkItem(WorkItem);
if (WorkItemData)
ExFreePoolWithTag(WorkItemData, I8042PRT_TAG);
break;
}
case IOCTL_INTERNAL_MOUSE_DISCONNECT:
{
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
/* MSDN says that operation is to implemented.
* To implement it, we just have to do:
* DeviceExtension->MouseData.ClassService = NULL;
*/
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
{
PINTERNAL_I8042_HOOK_MOUSE MouseHook;
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(INTERNAL_I8042_HOOK_MOUSE))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
MouseHook = (PINTERNAL_I8042_HOOK_MOUSE)Stack->Parameters.DeviceIoControl.Type3InputBuffer;
DeviceExtension->MouseHook.Context = MouseHook->Context;
if (MouseHook->IsrRoutine)
DeviceExtension->MouseHook.IsrRoutine = MouseHook->IsrRoutine;
Status = STATUS_SUCCESS;
break;
}
case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
{
DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION:
{
DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_MOUSE_QUERY_ATTRIBUTES:
{
TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
*(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = DeviceExtension->MouseAttributes;
Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
Status = STATUS_SUCCESS;
break;
}
default:
{
ERR_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}
/* 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
i8042MouInputTestTimeout(
IN PI8042_MOUSE_EXTENSION DeviceExtension)
{
ULARGE_INTEGER Now;
if (DeviceExtension->MouseState == MouseExpectingACK ||
DeviceExtension->MouseState == MouseResetting)
return;
Now.QuadPart = KeQueryInterruptTime();
if (DeviceExtension->MouseState != MouseIdle) {
/* Check if the last byte came too long ago */
if (Now.QuadPart - DeviceExtension->MousePacketStartTime.QuadPart >
DeviceExtension->Common.PortDeviceExtension->Settings.MouseSynchIn100ns)
{
WARN_(I8042PRT, "Mouse input packet timeout\n");
DeviceExtension->MouseState = MouseIdle;
}
}
if (DeviceExtension->MouseState == MouseIdle)
DeviceExtension->MousePacketStartTime.QuadPart = Now.QuadPart;
}
/*
* 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
i8042MouCallIsrHook(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Status,
IN UCHAR Input,
OUT PBOOLEAN ToReturn)
{
BOOLEAN HookReturn, HookContinue;
HookContinue = FALSE;
if (DeviceExtension->MouseHook.IsrRoutine)
{
HookReturn = DeviceExtension->MouseHook.IsrRoutine(
DeviceExtension->MouseHook.Context,
DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
&DeviceExtension->Common.PortDeviceExtension->Packet,
Status,
&Input,
&HookContinue,
&DeviceExtension->MouseState,
&DeviceExtension->MouseResetState);
if (!HookContinue)
{
*ToReturn = HookReturn;
return TRUE;
}
}
return FALSE;
}
static BOOLEAN
i8042MouResetIsr(
IN PI8042_MOUSE_EXTENSION DeviceExtension,
IN UCHAR Status,
IN UCHAR Value)
{
PPORT_DEVICE_EXTENSION PortDeviceExtension;
BOOLEAN ToReturn = FALSE;
if (i8042MouCallIsrHook(DeviceExtension, Status, Value, &ToReturn))
return ToReturn;
if (MouseIdle == DeviceExtension->MouseState)
{
/* Magic packet value that indicates a reset */
if (0xAA == Value)
{
WARN_(I8042PRT, "Hot plugged mouse!\n");
DeviceExtension->MouseState = MouseResetting;
DeviceExtension->MouseResetState = ExpectingReset;
}
else
return FALSE;
}
else if (MouseResetting != DeviceExtension->MouseState)
return FALSE;
DeviceExtension->MouseTimeoutState = TimeoutStart;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
switch ((ULONG)DeviceExtension->MouseResetState)
{
case ExpectingReset:
if (MOUSE_ACK == Value)
{
WARN_(I8042PRT, "Dropping extra ACK\n");
return TRUE;
}
/* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
if (0xAA == Value)
{
DeviceExtension->MouseResetState++;
}
else
{
PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
DeviceExtension->MouseState = MouseIdle;
WARN_(I8042PRT, "Mouse returned bad reset reply: %x (expected aa)\n", Value);
}
return TRUE;
case ExpectingResetId:
if (MOUSE_ACK == Value)
{
WARN_(I8042PRT, "Dropping extra ACK #2\n");
return TRUE;
}
if (0x00 == Value)
{
DeviceExtension->MouseResetState++;
DeviceExtension->MouseType = GenericPS2;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2);
}
else
{
PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
DeviceExtension->MouseState = MouseIdle;
WARN_(I8042PRT, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value);
}
return TRUE;
case ExpectingGetDeviceIdACK:
if (MOUSE_ACK == Value)
{
DeviceExtension->MouseResetState++;
}
else if (MOUSE_NACK == Value || MOUSE_ERROR == Value)
{
DeviceExtension->MouseResetState++;
/* Act as if 00 (normal mouse) was received */
WARN_(I8042PRT, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value, MOUSE_ACK);
i8042MouResetIsr(DeviceExtension, Status, 0);
}
return TRUE;
case ExpectingGetDeviceIdValue:
switch (Value)
{
case 0x02:
DeviceExtension->MouseAttributes.MouseIdentifier =
BALLPOINT_I8042_HARDWARE;
break;
case 0x03:
case 0x04:
DeviceExtension->MouseAttributes.MouseIdentifier =
WHEELMOUSE_I8042_HARDWARE;
break;
default:
DeviceExtension->MouseAttributes.MouseIdentifier =
MOUSE_I8042_HARDWARE;
}
DeviceExtension->MouseResetState++;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE8);
return TRUE;
case ExpectingSetResolutionDefaultACK:
DeviceExtension->MouseResetState++;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x00);
return TRUE;
case ExpectingSetResolutionDefaultValueACK:
DeviceExtension->MouseResetState = ExpectingSetScaling1to1ACK;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE6);
return TRUE;
case ExpectingSetScaling1to1ACK:
case ExpectingSetScaling1to1ACK2:
DeviceExtension->MouseResetState++;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE6);
return TRUE;
case ExpectingSetScaling1to1ACK3:
DeviceExtension->MouseResetState++;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE9);
return TRUE;
case ExpectingReadMouseStatusACK:
DeviceExtension->MouseResetState++;
return TRUE;
case ExpectingReadMouseStatusByte1:
DeviceExtension->MouseLogiBuffer[0] = Value;
DeviceExtension->MouseResetState++;
return TRUE;
case ExpectingReadMouseStatusByte2:
DeviceExtension->MouseLogiBuffer[1] = Value;
DeviceExtension->MouseResetState++;
return TRUE;
case ExpectingReadMouseStatusByte3:
DeviceExtension->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 (DeviceExtension->MouseLogiBuffer[1])
{
DeviceExtension->MouseAttributes.NumberOfButtons =
DeviceExtension->MouseLogiBuffer[1];
DeviceExtension->MouseType = Ps2pp;
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
/* TODO: Go through EnableWheel and Enable5Buttons */
return TRUE;
}
DeviceExtension->MouseResetState = EnableWheel;
i8042MouResetIsr(DeviceExtension, Status, Value);
return TRUE;
case EnableWheel:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState = 1001;
return TRUE;
case 1001:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xC8);
DeviceExtension->MouseResetState++;
return TRUE;
case 1002:
case 1004:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState++;
return TRUE;
case 1003:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x64);
DeviceExtension->MouseResetState++;
return TRUE;
case 1005:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x50);
DeviceExtension->MouseResetState++;
return TRUE;
case 1006:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2);
DeviceExtension->MouseResetState++;
return TRUE;
case 1007:
/* Ignore ACK */
DeviceExtension->MouseResetState++;
return TRUE;
case 1008:
if (0x03 == Value) {
/* It's either an Intellimouse or Intellimouse Explorer. */
DeviceExtension->MouseAttributes.NumberOfButtons = 3;
DeviceExtension->MouseAttributes.MouseIdentifier =
WHEELMOUSE_I8042_HARDWARE;
DeviceExtension->MouseType = Intellimouse;
DeviceExtension->MouseResetState = Enable5Buttons;
i8042MouResetIsr(DeviceExtension, Status, Value);
}
else
{
/* Just set the default settings and be done */
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
}
return TRUE;
case Enable5Buttons:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState = 1021;
return TRUE;
case 1022:
case 1024:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState++;
return TRUE;
case 1021:
case 1023:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xC8);
DeviceExtension->MouseResetState++;
return TRUE;
case 1025:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x50);
DeviceExtension->MouseResetState++;
return TRUE;
case 1026:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2);
DeviceExtension->MouseResetState++;
return TRUE;
case 1027:
if (0x04 == Value)
{
DeviceExtension->MouseAttributes.NumberOfButtons = 5;
DeviceExtension->MouseAttributes.MouseIdentifier =
WHEELMOUSE_I8042_HARDWARE;
DeviceExtension->MouseType = IntellimouseExplorer;
}
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
return TRUE;
case ExpectingSetSamplingRateACK:
DeviceExtension->MouseHook.IsrWritePort(
DeviceExtension->MouseHook.CallContext,
(UCHAR)DeviceExtension->MouseAttributes.SampleRate);
DeviceExtension->MouseResetState++;
return TRUE;
case ExpectingSetSamplingRateValueACK:
if (MOUSE_NACK == Value)
{
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x3C);
DeviceExtension->MouseAttributes.SampleRate = (USHORT)PortDeviceExtension->Settings.SampleRate;
DeviceExtension->MouseResetState = 1040;
return TRUE;
}
case 1040: /* Fallthrough */
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE8);
DeviceExtension->MouseResetState = ExpectingFinalResolutionACK;
return TRUE;
case ExpectingFinalResolutionACK:
DeviceExtension->MouseHook.IsrWritePort(
DeviceExtension->MouseHook.CallContext,
(UCHAR)(PortDeviceExtension->Settings.MouseResolution & 0xff));
INFO_(I8042PRT, "Mouse resolution %lu\n",
PortDeviceExtension->Settings.MouseResolution);
DeviceExtension->MouseResetState = ExpectingFinalResolutionValueACK;
return TRUE;
case ExpectingFinalResolutionValueACK:
DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF4);
DeviceExtension->MouseResetState = ExpectingEnableACK;
return TRUE;
case ExpectingEnableACK:
PortDeviceExtension->Flags |= MOUSE_PRESENT;
DeviceExtension->MouseState = MouseIdle;
DeviceExtension->MouseTimeoutState = TimeoutCancel;
INFO_(I8042PRT, "Mouse type = %u\n", DeviceExtension->MouseType);
return TRUE;
default:
if (DeviceExtension->MouseResetState < 100 || DeviceExtension->MouseResetState > 999)
ERR_(I8042PRT, "MouseResetState went out of range: %lu\n", DeviceExtension->MouseResetState);
return FALSE;
}
}
BOOLEAN NTAPI
i8042MouInterruptService(
IN PKINTERRUPT Interrupt,
PVOID Context)
{
PI8042_MOUSE_EXTENSION DeviceExtension;
PPORT_DEVICE_EXTENSION PortDeviceExtension;
ULONG Counter;
UCHAR Output = 0, PortStatus = 0;
NTSTATUS Status;
UNREFERENCED_PARAMETER(Interrupt);
__analysis_assume(Context != NULL);
DeviceExtension = Context;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
Counter = PortDeviceExtension->Settings.PollStatusIterations;
while (Counter)
{
Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "i8042ReadStatus() failed with status 0x%08lx\n", Status);
return FALSE;
}
Status = i8042ReadMouseData(PortDeviceExtension, &Output);
if (NT_SUCCESS(Status))
break;
KeStallExecutionProcessor(1);
Counter--;
}
if (Counter == 0)
{
WARN_(I8042PRT, "Spurious i8042 mouse interrupt\n");
return FALSE;
}
INFO_(I8042PRT, "Got: 0x%02x\n", Output);
if (i8042PacketIsr(PortDeviceExtension, Output))
{
if (PortDeviceExtension->PacketComplete)
{
TRACE_(I8042PRT, "Packet complete\n");
KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
}
TRACE_(I8042PRT, "Irq eaten by packet\n");
return TRUE;
}
TRACE_(I8042PRT, "Irq is mouse input\n");
i8042MouInputTestTimeout(DeviceExtension);
if (i8042MouResetIsr(DeviceExtension, PortStatus, Output))
{
TRACE_(I8042PRT, "Handled by ResetIsr or hooked Isr\n");
if (NoChange != DeviceExtension->MouseTimeoutState) {
KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
}
return TRUE;
}
if (DeviceExtension->MouseType == Ps2pp)
i8042MouHandlePs2pp(DeviceExtension, Output);
else
i8042MouHandle(DeviceExtension, Output);
return TRUE;
}

View file

@ -0,0 +1,769 @@
/*
* 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-2007 Hervé Poussineau (hpoussin@reactos.org)
* Copyright 2008 Colin Finck (mail@colinfinck.de)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#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))
{
WARN_(I8042PRT, "Can't read i8042 mode\n");
return FALSE;
}
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "No response after read i8042 mode\n");
return FALSE;
}
Value &= ~FlagsToDisable;
Value |= FlagsToEnable;
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE))
{
WARN_(I8042PRT, "Can't set i8042 mode\n");
return FALSE;
}
if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
{
WARN_(I8042PRT, "Can't send i8042 mode\n");
return FALSE;
}
return TRUE;
}
static NTSTATUS
i8042BasicDetect(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
NTSTATUS Status;
ULONG ResendIterations;
UCHAR Value = 0;
/* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */
i8042Flush(DeviceExtension);
if (!i8042ChangeMode(DeviceExtension, CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB, CCB_KBD_DISAB | CCB_MOUSE_DISAB))
return STATUS_IO_DEVICE_ERROR;
i8042Flush(DeviceExtension);
/* Issue a CTRL_SELF_TEST command to check if this is really an i8042 controller */
ResendIterations = DeviceExtension->Settings.ResendIterations + 1;
while (ResendIterations--)
{
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST))
{
WARN_(I8042PRT, "Writing CTRL_SELF_TEST command failed\n");
return STATUS_IO_TIMEOUT;
}
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status);
return Status;
}
if (Value == KBD_SELF_TEST_OK)
{
INFO_(I8042PRT, "CTRL_SELF_TEST completed successfully!\n");
break;
}
else if (Value == KBD_RESEND)
{
TRACE_(I8042PRT, "Resending...\n");
KeStallExecutionProcessor(50);
}
else
{
WARN_(I8042PRT, "Got 0x%02x instead of 0x55\n", Value);
return STATUS_IO_DEVICE_ERROR;
}
}
return STATUS_SUCCESS;
}
static VOID
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))
{
WARN_(I8042PRT, "Can't finish SET_LEDS (0x%08lx)\n", Status);
return;
}
}
else
{
WARN_(I8042PRT, "Warning: can't write SET_LEDS (0x%08lx)\n", Status);
}
/* Turn on translation and SF (Some machines don't reboot if SF is not set, see ReactOS bug CORE-1713) */
if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE | CCB_SYSTEM_FLAG))
return;
/*
* We used to send a KBD_LINE_TEST (0xAB) command, 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;
INFO_(I8042PRT, "Keyboard detected\n");
}
static VOID
i8042DetectMouse(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
NTSTATUS Status;
UCHAR Value;
UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA };
UCHAR ReplyByte;
/* First do a mouse line test */
if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST))
{
Status = i8042ReadDataWait(DeviceExtension, &Value);
if (!NT_SUCCESS(Status) || Value != 0)
{
WARN_(I8042PRT, "Mouse line test failed\n");
goto failure;
}
}
/* Now reset the mouse */
i8042Flush(DeviceExtension);
if(!i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE))
{
WARN_(I8042PRT, "Failed to write reset command to mouse\n");
goto failure;
}
/* The implementation of the "Mouse Reset" command differs much from chip to chip.
By default, the first byte is an ACK, when the mouse is plugged in and working and NACK when it's not.
On success, the next bytes are 0xAA and 0x00.
But on some systems (like ECS K7S5A Pro, SiS 735 chipset), we always get an ACK and 0xAA.
Only the last byte indicates, whether a mouse is plugged in.
It is either sent or not, so there is no byte, which indicates a failure here.
After the Mouse Reset command was issued, it usually takes some time until we get a response.
So get the first two bytes in a loop. */
for (ReplyByte = 0;
ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]);
ReplyByte++)
{
ULONG Counter = 500;
do
{
Status = i8042ReadDataWait(DeviceExtension, &Value);
if(!NT_SUCCESS(Status))
{
/* Wait some time before trying again */
KeStallExecutionProcessor(50);
}
} while (Status == STATUS_IO_TIMEOUT && Counter--);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "No ACK after mouse reset, status 0x%08lx\n", Status);
goto failure;
}
else if (Value != ExpectedReply[ReplyByte])
{
WARN_(I8042PRT, "Unexpected reply: 0x%02x (expected 0x%02x)\n", Value, ExpectedReply[ReplyByte]);
goto failure;
}
}
/* Finally get the third byte, but only try it one time (see above).
Otherwise this takes around 45 seconds on a K7S5A Pro, when no mouse is plugged in. */
Status = i8042ReadDataWait(DeviceExtension, &Value);
if(!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "Last byte was not transmitted after mouse reset, status 0x%08lx\n", Status);
goto failure;
}
else if(Value != 0x00)
{
WARN_(I8042PRT, "Last byte after mouse reset was not 0x00, but 0x%02x\n", Value);
goto failure;
}
DeviceExtension->Flags |= MOUSE_PRESENT;
INFO_(I8042PRT, "Mouse detected\n");
return;
failure:
/* 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);
INFO_(I8042PRT, "Mouse not detected\n");
}
static NTSTATUS
i8042ConnectKeyboardInterrupt(
IN PI8042_KEYBOARD_EXTENSION DeviceExtension)
{
PPORT_DEVICE_EXTENSION PortDeviceExtension;
KIRQL DirqlMax;
NTSTATUS Status;
TRACE_(I8042PRT, "i8042ConnectKeyboardInterrupt()\n");
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
DirqlMax = MAX(
PortDeviceExtension->KeyboardInterrupt.Dirql,
PortDeviceExtension->MouseInterrupt.Dirql);
INFO_(I8042PRT, "KeyboardInterrupt.Vector %lu\n",
PortDeviceExtension->KeyboardInterrupt.Vector);
INFO_(I8042PRT, "KeyboardInterrupt.Dirql %lu\n",
PortDeviceExtension->KeyboardInterrupt.Dirql);
INFO_(I8042PRT, "KeyboardInterrupt.DirqlMax %lu\n",
DirqlMax);
INFO_(I8042PRT, "KeyboardInterrupt.InterruptMode %s\n",
PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
INFO_(I8042PRT, "KeyboardInterrupt.ShareInterrupt %s\n",
PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no");
INFO_(I8042PRT, "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))
{
WARN_(I8042PRT, "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;
TRACE_(I8042PRT, "i8042ConnectMouseInterrupt()\n");
Status = i8042MouInitialize(DeviceExtension);
if (!NT_SUCCESS(Status))
return Status;
PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
DirqlMax = MAX(
PortDeviceExtension->KeyboardInterrupt.Dirql,
PortDeviceExtension->MouseInterrupt.Dirql);
INFO_(I8042PRT, "MouseInterrupt.Vector %lu\n",
PortDeviceExtension->MouseInterrupt.Vector);
INFO_(I8042PRT, "MouseInterrupt.Dirql %lu\n",
PortDeviceExtension->MouseInterrupt.Dirql);
INFO_(I8042PRT, "MouseInterrupt.DirqlMax %lu\n",
DirqlMax);
INFO_(I8042PRT, "MouseInterrupt.InterruptMode %s\n",
PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched");
INFO_(I8042PRT, "MouseInterrupt.ShareInterrupt %s\n",
PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no");
INFO_(I8042PRT, "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))
{
WARN_(I8042PRT, "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,
IN UCHAR FlagsToDisable,
IN UCHAR FlagsToEnable)
{
i8042Flush(DeviceExtension);
if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable))
return STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
static NTSTATUS
StartProcedure(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
UCHAR FlagsToDisable = 0;
UCHAR FlagsToEnable = 0;
KIRQL Irql;
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 */
TRACE_(I8042PRT, "Check if the controller is really a i8042\n");
Status = i8042BasicDetect(DeviceExtension);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "i8042BasicDetect() failed with status 0x%08lx\n", Status);
return STATUS_UNSUCCESSFUL;
}
/* First detect the mouse and then the keyboard!
If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */
TRACE_(I8042PRT, "Detecting mouse\n");
i8042DetectMouse(DeviceExtension);
TRACE_(I8042PRT, "Detecting keyboard\n");
i8042DetectKeyboard(DeviceExtension);
INFO_(I8042PRT, "Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO");
INFO_(I8042PRT, "Mouse present : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO");
TRACE_(I8042PRT, "Enabling i8042 interrupts\n");
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;
}
Status = EnableInterrupts(DeviceExtension, FlagsToDisable, FlagsToEnable);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "EnableInterrupts failed: %lx\n", Status);
DeviceExtension->Flags &= ~(KEYBOARD_PRESENT | MOUSE_PRESENT);
return Status;
}
}
/* Connect interrupts */
if (DeviceExtension->Flags & KEYBOARD_PRESENT &&
DeviceExtension->Flags & KEYBOARD_CONNECTED &&
DeviceExtension->Flags & KEYBOARD_STARTED &&
!(DeviceExtension->Flags & KEYBOARD_INITIALIZED))
{
/* Keyboard is ready to be initialized */
Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension);
if (NT_SUCCESS(Status))
{
DeviceExtension->Flags |= KEYBOARD_INITIALIZED;
}
else
{
WARN_(I8042PRT, "i8042ConnectKeyboardInterrupt failed: %lx\n", Status);
}
}
if (DeviceExtension->Flags & MOUSE_PRESENT &&
DeviceExtension->Flags & MOUSE_CONNECTED &&
DeviceExtension->Flags & MOUSE_STARTED &&
!(DeviceExtension->Flags & MOUSE_INITIALIZED))
{
/* Mouse is ready to be initialized */
Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension);
if (NT_SUCCESS(Status))
{
DeviceExtension->Flags |= MOUSE_INITIALIZED;
}
else
{
WARN_(I8042PRT, "i8042ConnectMouseInterrupt failed: %lx\n", Status);
}
/* Start the mouse */
Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
/* HACK: the mouse has already been reset in i8042DetectMouse. This second
reset prevents some touchpads/mice from working (Dell D531, D600).
See CORE-6901 */
if (!(i8042HwFlags & FL_INITHACK))
{
i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE);
}
KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
}
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 = { NULL };
BOOLEAN FoundDataPort = FALSE;
BOOLEAN FoundControlPort = FALSE;
BOOLEAN FoundIrq = FALSE;
ULONG i;
NTSTATUS Status;
TRACE_(I8042PRT, "i8042PnpStartDevice(%p)\n", DeviceObject);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
PortDeviceExtension = DeviceExtension->PortDeviceExtension;
ASSERT(DeviceExtension->PnpState == dsStopped);
if (!AllocatedResources)
{
WARN_(I8042PRT, "No allocated resources sent to driver\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if (AllocatedResources->Count != 1)
{
WARN_(I8042PRT, "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)
{
WARN_(I8042PRT, "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 resource will
* be the control port and the second one
* will be the data port...
*/
if (!FoundDataPort)
{
PortDeviceExtension->DataPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart);
INFO_(I8042PRT, "Found data port: %p\n", PortDeviceExtension->DataPort);
FoundDataPort = TRUE;
}
else if (!FoundControlPort)
{
PortDeviceExtension->ControlPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart);
INFO_(I8042PRT, "Found control port: %p\n", PortDeviceExtension->ControlPort);
FoundControlPort = TRUE;
}
else
{
/* FIXME: implement PS/2 Active Multiplexing */
ERR_(I8042PRT, "Unhandled I/O ranges provided: 0x%lx\n", ResourceDescriptor->u.Port.Length);
}
}
else
WARN_(I8042PRT, "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);
INFO_(I8042PRT, "Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Level);
FoundIrq = TRUE;
break;
}
default:
WARN_(I8042PRT, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
}
}
if (!FoundIrq)
{
WARN_(I8042PRT, "Interrupt resource was not found in allocated resources list\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort))
{
WARN_(I8042PRT, "Some required resources were not found in allocated resources list\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort))
{
WARN_(I8042PRT, "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:
{
WARN_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type);
ASSERT(!(PortDeviceExtension->Flags & KEYBOARD_CONNECTED) || !(PortDeviceExtension->Flags & MOUSE_CONNECTED));
Status = STATUS_INVALID_DEVICE_REQUEST;
}
}
if (NT_SUCCESS(Status))
DeviceExtension->PnpState = dsStarted;
return Status;
}
static VOID
i8042RemoveDevice(
IN PDEVICE_OBJECT DeviceObject)
{
PI8042_DRIVER_EXTENSION DriverExtension;
KIRQL OldIrql;
PFDO_DEVICE_EXTENSION DeviceExtension;
DriverExtension = (PI8042_DRIVER_EXTENSION)IoGetDriverObjectExtension(DeviceObject->DriverObject, DeviceObject->DriverObject);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
KeAcquireSpinLock(&DriverExtension->DeviceListLock, &OldIrql);
RemoveEntryList(&DeviceExtension->ListEntry);
KeReleaseSpinLock(&DriverExtension->DeviceListLock, OldIrql);
IoDetachDevice(DeviceExtension->LowerDevice);
IoDeleteDevice(DeviceObject);
}
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: /* 0x00 */
{
TRACE_(I8042PRT, "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) 0x07 */
{
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case RemovalRelations:
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
default:
ERR_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
return ForwardIrpAndForget(DeviceObject, Irp);
}
break;
}
case IRP_MN_QUERY_CAPABILITIES: /* (optional) 0x09 */
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0x0d */
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case IRP_MN_QUERY_PNP_DEVICE_STATE: /* (optional) 0x14 */
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case IRP_MN_QUERY_REMOVE_DEVICE:
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case IRP_MN_CANCEL_REMOVE_DEVICE:
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_CANCEL_REMOVE_DEVICE\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
case IRP_MN_REMOVE_DEVICE:
{
TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
Status = ForwardIrpAndForget(DeviceObject, Irp);
i8042RemoveDevice(DeviceObject);
return Status;
}
default:
{
ERR_(I8042PRT, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

View file

@ -0,0 +1,140 @@
/*
* 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-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ****************************************************************/
#include "i8042prt.h"
#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 1 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)))
{
WARN_(I8042PRT, "Ps2pp packet fails sanity checks\n");
return;
}
/* Now get the packet type */
PktType = ((DeviceExtension->MouseLogiBuffer[0] & 0x30) >> 2) |
((DeviceExtension->MouseLogiBuffer[1] & 0x30) >> 4);
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);
DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext);
return;
default:
/* These are for things that would probably
* be handled by logitechs own driver.
*/
return;
}
default:
WARN_(I8042PRT, "Unexpected input state for ps2pp!\n");
}
}

View file

@ -0,0 +1,224 @@
/*
* 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-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#include <debug.h>
/* FUNCTIONS *****************************************************************/
VOID
i8042Flush(
IN PPORT_DEVICE_EXTENSION DeviceExtension)
{
UCHAR Ignore;
/* Flush output buffer */
while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_OBF /* | MOU_OBF*/, &Ignore))) {
KeStallExecutionProcessor(50);
TRACE_(I8042PRT, "Output data flushed\n");
}
/* Flush input buffer */
while (NT_SUCCESS(i8042ReadData(DeviceExtension, KBD_IBF, &Ignore))) {
KeStallExecutionProcessor(50);
TRACE_(I8042PRT, "Input data flushed\n");
}
}
BOOLEAN
i8042IsrWritePort(
IN PPORT_DEVICE_EXTENSION DeviceExtension,
IN UCHAR Value,
IN UCHAR SelectCmd OPTIONAL)
{
if (SelectCmd)
if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, SelectCmd))
return FALSE;
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);
INFO_(I8042PRT, "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;
UNREFERENCED_PARAMETER(WaitForAck);
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))
{
WARN_(I8042PRT, "Failed to write Port\n");
return STATUS_IO_TIMEOUT;
}
if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value))
{
WARN_(I8042PRT, "Failed to write Value\n");
return STATUS_IO_TIMEOUT;
}
if (WaitForAck)
{
Status = i8042ReadDataWait(DeviceExtension, &Ack);
if (!NT_SUCCESS(Status))
{
WARN_(I8042PRT, "Failed to read Ack\n");
return Status;
}
if (Ack == KBD_ACK)
return STATUS_SUCCESS;
else if (Ack == KBD_RESEND)
INFO_(I8042PRT, "i8042 asks for a data resend\n");
}
else
{
return STATUS_SUCCESS;
}
TRACE_(I8042PRT, "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 Counter;
ASSERT(addr);
ASSERT(DeviceExtension->ControlPort != NULL);
Counter = DeviceExtension->Settings.PollingIterations;
while ((KBD_IBF & READ_PORT_UCHAR(DeviceExtension->ControlPort)) &&
(Counter--))
{
KeStallExecutionProcessor(50);
}
if (Counter)
{
WRITE_PORT_UCHAR(addr, data);
INFO_(I8042PRT, "Sent 0x%x to port %p\n", data, addr);
return TRUE;
}
return FALSE;
}

View file

@ -0,0 +1,233 @@
/*
* 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-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "i8042prt.h"
#include <debug.h>
/* FUNCTIONS *****************************************************************/
NTSTATUS
ReadRegistryEntries(
IN PUNICODE_STRING RegistryPath,
OUT PI8042_SETTINGS Settings)
{
RTL_QUERY_REGISTRY_TABLE Parameters[17];
NTSTATUS Status;
ULONG DefaultKeyboardDataQueueSize = 0x64;
PCWSTR DefaultKeyboardDeviceBaseName = L"KeyboardPort";
ULONG DefaultMouseDataQueueSize = 0x64;
ULONG DefaultMouseResolution = 3;
ULONG DefaultMouseSynchIn100ns = 20000000;
ULONG DefaultNumberOfButtons = 2;
PCWSTR DefaultPointerDeviceBaseName = 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.
*/
#if DBG
DefaultCrashOnCtrlScroll = 1;
#else
DefaultCrashOnCtrlScroll = 0;
#endif
RtlZeroMemory(Parameters, sizeof(Parameters));
Parameters[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
Parameters[0].Name = L"Parameters";
Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[1].Name = L"KeyboardDataQueueSize";
Parameters[1].EntryContext = &Settings->KeyboardDataQueueSize;
Parameters[1].DefaultType = REG_DWORD;
Parameters[1].DefaultData = &DefaultKeyboardDataQueueSize;
Parameters[1].DefaultLength = sizeof(ULONG);
Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[2].Name = L"KeyboardDeviceBaseName";
Parameters[2].EntryContext = &Settings->KeyboardDeviceBaseName;
Parameters[2].DefaultType = REG_SZ;
Parameters[2].DefaultData = (PVOID)DefaultKeyboardDeviceBaseName;
Parameters[2].DefaultLength = 0;
Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[3].Name = L"MouseDataQueueSize";
Parameters[3].EntryContext = &Settings->MouseDataQueueSize;
Parameters[3].DefaultType = REG_DWORD;
Parameters[3].DefaultData = &DefaultMouseDataQueueSize;
Parameters[3].DefaultLength = sizeof(ULONG);
Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[4].Name = L"MouseResolution";
Parameters[4].EntryContext = &Settings->MouseResolution;
Parameters[4].DefaultType = REG_DWORD;
Parameters[4].DefaultData = &DefaultMouseResolution;
Parameters[4].DefaultLength = sizeof(ULONG);
Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[5].Name = L"MouseSynchIn100ns";
Parameters[5].EntryContext = &Settings->MouseSynchIn100ns;
Parameters[5].DefaultType = REG_DWORD;
Parameters[5].DefaultData = &DefaultMouseSynchIn100ns;
Parameters[5].DefaultLength = sizeof(ULONG);
Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[6].Name = L"NumberOfButtons";
Parameters[6].EntryContext = &Settings->NumberOfButtons;
Parameters[6].DefaultType = REG_DWORD;
Parameters[6].DefaultData = &DefaultNumberOfButtons;
Parameters[6].DefaultLength = sizeof(ULONG);
Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[7].Name = L"PointerDeviceBaseName";
Parameters[7].EntryContext = &Settings->PointerDeviceBaseName;
Parameters[7].DefaultType = REG_SZ;
Parameters[7].DefaultData = (PVOID)DefaultPointerDeviceBaseName;
Parameters[7].DefaultLength = 0;
Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[8].Name = L"PollStatusIterations";
Parameters[8].EntryContext = &Settings->PollStatusIterations;
Parameters[8].DefaultType = REG_DWORD;
Parameters[8].DefaultData = &DefaultPollStatusIterations;
Parameters[8].DefaultLength = sizeof(ULONG);
Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[9].Name = L"OverrideKeyboardType";
Parameters[9].EntryContext = &Settings->OverrideKeyboardType;
Parameters[9].DefaultType = REG_DWORD;
Parameters[9].DefaultData = &DefaultOverrideKeyboardType;
Parameters[9].DefaultLength = sizeof(ULONG);
Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[10].Name = L"OverrideKeyboardSubtype";
Parameters[10].EntryContext = &Settings->OverrideKeyboardSubtype;
Parameters[10].DefaultType = REG_DWORD;
Parameters[10].DefaultData = &DefaultOverrideKeyboardSubtype;
Parameters[10].DefaultLength = sizeof(ULONG);
Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[11].Name = L"PollingIterations";
Parameters[11].EntryContext = &Settings->PollingIterations;
Parameters[11].DefaultType = REG_DWORD;
Parameters[11].DefaultData = &DefaultPollingIterations;
Parameters[11].DefaultLength = sizeof(ULONG);
Parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[12].Name = L"PollingIterationsMaximum";
Parameters[12].EntryContext = &Settings->PollingIterationsMaximum;
Parameters[12].DefaultType = REG_DWORD;
Parameters[12].DefaultData = &DefaultPollingIterationsMaximum;
Parameters[12].DefaultLength = sizeof(ULONG);
Parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[13].Name = L"ResendIterations";
Parameters[13].EntryContext = &Settings->ResendIterations;
Parameters[13].DefaultType = REG_DWORD;
Parameters[13].DefaultData = &DefaultResendIterations;
Parameters[13].DefaultLength = sizeof(ULONG);
Parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[14].Name = L"SampleRate";
Parameters[14].EntryContext = &Settings->SampleRate;
Parameters[14].DefaultType = REG_DWORD;
Parameters[14].DefaultData = &DefaultSampleRate;
Parameters[14].DefaultLength = sizeof(ULONG);
Parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
Parameters[15].Name = L"CrashOnCtrlScroll";
Parameters[15].EntryContext = &Settings->CrashOnCtrlScroll;
Parameters[15].DefaultType = REG_DWORD;
Parameters[15].DefaultData = &DefaultCrashOnCtrlScroll;
Parameters[15].DefaultLength = sizeof(ULONG);
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
RegistryPath->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;
if (!RtlCreateUnicodeString(&Settings->KeyboardDeviceBaseName, DefaultKeyboardDeviceBaseName)
|| !RtlCreateUnicodeString(&Settings->PointerDeviceBaseName, DefaultPointerDeviceBaseName))
{
WARN_(I8042PRT, "RtlCreateUnicodeString() failed\n");
Status = STATUS_NO_MEMORY;
}
else
{
Status = STATUS_SUCCESS;
}
}
if (NT_SUCCESS(Status))
{
INFO_(I8042PRT, "KeyboardDataQueueSize : 0x%lx\n", Settings->KeyboardDataQueueSize);
INFO_(I8042PRT, "KeyboardDeviceBaseName : %wZ\n", &Settings->KeyboardDeviceBaseName);
INFO_(I8042PRT, "MouseDataQueueSize : 0x%lx\n", Settings->MouseDataQueueSize);
INFO_(I8042PRT, "MouseResolution : 0x%lx\n", Settings->MouseResolution);
INFO_(I8042PRT, "MouseSynchIn100ns : %lu\n", Settings->MouseSynchIn100ns);
INFO_(I8042PRT, "NumberOfButtons : 0x%lx\n", Settings->NumberOfButtons);
INFO_(I8042PRT, "PointerDeviceBaseName : %wZ\n", &Settings->PointerDeviceBaseName);
INFO_(I8042PRT, "PollStatusIterations : 0x%lx\n", Settings->PollStatusIterations);
INFO_(I8042PRT, "OverrideKeyboardType : 0x%lx\n", Settings->OverrideKeyboardType);
INFO_(I8042PRT, "OverrideKeyboardSubtype : 0x%lx\n", Settings->OverrideKeyboardSubtype);
INFO_(I8042PRT, "PollingIterations : 0x%lx\n", Settings->PollingIterations);
INFO_(I8042PRT, "PollingIterationsMaximum : %lu\n", Settings->PollingIterationsMaximum);
INFO_(I8042PRT, "ResendIterations : 0x%lx\n", Settings->ResendIterations);
INFO_(I8042PRT, "SampleRate : %lu\n", Settings->SampleRate);
}
return Status;
}

View file

@ -0,0 +1,17 @@
list(APPEND SOURCE
kbdclass.c
misc.c
kbdclass.h)
add_library(kbdclass SHARED
${SOURCE}
guid.c
kbdclass.rc)
set_module_type(kbdclass kernelmodedriver)
add_pch(kbdclass kbdclass.h SOURCE)
target_link_libraries(kbdclass ${PSEH_LIB})
add_importlibs(kbdclass ntoskrnl hal)
add_cd_file(TARGET kbdclass DESTINATION reactos/system32/drivers NO_CAB FOR all)
add_registry_inf(kbdclass_reg.inf)

View file

@ -0,0 +1,8 @@
/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
#define STDAPICALLTYPE __stdcall
#include <wdm.h>
#include <initguid.h>
#include <kbdmou.h>
/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
#ifndef _KBDCLASS_PCH_
#define _KBDCLASS_PCH_
#include <ntifs.h>
#include <ntddkbd.h>
#define MAX_PATH 260
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLASS_TAG 'CdbK'
#define DPFLTR_CLASS_NAME_ID DPFLTR_KBDCLASS_ID
typedef enum
{
dsStopped,
dsStarted,
dsPaused,
dsRemoved,
dsSurpriseRemoved
} PORT_DEVICE_STATE;
typedef struct _CLASS_DRIVER_EXTENSION
{
UNICODE_STRING RegistryPath;
/* Registry settings */
ULONG ConnectMultiplePorts;
ULONG DataQueueSize;
UNICODE_STRING DeviceBaseName;
PDEVICE_OBJECT MainClassDeviceObject;
} CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION;
typedef struct _COMMON_DEVICE_EXTENSION
{
BOOLEAN IsClassDO;
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
typedef struct _PORT_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
LIST_ENTRY ListEntry;
PDEVICE_OBJECT DeviceObject;
PORT_DEVICE_STATE PnpState;
PDEVICE_OBJECT LowerDevice;
PDEVICE_OBJECT ClassDO;
HANDLE FileHandle;
UNICODE_STRING InterfaceName;
} PORT_DEVICE_EXTENSION, *PPORT_DEVICE_EXTENSION;
typedef struct _CLASS_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
PCLASS_DRIVER_EXTENSION DriverExtension;
LIST_ENTRY ListHead;
KSPIN_LOCK ListSpinLock;
KSPIN_LOCK SpinLock;
PIRP PendingIrp;
SIZE_T InputCount;
PKEYBOARD_INPUT_DATA PortData;
LPCWSTR DeviceName;
} CLASS_DEVICE_EXTENSION, *PCLASS_DEVICE_EXTENSION;
/* misc.c */
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
DRIVER_DISPATCH ForwardIrpAndForget;
NTSTATUS
DuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString);
#endif /* _KBDCLASS_PCH_ */

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Keyboard Device Driver"
#define REACTOS_STR_INTERNAL_NAME "keyboard"
#define REACTOS_STR_ORIGINAL_FILENAME "keyboard.sys"
#include <reactos/version.rc>

View file

@ -0,0 +1,9 @@
; Keyboard class driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Group",0x00000000,"Keyboard Class"
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","ImagePath",0x00020000,"system32\drivers\kbdclass.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\kbdclass\Parameters","ConnectMultiplePorts",0x00010001,1
HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"kbdclass"

View file

@ -0,0 +1,113 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Keyboard class driver
* FILE: drivers/input/kbdclass/misc.c
* PURPOSE: Miscellaneous operations
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
*/
#include "kbdclass.h"
#include <debug.h>
static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
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;
KEVENT Event;
NTSTATUS Status;
ASSERT(!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO);
LowerDevice = ((PPORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
TRACE_(CLASS_NAME, "Calling lower device %p\n", LowerDevice);
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;
ASSERT(!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO);
LowerDevice = ((PPORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}
NTSTATUS
DuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString)
{
if (SourceString == NULL || DestinationString == NULL
|| SourceString->Length > SourceString->MaximumLength
|| (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL)
|| Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
{
return STATUS_INVALID_PARAMETER;
}
if ((SourceString->Length == 0)
&& (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
{
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
}
else
{
USHORT DestMaxLength = SourceString->Length;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestMaxLength += sizeof(UNICODE_NULL);
DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, CLASS_TAG);
if (DestinationString->Buffer == NULL)
return STATUS_NO_MEMORY;
RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = DestMaxLength;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
}
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,17 @@
list(APPEND SOURCE
misc.c
mouclass.c
mouclass.h)
add_library(mouclass SHARED
${SOURCE}
guid.c
mouclass.rc)
set_module_type(mouclass kernelmodedriver)
target_link_libraries(mouclass ${PSEH_LIB})
add_importlibs(mouclass ntoskrnl hal)
add_pch(mouclass mouclass.h SOURCE)
add_cd_file(TARGET mouclass DESTINATION reactos/system32/drivers FOR all)
add_registry_inf(mouclass_reg.inf)

View file

@ -0,0 +1,7 @@
/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
#include <ntdef.h>
#include <initguid.h>
#include <ntddmou.h>
/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */

View file

@ -0,0 +1,113 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Mouse class driver
* FILE: drivers/input/mouclass/misc.c
* PURPOSE: Miscellaneous operations
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
*/
#include "mouclass.h"
#include <debug.h>
static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
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;
KEVENT Event;
NTSTATUS Status;
ASSERT(!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO);
LowerDevice = ((PPORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
TRACE_(CLASS_NAME, "Calling lower device %p\n", LowerDevice);
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;
ASSERT(!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO);
LowerDevice = ((PPORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}
NTSTATUS
DuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString)
{
if (SourceString == NULL || DestinationString == NULL
|| SourceString->Length > SourceString->MaximumLength
|| (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL)
|| Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
{
return STATUS_INVALID_PARAMETER;
}
if ((SourceString->Length == 0)
&& (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
{
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
}
else
{
USHORT DestMaxLength = SourceString->Length;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestMaxLength += sizeof(UNICODE_NULL);
DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, CLASS_TAG);
if (DestinationString->Buffer == NULL)
return STATUS_NO_MEMORY;
RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = DestMaxLength;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
}
return STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
#ifndef _MOUCLASS_PCH_
#define _MOUCLASS_PCH_
#include <ntifs.h>
#include <ntddmou.h>
#define MAX_PATH 260
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLASS_TAG 'CuoM'
#define DPFLTR_CLASS_NAME_ID DPFLTR_MOUCLASS_ID
typedef enum
{
dsStopped,
dsStarted,
dsPaused,
dsRemoved,
dsSurpriseRemoved
} PORT_DEVICE_STATE;
typedef struct _CLASS_DRIVER_EXTENSION
{
UNICODE_STRING RegistryPath;
/* Registry settings */
ULONG ConnectMultiplePorts;
ULONG DataQueueSize;
UNICODE_STRING DeviceBaseName;
PDEVICE_OBJECT MainClassDeviceObject;
} CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION;
typedef struct _COMMON_DEVICE_EXTENSION
{
BOOLEAN IsClassDO;
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
typedef struct _PORT_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
LIST_ENTRY ListEntry;
PDEVICE_OBJECT DeviceObject;
PORT_DEVICE_STATE PnpState;
PDEVICE_OBJECT LowerDevice;
PDEVICE_OBJECT ClassDO;
HANDLE FileHandle;
UNICODE_STRING InterfaceName;
} PORT_DEVICE_EXTENSION, *PPORT_DEVICE_EXTENSION;
typedef struct _CLASS_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
PCLASS_DRIVER_EXTENSION DriverExtension;
LIST_ENTRY ListHead;
KSPIN_LOCK ListSpinLock;
KSPIN_LOCK SpinLock;
PIRP PendingIrp;
SIZE_T InputCount;
PMOUSE_INPUT_DATA PortData;
LPCWSTR DeviceName;
} CLASS_DEVICE_EXTENSION, *PCLASS_DEVICE_EXTENSION;
/* misc.c */
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
DRIVER_DISPATCH ForwardIrpAndForget;
NTSTATUS
DuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString);
#endif /* _MOUCLASS_PCH_ */

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Mouse Class Device Driver"
#define REACTOS_STR_INTERNAL_NAME "mouclass"
#define REACTOS_STR_ORIGINAL_FILENAME "mouclass.sys"
#include <reactos/version.rc>

View file

@ -0,0 +1,9 @@
; Mouse class driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Group",0x00000000,"Pointer Class"
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","ImagePath",0x00020000,"system32\drivers\mouclass.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Start",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\mouclass\Parameters","ConnectMultiplePorts",0x00010001,1
HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"mouclass"

View file

@ -0,0 +1,16 @@
list(APPEND SOURCE
createclose.c
detect.c
fdo.c
internaldevctl.c
misc.c
readmouse.c
sermouse.c
sermouse.h)
add_library(sermouse SHARED ${SOURCE} sermouse.rc)
set_module_type(sermouse kernelmodedriver)
add_pch(sermouse sermouse.h SOURCE)
add_importlibs(sermouse ntoskrnl hal)
add_cd_file(TARGET sermouse DESTINATION reactos/system32/drivers FOR all)

View file

@ -0,0 +1,51 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/createclose.c
* PURPOSE: IRP_MJ_CREATE and IRP_MJ_CLOSE operations
* PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <debug.h>
NTSTATUS NTAPI
SermouseCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
TRACE_(SERMOUSE, "IRP_MJ_CREATE\n");
ASSERT(((PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->PnpState == dsStarted);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
SermouseClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
TRACE_(SERMOUSE, "IRP_MJ_CLOSE\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
SermouseCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
TRACE_(SERMOUSE, "IRP_MJ_CLEANUP\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,247 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/detect.c
* PURPOSE: Detect serial mouse type
* PROGRAMMERS: Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Filip Navara (xnavara@volny.cz)
Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <ntifs.h>
#include <debug.h>
/* Most of this file is ripped from reactos/drivers/bus/serenum/detect.c */
static NTSTATUS
DeviceIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG CtlCode,
IN PVOID InputBuffer OPTIONAL,
IN SIZE_T InputBufferSize,
IN OUT PVOID OutputBuffer OPTIONAL,
IN OUT PSIZE_T OutputBufferSize)
{
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
KeInitializeEvent (&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(CtlCode,
DeviceObject,
InputBuffer,
(ULONG)InputBufferSize,
OutputBuffer,
(OutputBufferSize) ? (ULONG)*OutputBufferSize : 0,
FALSE,
&Event,
&IoStatus);
if (Irp == NULL)
{
WARN_(SERMOUSE, "IoBuildDeviceIoControlRequest() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
INFO_(SERMOUSE, "Operation pending\n");
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
if (OutputBufferSize)
{
*OutputBufferSize = (SIZE_T)IoStatus.Information;
}
return Status;
}
static NTSTATUS
ReadBytes(
IN PDEVICE_OBJECT LowerDevice,
OUT PUCHAR Buffer,
IN ULONG BufferSize,
OUT PULONG_PTR FilledBytes)
{
PIRP Irp;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
LARGE_INTEGER zero;
NTSTATUS Status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
zero.QuadPart = 0;
Irp = IoBuildSynchronousFsdRequest(
IRP_MJ_READ,
LowerDevice,
Buffer, BufferSize,
&zero,
&event,
&ioStatus);
if (!Irp)
return FALSE;
Status = IoCallDriver(LowerDevice, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
Status = ioStatus.Status;
}
INFO_(SERMOUSE, "Bytes received: %lu/%lu\n",
ioStatus.Information, BufferSize);
*FilledBytes = ioStatus.Information;
return Status;
}
static NTSTATUS
Wait(
IN ULONG milliseconds)
{
KTIMER Timer;
LARGE_INTEGER DueTime;
DueTime.QuadPart = milliseconds * -10;
KeInitializeTimer(&Timer);
KeSetTimer(&Timer, DueTime, NULL);
return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
}
SERMOUSE_MOUSE_TYPE
SermouseDetectLegacyDevice(
IN PDEVICE_OBJECT LowerDevice)
{
HANDLE Handle;
ULONG Fcr, Mcr;
ULONG BaudRate;
ULONG Command;
SERIAL_TIMEOUTS Timeouts;
SERIAL_LINE_CONTROL LCR;
ULONG_PTR i, Count = 0;
UCHAR Buffer[16];
SERMOUSE_MOUSE_TYPE MouseType = mtNone;
NTSTATUS Status;
TRACE_(SERMOUSE, "SermouseDetectLegacyDevice(LowerDevice %p)\n", LowerDevice);
RtlZeroMemory(Buffer, sizeof(Buffer));
/* Open port */
Status = ObOpenObjectByPointer(
LowerDevice,
OBJ_KERNEL_HANDLE,
NULL,
0,
NULL,
KernelMode,
&Handle);
if (!NT_SUCCESS(Status)) return mtNone;
/* Reset UART */
TRACE_(SERMOUSE, "Reset UART\n");
Mcr = 0; /* MCR: DTR/RTS/OUT2 off */
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
&Mcr, sizeof(Mcr), NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Set communications parameters */
TRACE_(SERMOUSE, "Set communications parameters\n");
/* DLAB off */
Fcr = 0;
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
&Fcr, sizeof(Fcr), NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Set serial port speed */
BaudRate = 1200;
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
&BaudRate, sizeof(BaudRate), NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Set LCR */
LCR.WordLength = 7;
LCR.Parity = NO_PARITY;
LCR.StopBits = STOP_BITS_2;
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
&LCR, sizeof(LCR), NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Flush receive buffer */
TRACE_(SERMOUSE, "Flush receive buffer\n");
Command = SERIAL_PURGE_RXCLEAR;
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
&Command, sizeof(Command), NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Wait 100 ms */
Wait(100);
/* Enable DTR/RTS */
TRACE_(SERMOUSE, "Enable DTR/RTS\n");
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
NULL, 0, NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Set timeout to 500 microseconds */
TRACE_(SERMOUSE, "Set timeout to 500 microseconds\n");
Timeouts.ReadIntervalTimeout = 100;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutConstant = 500;
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts, sizeof(Timeouts), NULL, NULL);
if (!NT_SUCCESS(Status)) goto ByeBye;
/* Fill the read buffer */
TRACE_(SERMOUSE, "Fill the read buffer\n");
Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), &Count);
if (!NT_SUCCESS(Status)) goto ByeBye;
for (i = 0; i < Count; i++)
{
if (Buffer[i] == 'B')
{
/* Sign for Microsoft Ballpoint */
ERR_(SERMOUSE, "Microsoft Ballpoint device detected. THIS DEVICE IS NOT YET SUPPORTED");
MouseType = mtNone;
goto ByeBye;
}
else if (Buffer[i] == 'M')
{
/* Sign for Microsoft Mouse protocol followed by button specifier */
if (i == sizeof(Buffer) - 1)
{
/* Overflow Error */
goto ByeBye;
}
switch (Buffer[i + 1])
{
case '3':
INFO_(SERMOUSE, "Microsoft Mouse with 3-buttons detected\n");
MouseType = mtLogitech;
break;
case 'Z':
INFO_(SERMOUSE, "Microsoft Wheel Mouse detected\n");
MouseType = mtWheelZ;
break;
default:
INFO_(SERMOUSE, "Microsoft Mouse with 2-buttons detected\n");
MouseType = mtMicrosoft;
break;
}
goto ByeBye;
}
}
ByeBye:
/* Close port */
if (Handle)
ZwClose(Handle);
return MouseType;
}

View file

@ -0,0 +1,225 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/fdo.c
* PURPOSE: IRP_MJ_PNP operations for FDOs
* PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <debug.h>
NTSTATUS NTAPI
SermouseAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo)
{
PSERMOUSE_DRIVER_EXTENSION DriverExtension;
PDEVICE_OBJECT Fdo;
PSERMOUSE_DEVICE_EXTENSION DeviceExtension = NULL;
NTSTATUS Status;
TRACE_(SERMOUSE, "SermouseAddDevice called. Pdo = 0x%p\n", Pdo);
if (Pdo == NULL)
return STATUS_SUCCESS;
/* Create new device object */
DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
Status = IoCreateDevice(
DriverObject,
sizeof(SERMOUSE_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_SERIAL_MOUSE_PORT,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&Fdo);
if (!NT_SUCCESS(Status))
{
WARN_(SERMOUSE, "IoCreateDevice() failed with status 0x%08lx\n", Status);
goto cleanup;
}
DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)Fdo->DeviceExtension;
RtlZeroMemory(DeviceExtension, sizeof(SERMOUSE_DEVICE_EXTENSION));
DeviceExtension->MouseType = mtNone;
DeviceExtension->PnpState = dsStopped;
DeviceExtension->DriverExtension = DriverExtension;
KeInitializeEvent(&DeviceExtension->StopWorkerThreadEvent, NotificationEvent, FALSE);
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
if (!NT_SUCCESS(Status))
{
WARN_(SERMOUSE, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
goto cleanup;
}
if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
Fdo->Flags |= DO_POWER_PAGABLE;
if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
Fdo->Flags |= DO_BUFFERED_IO;
if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
Fdo->Flags |= DO_DIRECT_IO;
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
cleanup:
if (DeviceExtension)
{
if (DeviceExtension->LowerDevice)
IoDetachDevice(DeviceExtension->LowerDevice);
}
if (Fdo)
{
IoDeleteDevice(Fdo);
}
return Status;
}
NTSTATUS NTAPI
SermouseStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PSERMOUSE_DEVICE_EXTENSION DeviceExtension;
SERMOUSE_MOUSE_TYPE MouseType;
NTSTATUS Status;
DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->PnpState == dsStopped);
ASSERT(DeviceExtension->LowerDevice);
MouseType = SermouseDetectLegacyDevice(DeviceExtension->LowerDevice);
if (MouseType == mtNone)
{
WARN_(SERMOUSE, "No mouse connected to Fdo %p\n",
DeviceExtension->LowerDevice);
return STATUS_DEVICE_NOT_CONNECTED;
}
switch (MouseType)
{
case mtMicrosoft:
DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
DeviceExtension->AttributesInformation.NumberOfButtons = 2;
break;
case mtLogitech:
DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
DeviceExtension->AttributesInformation.NumberOfButtons = 3;
break;
case mtWheelZ:
DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE;
DeviceExtension->AttributesInformation.NumberOfButtons = 3;
break;
default:
WARN_(SERMOUSE, "Unknown mouse type 0x%lx\n", MouseType);
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
if (DeviceExtension->DriverExtension->NumberOfButtons != 0)
/* Override the number of buttons */
DeviceExtension->AttributesInformation.NumberOfButtons = DeviceExtension->DriverExtension->NumberOfButtons;
DeviceExtension->AttributesInformation.SampleRate = 1200 / 8;
DeviceExtension->AttributesInformation.InputDataQueueLength = 1;
DeviceExtension->MouseType = MouseType;
DeviceExtension->PnpState = dsStarted;
/* Start read loop */
Status = PsCreateSystemThread(
&DeviceExtension->WorkerThreadHandle,
(ACCESS_MASK)0L,
NULL,
NULL,
NULL,
SermouseDeviceWorker,
DeviceObject);
return Status;
}
NTSTATUS NTAPI
SermousePnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
ULONG MinorFunction;
PIO_STACK_LOCATION Stack;
ULONG_PTR Information = 0;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
MinorFunction = Stack->MinorFunction;
Information = Irp->IoStatus.Information;
switch (MinorFunction)
{
/* FIXME: do all these minor functions
IRP_MN_QUERY_REMOVE_DEVICE 0x1
IRP_MN_REMOVE_DEVICE 0x2
IRP_MN_CANCEL_REMOVE_DEVICE 0x3
IRP_MN_STOP_DEVICE 0x4
IRP_MN_QUERY_STOP_DEVICE 0x5
IRP_MN_CANCEL_STOP_DEVICE 0x6
IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
IRP_MN_QUERY_INTERFACE (optional) 0x8
IRP_MN_QUERY_CAPABILITIES (optional) 0x9
IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional or required) 0xd
IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
IRP_MN_SURPRISE_REMOVAL 0x17
*/
case IRP_MN_START_DEVICE: /* 0x0 */
{
TRACE_(SERMOUSE, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
/* Call lower driver */
Status = ForwardIrpAndWait(DeviceObject, Irp);
if (NT_SUCCESS(Status))
Status = SermouseStartDevice(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
{
switch (Stack->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
{
PDEVICE_RELATIONS DeviceRelations = NULL;
TRACE_(SERMOUSE, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
DeviceRelations = ExAllocatePoolWithTag(PagedPool, FIELD_OFFSET(DEVICE_RELATIONS, Objects), SERMOUSE_TAG);
if (!DeviceRelations)
{
WARN_(SERMOUSE, "ExAllocatePoolWithTag() failed\n");
Status = STATUS_NO_MEMORY;
}
else
{
DeviceRelations->Count = 0;
Status = STATUS_SUCCESS;
Information = (ULONG_PTR)DeviceRelations;
}
break;
}
default:
{
TRACE_(SERMOUSE, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
Stack->Parameters.QueryDeviceRelations.Type);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
break;
}
default:
{
TRACE_(SERMOUSE, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

View file

@ -0,0 +1,82 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/fdo.c
* PURPOSE: IRP_MJ_INTERNAL_DEVICE_CONTROL operations
* PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <debug.h>
NTSTATUS NTAPI
SermouseInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PSERMOUSE_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION Stack;
NTSTATUS Status;
DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
Stack = IoGetCurrentIrpStackLocation(Irp);
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_INTERNAL_MOUSE_CONNECT:
{
TRACE_(SERMOUSE, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
DeviceExtension->ConnectData =
*((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
Status = STATUS_SUCCESS;
break;
}
case IOCTL_INTERNAL_MOUSE_DISCONNECT:
{
TRACE_(SERMOUSE, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
/* Ask read loop to end */
KeSetEvent(&DeviceExtension->StopWorkerThreadEvent, (KPRIORITY)0, FALSE);
Status = STATUS_SUCCESS;
break;
}
case IOCTL_MOUSE_QUERY_ATTRIBUTES:
{
TRACE_(SERMOUSE, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
if (Stack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(MOUSE_ATTRIBUTES))
{
*(PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer =
DeviceExtension->AttributesInformation;
Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
}
default:
{
WARN_(SERMOUSE, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
Stack->Parameters.DeviceIoControl.IoControlCode);
ASSERT(FALSE);
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
Irp->IoStatus.Status = Status;
if (Status == STATUS_PENDING)
{
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
}
else
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}

View file

@ -0,0 +1,61 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/fdo.c
* PURPOSE: Miscellaneous operations
* PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <debug.h>
static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
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 = ((PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
KEVENT Event;
NTSTATUS Status;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
TRACE_(SERMOUSE, "Calling lower device %p\n", LowerDevice);
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 = ((PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}

View file

@ -0,0 +1,276 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/fdo.c
* PURPOSE: Read mouse moves and send them to mouclass
* PROGRAMMERS: Copyright Jason Filby (jasonfilby@yahoo.com)
Copyright Filip Navara (xnavara@volny.cz)
Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <debug.h>
static NTSTATUS
SermouseDeviceIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG CtlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferSize,
IN OUT PVOID OutputBuffer OPTIONAL,
IN OUT PULONG OutputBufferSize)
{
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(CtlCode,
DeviceObject,
InputBuffer,
InputBufferSize,
OutputBuffer,
(OutputBufferSize) ? *OutputBufferSize : 0,
FALSE,
&Event,
&IoStatus);
if (Irp == NULL)
{
WARN_(SERMOUSE, "IoBuildDeviceIoControlRequest() failed\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
INFO_(SERMOUSE, "Operation pending\n");
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
if (OutputBufferSize)
{
*OutputBufferSize = (ULONG)IoStatus.Information;
}
return Status;
}
VOID NTAPI
SermouseDeviceWorker(
PVOID Context)
{
PSERMOUSE_DEVICE_EXTENSION DeviceExtension;
PDEVICE_OBJECT LowerDevice;
UCHAR Buffer[PACKET_BUFFER_SIZE];
PIRP Irp;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
PUCHAR PacketBuffer;
UCHAR ReceivedByte;
ULONG Queue;
PMOUSE_INPUT_DATA Input;
ULONG ButtonsDifference;
KIRQL OldIrql;
ULONG i;
ULONG Fcr;
ULONG BaudRate;
SERIAL_TIMEOUTS Timeouts;
SERIAL_LINE_CONTROL LCR;
LARGE_INTEGER Zero;
NTSTATUS Status;
TRACE_(SERMOUSE, "SermouseDeviceWorker() called\n");
DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
LowerDevice = DeviceExtension->LowerDevice;
Zero.QuadPart = 0;
PacketBuffer = DeviceExtension->PacketBuffer;
ASSERT(LowerDevice);
/* Initialize device extension */
DeviceExtension->ActiveQueue = 0;
DeviceExtension->PacketBufferPosition = 0;
DeviceExtension->PreviousButtons = 0;
/* Initialize serial port */
Fcr = 0;
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
&Fcr, sizeof(Fcr), NULL, NULL);
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
/* Set serial port speed */
BaudRate = DeviceExtension->AttributesInformation.SampleRate * 8;
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
&BaudRate, sizeof(BaudRate), NULL, NULL);
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
/* Set LCR */
LCR.WordLength = 7;
LCR.Parity = NO_PARITY;
LCR.StopBits = STOP_BIT_1;
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
&LCR, sizeof(LCR), NULL, NULL);
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
/* Set timeouts */
Timeouts.ReadTotalTimeoutConstant = Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.ReadIntervalTimeout = 100;
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts, sizeof(Timeouts), NULL, NULL);
if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
/* main read loop */
RtlZeroMemory(Buffer, PACKET_BUFFER_SIZE);
while (TRUE)
{
Status = KeWaitForSingleObject(
&DeviceExtension->StopWorkerThreadEvent,
Executive,
KernelMode,
TRUE,
&Zero);
if (Status != STATUS_TIMEOUT)
{
/* we need to stop the worker thread */
KeResetEvent(&DeviceExtension->StopWorkerThreadEvent);
break;
}
KeInitializeEvent(&event, NotificationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(
IRP_MJ_READ,
LowerDevice,
Buffer, PACKET_BUFFER_SIZE,
&Zero,
&event,
&ioStatus);
if (!Irp)
{
/* No memory actually, try later */
INFO_(SERMOUSE, "No memory actually, trying again\n");
KeStallExecutionProcessor(10);
continue;
}
Status = IoCallDriver(LowerDevice, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
Status = ioStatus.Status;
}
if (!NT_SUCCESS(Status))
continue;
/* Read all available data and process */
for (i = 0; i < ioStatus.Information; i++)
{
ReceivedByte = Buffer[i];
INFO_(SERMOUSE, "ReceivedByte 0x%02x\n", ReceivedByte);
/* Synchronize */
if ((ReceivedByte & 0x40) == 0x40)
DeviceExtension->PacketBufferPosition = 0;
PacketBuffer[DeviceExtension->PacketBufferPosition] = ReceivedByte & 0x7f;
DeviceExtension->PacketBufferPosition++;
/* Process packet if complete */
if (DeviceExtension->PacketBufferPosition >= 3)
{
Queue = DeviceExtension->ActiveQueue % 2;
/* Prevent buffer overflow */
if (DeviceExtension->InputDataCount[Queue] == 1)
continue;
Input = &DeviceExtension->MouseInputData[Queue];
if (DeviceExtension->PacketBufferPosition == 3)
{
/* Retrieve change in x and y from packet */
Input->LastX = (signed char)(PacketBuffer[1] | ((PacketBuffer[0] & 0x03) << 6));
Input->LastY = (signed char)(PacketBuffer[2] | ((PacketBuffer[0] & 0x0c) << 4));
/* Determine the current state of the buttons */
Input->RawButtons = (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE) |
((UCHAR)(PacketBuffer[0] & LEFT_BUTTON_MASK) >> LEFT_BUTTON_SHIFT) |
((UCHAR)(PacketBuffer[0] & RIGHT_BUTTON_MASK) >> RIGHT_BUTTON_SHIFT);
}
else if (DeviceExtension->PacketBufferPosition == 4)
{
DeviceExtension->PacketBufferPosition = 0;
/* If middle button state changed than report event */
if (((UCHAR)(PacketBuffer[3] & MIDDLE_BUTTON_MASK) >> MIDDLE_BUTTON_SHIFT) ^
(DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE))
{
Input->RawButtons ^= MOUSE_BUTTON_MIDDLE;
Input->LastX = 0;
Input->LastY = 0;
}
else
{
continue;
}
}
/* Determine ButtonFlags */
Input->ButtonFlags = 0;
ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons;
if (ButtonsDifference != 0)
{
if (ButtonsDifference & MOUSE_BUTTON_LEFT
&& DeviceExtension->AttributesInformation.NumberOfButtons >= 1)
{
if (Input->RawButtons & MOUSE_BUTTON_LEFT)
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
else
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
}
if (ButtonsDifference & MOUSE_BUTTON_RIGHT
&& DeviceExtension->AttributesInformation.NumberOfButtons >= 2)
{
if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
else
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
}
if (ButtonsDifference & MOUSE_BUTTON_MIDDLE
&& DeviceExtension->AttributesInformation.NumberOfButtons >= 3)
{
if (Input->RawButtons & MOUSE_BUTTON_MIDDLE)
Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
else
Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
}
}
/* Send the Input data to the Mouse Class driver */
DeviceExtension->InputDataCount[Queue]++;
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
InterlockedIncrement((PLONG)&DeviceExtension->ActiveQueue);
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ConnectData.ClassService)(
DeviceExtension->ConnectData.ClassDeviceObject,
&DeviceExtension->MouseInputData[Queue],
&DeviceExtension->MouseInputData[Queue] + 1,
&DeviceExtension->InputDataCount[Queue]);
KeLowerIrql(OldIrql);
DeviceExtension->InputDataCount[Queue] = 0;
/* Copy RawButtons to Previous Buttons for Input */
DeviceExtension->PreviousButtons = Input->RawButtons;
}
}
}
PsTerminateSystemThread(STATUS_SUCCESS);
}

View file

@ -0,0 +1,136 @@
/*
* PROJECT: ReactOS Serial mouse driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/input/sermouse/fdo.c
* PURPOSE: Serial mouse driver entry point
* PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "sermouse.h"
#include <debug.h>
static DRIVER_UNLOAD DriverUnload;
static DRIVER_DISPATCH IrpStub;
DRIVER_INITIALIZE DriverEntry;
static VOID NTAPI
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
// nothing to do here yet
}
static NTSTATUS NTAPI
IrpStub(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
ERR_(SERMOUSE, "Irp stub for major function 0x%lx\n",
IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_SUPPORTED;
}
static NTSTATUS
ReadRegistryEntries(
IN PUNICODE_STRING RegistryPath,
IN PSERMOUSE_DRIVER_EXTENSION DriverExtension)
{
UNICODE_STRING ParametersRegistryKey;
RTL_QUERY_REGISTRY_TABLE Parameters[2];
NTSTATUS Status;
ULONG DefaultNumberOfButtons = 2;
ParametersRegistryKey.Length = 0;
ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, SERMOUSE_TAG);
if (!ParametersRegistryKey.Buffer)
{
WARN_(SERMOUSE, "ExAllocatePoolWithTag() failed\n");
return STATUS_NO_MEMORY;
}
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"NumberOfButtons";
Parameters[0].EntryContext = &DriverExtension->NumberOfButtons;
Parameters[0].DefaultType = REG_DWORD;
Parameters[0].DefaultData = &DefaultNumberOfButtons;
Parameters[0].DefaultLength = sizeof(ULONG);
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParametersRegistryKey.Buffer,
Parameters,
NULL,
NULL);
if (NT_SUCCESS(Status))
{
/* Check values */
}
else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
/* Registry path doesn't exist. Set defaults */
DriverExtension->NumberOfButtons = (USHORT)DefaultNumberOfButtons;
Status = STATUS_SUCCESS;
}
ExFreePoolWithTag(ParametersRegistryKey.Buffer, SERMOUSE_TAG);
return Status;
}
/*
* Standard DriverEntry method.
*/
NTSTATUS NTAPI
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
PSERMOUSE_DRIVER_EXTENSION DriverExtension;
ULONG i;
NTSTATUS Status;
Status = IoAllocateDriverObjectExtension(
DriverObject,
DriverObject,
sizeof(SERMOUSE_DRIVER_EXTENSION),
(PVOID*)&DriverExtension);
if (!NT_SUCCESS(Status))
{
WARN_(SERMOUSE, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
return Status;
}
RtlZeroMemory(DriverExtension, sizeof(SERMOUSE_DRIVER_EXTENSION));
Status = ReadRegistryEntries(RegistryPath, DriverExtension);
if (!NT_SUCCESS(Status))
{
WARN_(SERMOUSE, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
return Status;
}
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = SermouseAddDevice;
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = IrpStub;
DriverObject->MajorFunction[IRP_MJ_CREATE] = SermouseCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SermouseClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SermouseCleanup;
//DriverObject->MajorFunction[IRP_MJ_READ] = SermouseRead;
//DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SermouseDeviceControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SermouseInternalDeviceControl;
//DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SermouseQueryInformation;
DriverObject->MajorFunction[IRP_MJ_PNP] = SermousePnp;
//DriverObject->MajorFunction[IRP_MJ_POWER] = SermousePower;
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,117 @@
#ifndef _SERMOUSE_PCH_
#define _SERMOUSE_PCH_
#include <ntddk.h>
#include <ntddser.h>
#include <kbdmou.h>
#define SERMOUSE_TAG 'uoMS'
typedef enum
{
dsStopped,
dsStarted,
dsPaused,
dsRemoved,
dsSurpriseRemoved
} SERMOUSE_DEVICE_STATE;
typedef enum
{
mtNone, /* No Mouse */
mtMicrosoft, /* Microsoft Mouse with 2 buttons */
mtLogitech, /* Logitech Mouse with 3 buttons */
mtWheelZ /* Microsoft Wheel Mouse (aka Z Mouse) */
} SERMOUSE_MOUSE_TYPE;
/* Size for packet buffer used in interrupt routine */
#define PACKET_BUFFER_SIZE 4
/* Hardware byte mask for left button */
#define LEFT_BUTTON_MASK 0x20
/* Hardware to Microsoft specific code byte shift for left button */
#define LEFT_BUTTON_SHIFT 5
/* Hardware byte mask for right button */
#define RIGHT_BUTTON_MASK 0x10
/* Hardware to Microsoft specific code byte shift for right button */
#define RIGHT_BUTTON_SHIFT 3
/* Hardware byte mask for middle button */
#define MIDDLE_BUTTON_MASK 0x20
/* Hardware to Microsoft specific code byte shift for middle button */
#define MIDDLE_BUTTON_SHIFT 3
/* Microsoft byte mask for left button */
#define MOUSE_BUTTON_LEFT 0x01
/* Microsoft byte mask for right button */
#define MOUSE_BUTTON_RIGHT 0x02
/* Microsoft byte mask for middle button */
#define MOUSE_BUTTON_MIDDLE 0x04
typedef struct _SERMOUSE_DRIVER_EXTENSION
{
USHORT NumberOfButtons;
} SERMOUSE_DRIVER_EXTENSION, *PSERMOUSE_DRIVER_EXTENSION;
typedef struct _SERMOUSE_DEVICE_EXTENSION
{
PDEVICE_OBJECT LowerDevice;
SERMOUSE_DEVICE_STATE PnpState;
SERMOUSE_MOUSE_TYPE MouseType;
PSERMOUSE_DRIVER_EXTENSION DriverExtension;
HANDLE WorkerThreadHandle;
KEVENT StopWorkerThreadEvent;
ULONG ActiveQueue;
ULONG InputDataCount[2];
CONNECT_DATA ConnectData;
MOUSE_INPUT_DATA MouseInputData[2];
UCHAR PacketBuffer[PACKET_BUFFER_SIZE];
ULONG PacketBufferPosition;
ULONG PreviousButtons;
MOUSE_ATTRIBUTES AttributesInformation;
} SERMOUSE_DEVICE_EXTENSION, *PSERMOUSE_DEVICE_EXTENSION;
/************************************ createclose.c */
DRIVER_DISPATCH SermouseCreate;
DRIVER_DISPATCH SermouseClose;
DRIVER_DISPATCH SermouseCleanup;
/************************************ detect.c */
SERMOUSE_MOUSE_TYPE
SermouseDetectLegacyDevice(
IN PDEVICE_OBJECT LowerDevice);
/************************************ fdo.c */
DRIVER_ADD_DEVICE SermouseAddDevice;
DRIVER_DISPATCH SermousePnp;
/************************************ internaldevctl.c */
DRIVER_DISPATCH SermouseInternalDeviceControl;
/************************************ misc.c */
NTSTATUS
ForwardIrpAndWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS NTAPI
ForwardIrpAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
/************************************ readmouse.c */
VOID NTAPI
SermouseDeviceWorker(
PVOID Context);
#endif /* _SERMOUSE_PCH_ */

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Serial mouse device driver"
#define REACTOS_STR_INTERNAL_NAME "sermouse"
#define REACTOS_STR_ORIGINAL_FILENAME "sermouse.sys"
#include <reactos/version.rc>

View file

@ -0,0 +1,82 @@
Following information obtained from Tomi Engdahl (then@delta.hut.fi),
http://www.hut.fi/~then/mytexts/mouse.html
Microsoft serial mouse
Serial data parameters:
1200bps, 7 databits, 1 stop-bit
Data packet format:
Data packet is 3 byte packet. It is send to the computer every time mouse
state changes (mouse moves or keys are pressed/released).
D7 D6 D5 D4 D3 D2 D1 D0
1. X 1 LB RB Y7 Y6 X7 X6
2. X 0 X5 X4 X3 X2 X1 X0
3. X 0 Y5 Y4 Y3 Y2 Y1 Y0
Note: The bit marked with X is 0 if the mouse received with 7 databits
and 2 stop bits format. It is also possible to use 8 databits and 1 stop
bit format for receiving. In this case X gets value 1. The safest thing
to get everything working is to use 7 databits and 1 stopbit when
receiving mouse information (and if you are making mouse then send out
7 databits and 2 stop bits).
The byte marked with 1. is send first, then the others. The bit D6 in
the first byte is used for synchronizing the software to mouse packets
if it goes out of sync.
LB is the state of the left button (1 means pressed down)
RB is the state of the right button (1 means pressed down)
X7-X0 movement in X direction since last packet (signed byte)
Y7-Y0 movement in Y direction since last packet (signed byte)
Mouse identification
When DTR line is toggled, mouse should send one data byte containing
letter 'M' (ascii 77).
Logitech serial mouse
Logitech uses the Microsoft serial mouse protocol in their mouses (for
example Logitech Pilot mouse and others). The original protocol supports
only two buttons, but logitech as added third button to some of their
mouse models. To make this possible logitech has made one extension to
the protocol.
I have not seen any documentation about the exact documents, but here is
what I have found out: The information of the third button state is sent
using one extra byte which is send after the normal packet when needed.
Value 32 (dec) is sent every time when the center button is pressed down.
It is also sent every time with the data packet when center button is kept
down and the mouse data packet is sent for other reasons. When center
button is released, the mouse sends the normal data packet followed by
data bythe which has value 0 (dec). As you can see the extra data byte
is sent only when you mess with the center button.
Mouse systems mouse
Serial data parameters:
1200bps, 8 databits, 1 stop-bit
Data packet format:
D7 D6 D5 D4 D3 D2 D1 D0
1. 1 0 0 0 0 LB CB RB
2. X7 X6 X5 X4 X3 X2 X1 X0
3. Y7 Y6 Y5 Y4 Y3 Y4 Y1 Y0
4. X7' X6' X5' X4' X3' X2' X1' X0'
5. Y7' Y6' Y5' Y4' Y3' Y4' Y1' Y0'
LB is left button state (0 = pressed, 1 = released)
CB is center button state (0 = pressed, 1 = released)
RB is right button state (0 = pressed, 1 = released)
X7-X0 movement in X direction since last packet in signed byte
format (-128..+127), positive direction right
Y7-Y0 movement in Y direction since last packet in signed byte
format (-128..+127), positive direction up
X7'-X0' movement in X direction since sending of X7-X0 packet in
signed byte format (-128..+127), positive direction right
Y7'-Y0' movement in Y direction since sending of Y7-Y0 packet in
signed byte format (-128..+127), positive direction up
The last two bytes in the packet (bytes 4 and 5) contains information
about movement data changes which have occured after data bytes 2 and 3
have been sent.