mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 09:21:50 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
5
drivers/input/CMakeLists.txt
Normal file
5
drivers/input/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
add_subdirectory(i8042prt)
|
||||
add_subdirectory(kbdclass)
|
||||
add_subdirectory(mouclass)
|
||||
add_subdirectory(sermouse)
|
23
drivers/input/i8042prt/CMakeLists.txt
Normal file
23
drivers/input/i8042prt/CMakeLists.txt
Normal 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)
|
80
drivers/input/i8042prt/README.txt
Normal file
80
drivers/input/i8042prt/README.txt
Normal 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.
|
57
drivers/input/i8042prt/createclose.c
Normal file
57
drivers/input/i8042prt/createclose.c
Normal 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;
|
||||
}
|
102
drivers/input/i8042prt/dmi.h
Normal file
102
drivers/input/i8042prt/dmi.h
Normal 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;
|
||||
|
7
drivers/input/i8042prt/guid.c
Normal file
7
drivers/input/i8042prt/guid.c
Normal 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 */
|
280
drivers/input/i8042prt/hwhacks.c
Normal file
280
drivers/input/i8042prt/hwhacks.c
Normal 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');
|
||||
}
|
||||
|
566
drivers/input/i8042prt/i8042prt.c
Normal file
566
drivers/input/i8042prt/i8042prt.c
Normal 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;
|
||||
}
|
459
drivers/input/i8042prt/i8042prt.h
Normal file
459
drivers/input/i8042prt/i8042prt.h
Normal 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_ */
|
5
drivers/input/i8042prt/i8042prt.rc
Normal file
5
drivers/input/i8042prt/i8042prt.rc
Normal 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>
|
939
drivers/input/i8042prt/keyboard.c
Normal file
939
drivers/input/i8042prt/keyboard.c
Normal 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;
|
||||
}
|
114
drivers/input/i8042prt/misc.c
Normal file
114
drivers/input/i8042prt/misc.c
Normal 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;
|
||||
}
|
973
drivers/input/i8042prt/mouse.c
Normal file
973
drivers/input/i8042prt/mouse.c
Normal 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;
|
||||
}
|
769
drivers/input/i8042prt/pnp.c
Normal file
769
drivers/input/i8042prt/pnp.c
Normal 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;
|
||||
}
|
140
drivers/input/i8042prt/ps2pp.c
Normal file
140
drivers/input/i8042prt/ps2pp.c
Normal 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");
|
||||
}
|
||||
}
|
224
drivers/input/i8042prt/readwrite.c
Normal file
224
drivers/input/i8042prt/readwrite.c
Normal 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;
|
||||
}
|
233
drivers/input/i8042prt/registry.c
Normal file
233
drivers/input/i8042prt/registry.c
Normal 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;
|
||||
}
|
17
drivers/input/kbdclass/CMakeLists.txt
Normal file
17
drivers/input/kbdclass/CMakeLists.txt
Normal 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)
|
8
drivers/input/kbdclass/guid.c
Normal file
8
drivers/input/kbdclass/guid.c
Normal 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 */
|
1116
drivers/input/kbdclass/kbdclass.c
Normal file
1116
drivers/input/kbdclass/kbdclass.c
Normal file
File diff suppressed because it is too large
Load diff
83
drivers/input/kbdclass/kbdclass.h
Normal file
83
drivers/input/kbdclass/kbdclass.h
Normal 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_ */
|
5
drivers/input/kbdclass/kbdclass.rc
Normal file
5
drivers/input/kbdclass/kbdclass.rc
Normal 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>
|
9
drivers/input/kbdclass/kbdclass_reg.inf
Normal file
9
drivers/input/kbdclass/kbdclass_reg.inf
Normal 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"
|
113
drivers/input/kbdclass/misc.c
Normal file
113
drivers/input/kbdclass/misc.c
Normal 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;
|
||||
}
|
17
drivers/input/mouclass/CMakeLists.txt
Normal file
17
drivers/input/mouclass/CMakeLists.txt
Normal 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)
|
7
drivers/input/mouclass/guid.c
Normal file
7
drivers/input/mouclass/guid.c
Normal 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 */
|
113
drivers/input/mouclass/misc.c
Normal file
113
drivers/input/mouclass/misc.c
Normal 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;
|
||||
}
|
1092
drivers/input/mouclass/mouclass.c
Normal file
1092
drivers/input/mouclass/mouclass.c
Normal file
File diff suppressed because it is too large
Load diff
83
drivers/input/mouclass/mouclass.h
Normal file
83
drivers/input/mouclass/mouclass.h
Normal 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_ */
|
5
drivers/input/mouclass/mouclass.rc
Normal file
5
drivers/input/mouclass/mouclass.rc
Normal 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>
|
9
drivers/input/mouclass/mouclass_reg.inf
Normal file
9
drivers/input/mouclass/mouclass_reg.inf
Normal 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"
|
16
drivers/input/sermouse/CMakeLists.txt
Normal file
16
drivers/input/sermouse/CMakeLists.txt
Normal 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)
|
51
drivers/input/sermouse/createclose.c
Normal file
51
drivers/input/sermouse/createclose.c
Normal 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;
|
||||
}
|
247
drivers/input/sermouse/detect.c
Normal file
247
drivers/input/sermouse/detect.c
Normal 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;
|
||||
}
|
225
drivers/input/sermouse/fdo.c
Normal file
225
drivers/input/sermouse/fdo.c
Normal 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;
|
||||
}
|
82
drivers/input/sermouse/internaldevctl.c
Normal file
82
drivers/input/sermouse/internaldevctl.c
Normal 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;
|
||||
}
|
61
drivers/input/sermouse/misc.c
Normal file
61
drivers/input/sermouse/misc.c
Normal 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);
|
||||
}
|
276
drivers/input/sermouse/readmouse.c
Normal file
276
drivers/input/sermouse/readmouse.c
Normal 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);
|
||||
}
|
136
drivers/input/sermouse/sermouse.c
Normal file
136
drivers/input/sermouse/sermouse.c
Normal 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;
|
||||
}
|
117
drivers/input/sermouse/sermouse.h
Normal file
117
drivers/input/sermouse/sermouse.h
Normal 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_ */
|
5
drivers/input/sermouse/sermouse.rc
Normal file
5
drivers/input/sermouse/sermouse.rc
Normal 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>
|
82
drivers/input/sermouse/sermouse.txt
Normal file
82
drivers/input/sermouse/sermouse.txt
Normal 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.
|
Loading…
Add table
Add a link
Reference in a new issue