mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 09:23:06 +00:00
Serial mouse driver rewrite by Filip Navara
svn path=/trunk/; revision=5906
This commit is contained in:
parent
d6a2479e6a
commit
eee0086bc9
6 changed files with 698 additions and 464 deletions
|
@ -140,7 +140,7 @@ NTSTATUS ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject)
|
||||||
PDEVICE_OBJECT PortDeviceObject = NULL;
|
PDEVICE_OBJECT PortDeviceObject = NULL;
|
||||||
PFILE_OBJECT FileObject = NULL;
|
PFILE_OBJECT FileObject = NULL;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
UNICODE_STRING PortName = UNICODE_STRING_INITIALIZER(L"\\Device\\Mouse");
|
UNICODE_STRING PortName = UNICODE_STRING_INITIALIZER(L"\\Device\\PointerClass0");
|
||||||
IO_STATUS_BLOCK ioStatus;
|
IO_STATUS_BLOCK ioStatus;
|
||||||
KEVENT event;
|
KEVENT event;
|
||||||
PIRP irp;
|
PIRP irp;
|
||||||
|
|
|
@ -147,6 +147,80 @@ VOID PS2MouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Cont
|
||||||
DeviceExtension->InputDataCount[Queue] = 0;
|
DeviceExtension->InputDataCount[Queue] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Maximum value plus one for \Device\PointerClass* device name */
|
||||||
|
#define POINTER_PORTS_MAXIMUM 8
|
||||||
|
/* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */
|
||||||
|
#define SUFFIX_MAXIMUM_SIZE (1 * sizeof(WCHAR))
|
||||||
|
|
||||||
|
/* This is almost the same routine as in sermouse.c. */
|
||||||
|
STATIC PDEVICE_OBJECT
|
||||||
|
AllocatePointerDevice(PDRIVER_OBJECT DriverObject)
|
||||||
|
{
|
||||||
|
PDEVICE_OBJECT DeviceObject;
|
||||||
|
UNICODE_STRING DeviceName;
|
||||||
|
UNICODE_STRING SuffixString;
|
||||||
|
UNICODE_STRING SymlinkName;
|
||||||
|
PDEVICE_EXTENSION DeviceExtension;
|
||||||
|
ULONG Suffix;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Allocate buffer for full device name */
|
||||||
|
RtlInitUnicodeString(&DeviceName, NULL);
|
||||||
|
DeviceName.MaximumLength = sizeof(DD_MOUSE_DEVICE_NAME_U) + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
|
||||||
|
DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
|
||||||
|
RtlAppendUnicodeToString(&DeviceName, DD_MOUSE_DEVICE_NAME_U);
|
||||||
|
|
||||||
|
/* Allocate buffer for device name suffix */
|
||||||
|
RtlInitUnicodeString(&SuffixString, NULL);
|
||||||
|
SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
|
||||||
|
SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength);
|
||||||
|
|
||||||
|
/* Generate full qualified name with suffix */
|
||||||
|
for (Suffix = 0; Suffix < POINTER_PORTS_MAXIMUM; ++Suffix)
|
||||||
|
{
|
||||||
|
ANSI_STRING DebugString;
|
||||||
|
|
||||||
|
RtlIntegerToUnicodeString(Suffix, 10, &SuffixString);
|
||||||
|
RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
|
||||||
|
// FIXME: this isn't really a serial mouse port driver
|
||||||
|
Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
|
||||||
|
&DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject);
|
||||||
|
RtlUnicodeStringToAnsiString(&DebugString, &DeviceName, TRUE);
|
||||||
|
DbgPrint(DebugString.Buffer);
|
||||||
|
DbgPrint("\n");
|
||||||
|
RtlFreeAnsiString(&DebugString);
|
||||||
|
/* Device successfully created, leave the cyclus */
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
DeviceName.Length -= SuffixString.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExFreePool(DeviceName.Buffer);
|
||||||
|
|
||||||
|
/* Couldn't create device */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ExFreePool(SuffixString.Buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
|
||||||
|
|
||||||
|
/* Create symlink */
|
||||||
|
RtlInitUnicodeString(&SymlinkName, NULL);
|
||||||
|
SymlinkName.MaximumLength = sizeof(L"\\??\\Mouse") + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
|
||||||
|
SymlinkName.Buffer = ExAllocatePool(PagedPool, SymlinkName.MaximumLength);
|
||||||
|
RtlAppendUnicodeToString(&SymlinkName, L"\\??\\Mouse");
|
||||||
|
RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
|
||||||
|
IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
||||||
|
ExFreePool(SuffixString.Buffer);
|
||||||
|
|
||||||
|
DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
|
KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)PS2MouseIsrDpc, DeviceObject);
|
||||||
|
|
||||||
|
return DeviceObject;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
||||||
{
|
{
|
||||||
|
@ -162,28 +236,12 @@ DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = PS2MouseDispatch;
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)PS2MouseDispatch;
|
||||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PS2MouseDispatch;
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)PS2MouseDispatch;
|
||||||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = PS2MouseInternalDeviceControl;
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PS2MouseInternalDeviceControl;
|
||||||
DriverObject->DriverStartIo = PS2MouseStartIo;
|
DriverObject->DriverStartIo = PS2MouseStartIo;
|
||||||
|
|
||||||
RtlInitUnicodeStringFromLiteral(&DeviceName,
|
DeviceObject = AllocatePointerDevice(DriverObject);
|
||||||
L"\\Device\\Mouse"); // FIXME: find correct device name
|
|
||||||
IoCreateDevice(DriverObject,
|
|
||||||
sizeof(DEVICE_EXTENSION),
|
|
||||||
&DeviceName,
|
|
||||||
FILE_DEVICE_SERIAL_MOUSE_PORT, // FIXME: this isn't really a serial mouse port driver
|
|
||||||
0,
|
|
||||||
TRUE,
|
|
||||||
&DeviceObject);
|
|
||||||
DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
|
|
||||||
|
|
||||||
RtlInitUnicodeStringFromLiteral(&SymlinkName,
|
|
||||||
L"\\??\\Mouse"); // FIXME: find correct device name
|
|
||||||
IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
|
||||||
|
|
||||||
DeviceExtension = DeviceObject->DeviceExtension;
|
|
||||||
KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)PS2MouseIsrDpc, DeviceObject);
|
|
||||||
|
|
||||||
mouse_init(DeviceObject);
|
mouse_init(DeviceObject);
|
||||||
|
|
||||||
|
|
|
@ -1,377 +1,250 @@
|
||||||
/*
|
/*
|
||||||
* Mouse driver 0.0.6
|
* Serial Mouse driver 0.0.8
|
||||||
* Written by Jason Filby (jasonfilby@yahoo.com)
|
* Written by Jason Filby (jasonfilby@yahoo.com)
|
||||||
|
* And heavily rewritten by Filip Navara (xnavara@volny.cz)
|
||||||
* For ReactOS (www.reactos.com)
|
* For ReactOS (www.reactos.com)
|
||||||
*
|
*
|
||||||
* Note: The serial.o driver must be loaded before loading this driver
|
* Technical information about mouse protocols can be found
|
||||||
*
|
* in the file sermouse.txt.
|
||||||
* Known Limitations:
|
|
||||||
* Only supports Microsoft mice on COM port 1
|
|
||||||
*
|
|
||||||
* 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 syncronizing 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 origianal 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.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ddk/ntddk.h>
|
#include <ddk/ntddk.h>
|
||||||
#include <ddk/ntddmou.h>
|
#include <ddk/ntddmou.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compile time options
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Support for the IOCTL_MOUSE_QUERY_ATTRIBUTES I/O control code */
|
||||||
|
#define SERMOUSE_QUERYATTRIBUTES_SUPPORT
|
||||||
|
/* Check for mouse on COM1? */
|
||||||
|
#define SERMOUSE_COM1_SUPPORT
|
||||||
|
/* Check for mouse on COM2? */
|
||||||
|
#define SERMOUSE_COM2_SUPPORT
|
||||||
|
/* Create \??\Mouse* symlink for device? */
|
||||||
|
#define SERMOUSE_MOUSESYMLINK_SUPPORT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions
|
||||||
|
*/
|
||||||
|
|
||||||
#define MOUSE_IRQ_COM1 4
|
#define MOUSE_IRQ_COM1 4
|
||||||
#define MOUSE_IRQ_COM2 3
|
#define MOUSE_IRQ_COM2 3
|
||||||
|
|
||||||
#define MOUSE_PORT_COM1 0x3f8
|
#define MOUSE_PORT_COM1 0x3f8
|
||||||
#define MOUSE_PORT_COM2 0x2f8
|
#define MOUSE_PORT_COM2 0x2f8
|
||||||
|
|
||||||
|
/* Maximum value plus one for \Device\PointerClass* device name */
|
||||||
|
#define POINTER_PORTS_MAXIMUM 8
|
||||||
|
/* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */
|
||||||
|
#define SUFFIX_MAXIMUM_SIZE (1 * sizeof(WCHAR))
|
||||||
|
|
||||||
|
/* No Mouse */
|
||||||
|
#define MOUSE_TYPE_NONE 0
|
||||||
|
/* Microsoft Mouse with 2 buttons */
|
||||||
|
#define MOUSE_TYPE_MICROSOFT 1
|
||||||
|
/* Logitech Mouse with 3 buttons */
|
||||||
|
#define MOUSE_TYPE_LOGITECH 2
|
||||||
|
/* Microsoft Wheel Mouse (aka Z Mouse) */
|
||||||
|
#define MOUSE_TYPE_WHEELZ 3
|
||||||
|
/* Mouse Systems Mouse */
|
||||||
|
#define MOUSE_TYPE_MOUSESYSTEMS 4
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structures
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct _DEVICE_EXTENSION {
|
typedef struct _DEVICE_EXTENSION {
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
ULONG ActiveQueue;
|
ULONG ActiveQueue;
|
||||||
ULONG InputDataCount[2];
|
ULONG InputDataCount[2];
|
||||||
MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE];
|
MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE];
|
||||||
CLASS_INFORMATION ClassInformation;
|
CLASS_INFORMATION ClassInformation;
|
||||||
|
|
||||||
PKINTERRUPT MouseInterrupt;
|
PKINTERRUPT MouseInterrupt;
|
||||||
KDPC IsrDpc;
|
KDPC IsrDpc;
|
||||||
|
ULONG MousePort;
|
||||||
|
ULONG MouseType;
|
||||||
|
UCHAR PacketBuffer[PACKET_BUFFER_SIZE];
|
||||||
|
ULONG PacketBufferPosition;
|
||||||
|
ULONG PreviousButtons;
|
||||||
|
#ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
|
||||||
|
MOUSE_ATTRIBUTES AttributesInformation;
|
||||||
|
#endif
|
||||||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
||||||
|
|
||||||
static unsigned int MOUSE_IRQ = MOUSE_IRQ_COM1;
|
/*
|
||||||
static unsigned int MOUSE_COM = MOUSE_PORT_COM1;
|
* Functions
|
||||||
|
*/
|
||||||
|
|
||||||
static unsigned int bytepos=0, coordinate;
|
void ClearMouse(ULONG Port)
|
||||||
static unsigned char mpacket[3];
|
{
|
||||||
static unsigned char mouse_button1, mouse_button2;
|
/* Waits until the mouse calms down but also quits out after a while
|
||||||
|
* in case some destructive user wants to keep moving the mouse
|
||||||
// Previous button state
|
* before we're done */
|
||||||
static ULONG PreviousButtons = 0;
|
unsigned int Restarts = 0, i;
|
||||||
|
for (i = 0; i < 60000; i++)
|
||||||
|
{
|
||||||
|
unsigned Temp = READ_PORT_UCHAR((PUCHAR)Port);
|
||||||
|
if (Temp != 0)
|
||||||
|
{
|
||||||
|
Restarts++;
|
||||||
|
if (Restarts < 300000)
|
||||||
|
i = 0;
|
||||||
|
else
|
||||||
|
i = 60000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOLEAN STDCALL
|
BOOLEAN STDCALL
|
||||||
microsoft_mouse_handler(IN PKINTERRUPT Interrupt, PVOID ServiceContext)
|
SerialMouseInterruptService(IN PKINTERRUPT Interrupt, PVOID ServiceContext)
|
||||||
{
|
{
|
||||||
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
|
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
|
||||||
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||||
|
UCHAR *PacketBuffer = DeviceExtension->PacketBuffer;
|
||||||
|
ULONG MousePort = DeviceExtension->MousePort;
|
||||||
|
UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MousePort + 2);
|
||||||
|
UCHAR RecievedByte;
|
||||||
|
ULONG Queue;
|
||||||
PMOUSE_INPUT_DATA Input;
|
PMOUSE_INPUT_DATA Input;
|
||||||
ULONG Queue, ButtonsDiff;
|
ULONG ButtonsDifference;
|
||||||
unsigned int mbyte;
|
|
||||||
int change_x;
|
|
||||||
int change_y;
|
|
||||||
UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 2);
|
|
||||||
|
|
||||||
/* Is the interrupt for us? */
|
/* Is the interrupt for us? */
|
||||||
if (0 != (InterruptId & 0x01))
|
if ((InterruptId & 0x01) == 0x01)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not a Receive Data Available interrupt? */
|
/* Not a Receive Data Available interrupt? */
|
||||||
if (0 == (InterruptId & 0x04))
|
if ((InterruptId & 0x04) == 0)
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read all available data and process */
|
/* Read all available data and process */
|
||||||
while (0 != (READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 5) & 0x01))
|
while ((READ_PORT_UCHAR((PUCHAR)MousePort + 5) & 0x01) != 0)
|
||||||
{
|
{
|
||||||
mbyte = READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
|
RecievedByte = READ_PORT_UCHAR((PUCHAR)MousePort);
|
||||||
|
|
||||||
/* Synchronize */
|
/* Synchronize */
|
||||||
if (0x40 == (mbyte & 0x40))
|
if ((RecievedByte & 0x40) == 0x40)
|
||||||
bytepos=0;
|
DeviceExtension->PacketBufferPosition = 0;
|
||||||
|
|
||||||
mpacket[bytepos] = (mbyte & 0x7f);
|
PacketBuffer[DeviceExtension->PacketBufferPosition] =
|
||||||
bytepos++;
|
(RecievedByte & 0x7f);
|
||||||
|
++DeviceExtension->PacketBufferPosition;
|
||||||
|
|
||||||
/* Process packet if complete */
|
/* Process packet if complete */
|
||||||
if (3 == bytepos)
|
if (DeviceExtension->PacketBufferPosition >= 3)
|
||||||
{
|
{
|
||||||
/* Set local variables for DeviceObject and DeviceExtension */
|
|
||||||
DeviceObject = (PDEVICE_OBJECT)ServiceContext;
|
|
||||||
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
||||||
Queue = DeviceExtension->ActiveQueue % 2;
|
Queue = DeviceExtension->ActiveQueue % 2;
|
||||||
|
|
||||||
/* Prevent buffer overflow */
|
/* Prevent buffer overflow */
|
||||||
if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
|
if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Input = &DeviceExtension->MouseInputData[Queue][DeviceExtension->InputDataCount[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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Input = &DeviceExtension->MouseInputData[Queue]
|
|
||||||
[DeviceExtension->InputDataCount[Queue]];
|
|
||||||
|
|
||||||
/* Retrieve change in x and y from packet */
|
|
||||||
change_x = - (int)(signed char)((mpacket[0] & 0x03) << 6) - mpacket[1];
|
|
||||||
change_y = - (int)(signed char)((mpacket[0] & 0x0c) << 4) - mpacket[2];
|
|
||||||
|
|
||||||
/* Some mice need this */
|
|
||||||
if (1 == coordinate)
|
|
||||||
{
|
|
||||||
change_x-=128;
|
|
||||||
change_y-=128;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Input->LastX = 2 * change_x;
|
|
||||||
Input->LastY = - 3 * change_y;
|
|
||||||
|
|
||||||
/* Retrieve mouse button status from packet */
|
|
||||||
mouse_button1 = mpacket[0] & 0x20;
|
|
||||||
mouse_button2 = mpacket[0] & 0x10;
|
|
||||||
|
|
||||||
/* Determine the current state of the buttons */
|
|
||||||
Input->RawButtons = mouse_button1 + mouse_button2;
|
|
||||||
|
|
||||||
/* Determine ButtonFlags */
|
/* Determine ButtonFlags */
|
||||||
Input->ButtonFlags = 0;
|
Input->ButtonFlags = 0;
|
||||||
ButtonsDiff = PreviousButtons ^ Input->RawButtons;
|
ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons;
|
||||||
|
|
||||||
if (0 != (ButtonsDiff & 0x20))
|
if (ButtonsDifference != 0)
|
||||||
{
|
{
|
||||||
if (0 != (Input->RawButtons & 0x20))
|
if (ButtonsDifference & MOUSE_BUTTON_LEFT)
|
||||||
{
|
{
|
||||||
Input->ButtonFlags |= MOUSE_BUTTON_1_DOWN;
|
if (Input->RawButtons & MOUSE_BUTTON_LEFT)
|
||||||
}
|
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
|
||||||
else
|
else
|
||||||
{
|
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
|
||||||
Input->ButtonFlags |= MOUSE_BUTTON_1_UP;
|
|
||||||
}
|
}
|
||||||
}
|
if (ButtonsDifference & MOUSE_BUTTON_RIGHT)
|
||||||
|
|
||||||
if (0 != (ButtonsDiff & 0x10))
|
|
||||||
{
|
{
|
||||||
if (0 != (Input->RawButtons & 0x10))
|
if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
|
||||||
{
|
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
|
||||||
Input->ButtonFlags |= MOUSE_BUTTON_2_DOWN;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
|
||||||
|
}
|
||||||
|
if (ButtonsDifference & MOUSE_BUTTON_MIDDLE)
|
||||||
{
|
{
|
||||||
Input->ButtonFlags |= MOUSE_BUTTON_2_UP;
|
if (Input->RawButtons & MOUSE_BUTTON_MIDDLE)
|
||||||
|
Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
|
||||||
|
else
|
||||||
|
Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bytepos=0;
|
|
||||||
|
|
||||||
/* Send the Input data to the Mouse Class driver */
|
/* Send the Input data to the Mouse Class driver */
|
||||||
DeviceExtension->InputDataCount[Queue]++;
|
DeviceExtension->InputDataCount[Queue]++;
|
||||||
KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
|
KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
|
||||||
|
|
||||||
/* Copy RawButtons to Previous Buttons for Input */
|
/* Copy RawButtons to Previous Buttons for Input */
|
||||||
PreviousButtons = Input->RawButtons;
|
DeviceExtension->PreviousButtons = Input->RawButtons;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeMouseHardware(unsigned int mtype)
|
VOID
|
||||||
{
|
SerialMouseInitializeDataQueue(PVOID Context)
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 3, 0x80); /* set DLAB on */
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM, 0x60); /* speed LO byte */
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 1, 0); /* speed HI byte */
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 3, mtype); /* 2=MS Mouse; 3=Mouse systems mouse */
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 1, 0); /* set comm and DLAB to 0 */
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 4, 0x09); /* DR int enable */
|
|
||||||
|
|
||||||
(void) READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5); /* clear error bits */
|
|
||||||
}
|
|
||||||
|
|
||||||
int DetMicrosoft(void)
|
|
||||||
{
|
|
||||||
char tmp, ind;
|
|
||||||
int buttons=0, i, timeout=250;
|
|
||||||
LARGE_INTEGER Timeout;
|
|
||||||
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 0x0b);
|
|
||||||
tmp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
|
|
||||||
|
|
||||||
/* Check the first four bytes for signs that this is an MS mouse */
|
|
||||||
for(i=0; i<4; i++) {
|
|
||||||
while(((READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5) & 1)==0) && (timeout>0))
|
|
||||||
{
|
|
||||||
Timeout.QuadPart = 1;
|
|
||||||
KeDelayExecutionThread (KernelMode, FALSE, &Timeout);
|
|
||||||
timeout--;
|
|
||||||
}
|
|
||||||
ind=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
|
|
||||||
if(ind==0x33) buttons=3;
|
|
||||||
if(ind==0x4d) buttons=2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CheckMouseType(unsigned int mtype)
|
|
||||||
{
|
|
||||||
unsigned int retval=0;
|
|
||||||
|
|
||||||
InitializeMouseHardware(mtype);
|
|
||||||
if(mtype==2) retval=DetMicrosoft();
|
|
||||||
if(mtype==3) {
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 11);
|
|
||||||
retval=3;
|
|
||||||
}
|
|
||||||
WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+1, 1);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearMouse(void)
|
|
||||||
{
|
|
||||||
/* Waits until the mouse calms down but also quits out after a while
|
|
||||||
* in case some destructive user wants to keep moving the mouse
|
|
||||||
* before we're done */
|
|
||||||
|
|
||||||
unsigned int restarts=0, i;
|
|
||||||
for (i=0; i<60000; i++)
|
|
||||||
{
|
|
||||||
unsigned temp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
|
|
||||||
if(temp!=0) {
|
|
||||||
restarts++;
|
|
||||||
if(restarts<300000) {
|
|
||||||
i=0;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
i=60000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN InitializeMouse(PDEVICE_OBJECT DeviceObject)
|
|
||||||
{
|
|
||||||
int mbuttons=0, gotmouse=0;
|
|
||||||
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
|
||||||
ULONG MappedIrq;
|
|
||||||
KIRQL Dirql;
|
|
||||||
KAFFINITY Affinity;
|
|
||||||
|
|
||||||
/* Check for Microsoft mouse (2 buttons) */
|
|
||||||
if(CheckMouseType(2)!=0)
|
|
||||||
{
|
|
||||||
gotmouse=1;
|
|
||||||
DbgPrint("Microsoft Mouse Detected\n");
|
|
||||||
ClearMouse();
|
|
||||||
coordinate=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for Microsoft Systems mouse (3 buttons) */
|
|
||||||
if(gotmouse==0) {
|
|
||||||
if(CheckMouseType(3)!=0)
|
|
||||||
{
|
|
||||||
gotmouse=1;
|
|
||||||
DbgPrint("Mouse Systems Mouse Detected\n");
|
|
||||||
ClearMouse();
|
|
||||||
coordinate=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gotmouse==0) return FALSE;
|
|
||||||
|
|
||||||
DeviceExtension->ActiveQueue = 0;
|
|
||||||
MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity);
|
|
||||||
|
|
||||||
IoConnectInterrupt(&DeviceExtension->MouseInterrupt, microsoft_mouse_handler,
|
|
||||||
DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE,
|
|
||||||
Affinity, FALSE);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID SerialMouseInitializeDataQueue(PVOID Context)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN STDCALL
|
BOOLEAN STDCALL
|
||||||
MouseSynchronizeRoutine(PVOID Context)
|
MouseSynchronizeRoutine(PVOID Context)
|
||||||
{
|
{
|
||||||
PIRP Irp = (PIRP)Context;
|
return TRUE;
|
||||||
PMOUSE_INPUT_DATA rec = (PMOUSE_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
|
|
||||||
PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
|
|
||||||
ULONG NrToRead = stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ((stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA))==NrToRead)
|
|
||||||
{
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID STDCALL
|
VOID STDCALL
|
||||||
|
@ -393,59 +266,68 @@ SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
||||||
{
|
{
|
||||||
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
NTSTATUS status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
|
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
|
||||||
{
|
{
|
||||||
case IOCTL_INTERNAL_MOUSE_CONNECT:
|
case IOCTL_INTERNAL_MOUSE_CONNECT:
|
||||||
|
/* Enable interrupts */
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)(DeviceExtension->MousePort) + 1, 1);
|
||||||
|
ClearMouse(DeviceExtension->MousePort);
|
||||||
|
|
||||||
DeviceExtension->ClassInformation =
|
DeviceExtension->ClassInformation =
|
||||||
*((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
|
*((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
|
||||||
|
|
||||||
/* Reinitialize the port input data queue synchronously */
|
/* Reinitialize the port input data queue synchronously */
|
||||||
KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
|
KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
|
||||||
(PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue, DeviceExtension);
|
(PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue,
|
||||||
|
DeviceExtension);
|
||||||
|
|
||||||
status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
|
||||||
|
case IOCTL_MOUSE_QUERY_ATTRIBUTES:
|
||||||
|
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;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Irp->IoStatus.Status = status;
|
Irp->IoStatus.Status = Status;
|
||||||
if (status == STATUS_PENDING) {
|
if (Status == STATUS_PENDING)
|
||||||
|
{
|
||||||
IoMarkIrpPending(Irp);
|
IoMarkIrpPending(Irp);
|
||||||
IoStartPacket(DeviceObject, Irp, NULL, NULL);
|
IoStartPacket(DeviceObject, Irp, NULL, NULL);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
|
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
static BOOLEAN AlreadyOpened = FALSE;
|
|
||||||
|
|
||||||
switch (stk->MajorFunction)
|
switch (Stack->MajorFunction)
|
||||||
{
|
{
|
||||||
case IRP_MJ_CREATE:
|
case IRP_MJ_CREATE:
|
||||||
if (AlreadyOpened == TRUE)
|
|
||||||
{
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
AlreadyOpened = TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IRP_MJ_CLOSE:
|
case IRP_MJ_CLOSE:
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
|
@ -466,7 +348,8 @@ SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||||
Irp->IoStatus.Information = 0;
|
Irp->IoStatus.Information = 0;
|
||||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||||
}
|
}
|
||||||
return(Status);
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
|
VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
|
||||||
|
@ -485,45 +368,241 @@ VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID C
|
||||||
DeviceExtension->InputDataCount[Queue] = 0;
|
DeviceExtension->InputDataCount[Queue] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
void InitializeSerialPort(ULONG Port, unsigned int LineControl)
|
||||||
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
{
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 3, 0x80); /* set DLAB on */
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port, 0x60); /* speed LO byte */
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0); /* speed HI byte */
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 3, LineControl);
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0); /* set comm and DLAB to 0 */
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x09); /* DR int enable */
|
||||||
|
(void) READ_PORT_UCHAR((PUCHAR)Port + 5); /* clear error bits */
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG DetectMicrosoftMouse(ULONG Port)
|
||||||
|
{
|
||||||
|
CHAR Buffer[4];
|
||||||
|
ULONG i;
|
||||||
|
ULONG TimeOut = 250;
|
||||||
|
UCHAR LineControl;
|
||||||
|
|
||||||
|
/* Shutdown mouse or something like that */
|
||||||
|
LineControl = READ_PORT_UCHAR((PUCHAR)Port + 4);
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 4, (LineControl & ~0x02) | 0x01);
|
||||||
|
KeStallExecutionProcessor(500000);
|
||||||
|
|
||||||
|
/* Clear buffer */
|
||||||
|
while (READ_PORT_UCHAR((PUCHAR)Port + 5) & 0x01)
|
||||||
|
(void)READ_PORT_UCHAR((PUCHAR)Port);
|
||||||
|
|
||||||
|
/* Send modem control with 'Data Terminal Ready', 'Request To Send' and
|
||||||
|
* 'Output Line 2' message. This enables mouse to identify. */
|
||||||
|
WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x0b);
|
||||||
|
/* Wait 10 milliseconds for the mouse getting ready */
|
||||||
|
KeStallExecutionProcessor(10000);
|
||||||
|
|
||||||
|
/* Read first four bytes, which contains Microsoft Mouse signs */
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
while (((READ_PORT_UCHAR((PUCHAR)Port + 5) & 1) == 0) && (TimeOut > 0))
|
||||||
|
{
|
||||||
|
KeStallExecutionProcessor(1000);
|
||||||
|
--TimeOut;
|
||||||
|
if (TimeOut == 0)
|
||||||
|
return MOUSE_TYPE_NONE;
|
||||||
|
}
|
||||||
|
Buffer[i] = READ_PORT_UCHAR((PUCHAR)Port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that four bytes for signs */
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
/* Sign for Microsoft Ballpoint */
|
||||||
|
if (Buffer[i] == 'B')
|
||||||
|
{
|
||||||
|
DbgPrint("Microsoft Ballpoint device detected");
|
||||||
|
DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET");
|
||||||
|
return MOUSE_TYPE_NONE;
|
||||||
|
} else
|
||||||
|
/* Sign for Microsoft Mouse protocol followed by button specifier */
|
||||||
|
if (Buffer[i] == 'M')
|
||||||
|
{
|
||||||
|
if (i == 3)
|
||||||
|
{
|
||||||
|
/* Overflow Error */
|
||||||
|
return MOUSE_TYPE_NONE;
|
||||||
|
}
|
||||||
|
switch (Buffer[i + 1])
|
||||||
|
{
|
||||||
|
case '3':
|
||||||
|
DbgPrint("Microsoft Mouse with 3-buttons detected\n");
|
||||||
|
return MOUSE_TYPE_LOGITECH;
|
||||||
|
case 'Z':
|
||||||
|
DbgPrint("Microsoft Wheel Mouse detected\n");
|
||||||
|
return MOUSE_TYPE_WHEELZ;
|
||||||
|
/* case '2': */
|
||||||
|
default:
|
||||||
|
DbgPrint("Microsoft Mouse with 2-buttons detected\n");
|
||||||
|
return MOUSE_TYPE_MICROSOFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MOUSE_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDEVICE_OBJECT
|
||||||
|
AllocatePointerDevice(PDRIVER_OBJECT DriverObject)
|
||||||
{
|
{
|
||||||
PDEVICE_OBJECT DeviceObject;
|
PDEVICE_OBJECT DeviceObject;
|
||||||
UNICODE_STRING DeviceName;
|
UNICODE_STRING DeviceName;
|
||||||
|
UNICODE_STRING SuffixString;
|
||||||
UNICODE_STRING SymlinkName;
|
UNICODE_STRING SymlinkName;
|
||||||
PDEVICE_EXTENSION DeviceExtension;
|
PDEVICE_EXTENSION DeviceExtension;
|
||||||
|
ULONG Suffix;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseDispatch;
|
/* Allocate buffer for full device name */
|
||||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialMouseDispatch;
|
RtlInitUnicodeString(&DeviceName, NULL);
|
||||||
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SerialMouseInternalDeviceControl;
|
DeviceName.MaximumLength = sizeof(DD_MOUSE_DEVICE_NAME_U) + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
|
||||||
DriverObject->DriverStartIo = SerialMouseStartIo;
|
DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
|
||||||
|
RtlAppendUnicodeToString(&DeviceName, DD_MOUSE_DEVICE_NAME_U);
|
||||||
|
|
||||||
RtlInitUnicodeStringFromLiteral(&DeviceName,
|
/* Allocate buffer for device name suffix */
|
||||||
L"\\Device\\Mouse"); /* FIXME: find correct device name */
|
RtlInitUnicodeString(&SuffixString, NULL);
|
||||||
IoCreateDevice(DriverObject,
|
SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
|
||||||
sizeof(DEVICE_EXTENSION),
|
SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength);
|
||||||
&DeviceName,
|
|
||||||
FILE_DEVICE_SERIAL_MOUSE_PORT,
|
|
||||||
0,
|
|
||||||
TRUE,
|
|
||||||
&DeviceObject);
|
|
||||||
DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
|
|
||||||
|
|
||||||
if(InitializeMouse(DeviceObject) == TRUE)
|
/* Generate full qualified name with suffix */
|
||||||
|
for (Suffix = 0; Suffix < POINTER_PORTS_MAXIMUM; ++Suffix)
|
||||||
{
|
{
|
||||||
DbgPrint("Serial Mouse Driver 0.0.5\n");
|
RtlIntegerToUnicodeString(Suffix, 10, &SuffixString);
|
||||||
} else {
|
RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
|
||||||
IoDeleteDevice(DeviceObject);
|
Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
|
||||||
DbgPrint("Serial mouse not found.\n");
|
&DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject);
|
||||||
return STATUS_UNSUCCESSFUL;
|
/* Device successfully created, leave the cyclus */
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
break;
|
||||||
|
DeviceName.Length -= SuffixString.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlInitUnicodeStringFromLiteral(&SymlinkName,
|
ExFreePool(DeviceName.Buffer);
|
||||||
L"\\??\\Mouse"); /* FIXME: find correct device name */
|
|
||||||
|
/* Couldn't create device */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ExFreePool(SuffixString.Buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
|
||||||
|
|
||||||
|
#ifdef SERMOUSE_MOUSESYMLINK_SUPPORT
|
||||||
|
/* Create symlink */
|
||||||
|
/* FIXME: Why? FiN 20/08/2003 */
|
||||||
|
RtlInitUnicodeString(&SymlinkName, NULL);
|
||||||
|
SymlinkName.MaximumLength = sizeof(L"\\??\\Mouse") + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
|
||||||
|
SymlinkName.Buffer = ExAllocatePool(PagedPool, SymlinkName.MaximumLength);
|
||||||
|
RtlAppendUnicodeToString(&SymlinkName, L"\\??\\Mouse");
|
||||||
|
RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
|
||||||
IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
||||||
|
#endif
|
||||||
|
ExFreePool(SuffixString.Buffer);
|
||||||
|
|
||||||
DeviceExtension = DeviceObject->DeviceExtension;
|
DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
|
KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
|
||||||
|
|
||||||
return(STATUS_SUCCESS);
|
return DeviceObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
InitializeMouse(ULONG Port, ULONG Irq, PDRIVER_OBJECT DriverObject)
|
||||||
|
{
|
||||||
|
PDEVICE_EXTENSION DeviceExtension;
|
||||||
|
PDEVICE_OBJECT DeviceObject;
|
||||||
|
ULONG MappedIrq;
|
||||||
|
KIRQL Dirql;
|
||||||
|
KAFFINITY Affinity;
|
||||||
|
ULONG MouseType;
|
||||||
|
|
||||||
|
/* Try to detect mouse on specified port */
|
||||||
|
InitializeSerialPort(Port, 2);
|
||||||
|
MouseType = DetectMicrosoftMouse(Port);
|
||||||
|
|
||||||
|
/* No mouse, no need to continue */
|
||||||
|
if (MouseType == MOUSE_TYPE_NONE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Allocate new device */
|
||||||
|
DeviceObject = AllocatePointerDevice(DriverObject);
|
||||||
|
if (!DeviceObject)
|
||||||
|
{
|
||||||
|
DbgPrint("Oops, couldn't creat device object.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
DeviceExtension = DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
|
/* Setup device extension structure */
|
||||||
|
DeviceExtension->ActiveQueue = 0;
|
||||||
|
DeviceExtension->MouseType = MouseType;
|
||||||
|
DeviceExtension->MousePort = Port;
|
||||||
|
DeviceExtension->PacketBufferPosition = 0;
|
||||||
|
DeviceExtension->PreviousButtons = 0;
|
||||||
|
#ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
|
||||||
|
switch (MouseType)
|
||||||
|
{
|
||||||
|
case MOUSE_TYPE_MICROSOFT:
|
||||||
|
DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
|
||||||
|
DeviceExtension->AttributesInformation.NumberOfButtons = 2;
|
||||||
|
break;
|
||||||
|
case MOUSE_TYPE_LOGITECH:
|
||||||
|
DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
|
||||||
|
DeviceExtension->AttributesInformation.NumberOfButtons = 3;
|
||||||
|
break;
|
||||||
|
case MOUSE_TYPE_WHEELZ:
|
||||||
|
DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE;
|
||||||
|
DeviceExtension->AttributesInformation.NumberOfButtons = 3;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
DeviceExtension->AttributesInformation.SampleRate = 40;
|
||||||
|
DeviceExtension->AttributesInformation.InputDataQueueLength = MOUSE_BUFFER_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MappedIrq = HalGetInterruptVector(Internal, 0, 0, Irq, &Dirql, &Affinity);
|
||||||
|
|
||||||
|
IoConnectInterrupt(
|
||||||
|
&DeviceExtension->MouseInterrupt, SerialMouseInterruptService,
|
||||||
|
DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE,
|
||||||
|
Affinity, FALSE);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS STDCALL
|
||||||
|
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
||||||
|
{
|
||||||
|
BOOL MouseFound = FALSE;
|
||||||
|
|
||||||
|
DbgPrint("Serial Mouse Driver 0.0.8\n");
|
||||||
|
#ifdef SERMOUSE_COM1_SUPPORT
|
||||||
|
DbgPrint("Trying to find mouse on COM1\n");
|
||||||
|
MouseFound |= InitializeMouse(MOUSE_PORT_COM1, MOUSE_IRQ_COM1, DriverObject);
|
||||||
|
#endif
|
||||||
|
#ifdef SERMOUSE_COM2_SUPPORT
|
||||||
|
DbgPrint("Trying to find mouse on COM2\n");
|
||||||
|
MouseFound |= InitializeMouse(MOUSE_PORT_COM2, MOUSE_IRQ_COM2, DriverObject);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!MouseFound)
|
||||||
|
{
|
||||||
|
DbgPrint("No serial mouse found.\n");
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)SerialMouseDispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)SerialMouseDispatch;
|
||||||
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)SerialMouseInternalDeviceControl;
|
||||||
|
DriverObject->DriverStartIo = SerialMouseStartIo;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", RES_STR_COMPANY_NAME
|
VALUE "CompanyName", RES_STR_COMPANY_NAME
|
||||||
VALUE "FileDescription", "Serial Mouse Device Driver\0"
|
VALUE "FileDescription", "Serial Mouse Device Driver\0"
|
||||||
VALUE "FileVersion", "0.0.1\0"
|
VALUE "FileVersion", "0.0.8\0"
|
||||||
VALUE "InternalName", "sermouse\0"
|
VALUE "InternalName", "sermouse\0"
|
||||||
VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
|
VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
|
||||||
VALUE "OriginalFilename", "sermouse.sys\0"
|
VALUE "OriginalFilename", "sermouse.sys\0"
|
||||||
|
|
82
reactos/drivers/input/sermouse/sermouse.txt
Normal file
82
reactos/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 syncronizing 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 origianal 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.
|
|
@ -1,5 +1,8 @@
|
||||||
/* Mouse definitions common to both mouse class and port drivers */
|
/* Mouse definitions common to both mouse class and port drivers */
|
||||||
|
|
||||||
|
#define DD_MOUSE_DEVICE_NAME "\\Device\\PointerClass"
|
||||||
|
#define DD_MOUSE_DEVICE_NAME_U L"\\Device\\PointerClass"
|
||||||
|
|
||||||
#define IO_MOUSE_INCREMENT 6
|
#define IO_MOUSE_INCREMENT 6
|
||||||
#define MOUSE_BUFFER_SIZE 32
|
#define MOUSE_BUFFER_SIZE 32
|
||||||
|
|
||||||
|
@ -8,6 +11,8 @@
|
||||||
#define IOCTL_INTERNAL_MOUSE_ENABLE CTL_CODE(FILE_DEVICE_MOUSE, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS)
|
#define IOCTL_INTERNAL_MOUSE_ENABLE CTL_CODE(FILE_DEVICE_MOUSE, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
#define IOCTL_INTERNAL_MOUSE_DISABLE CTL_CODE(FILE_DEVICE_MOUSE, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS)
|
#define IOCTL_INTERNAL_MOUSE_DISABLE CTL_CODE(FILE_DEVICE_MOUSE, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||||
|
|
||||||
|
#define IOCTL_MOUSE_QUERY_ATTRIBUTES CTL_CODE(FILE_DEVICE_MOUSE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||||
|
|
||||||
#define MOUSE_BUTTON_1_DOWN 0x0001
|
#define MOUSE_BUTTON_1_DOWN 0x0001
|
||||||
#define MOUSE_BUTTON_1_UP 0x0002
|
#define MOUSE_BUTTON_1_UP 0x0002
|
||||||
#define MOUSE_BUTTON_2_DOWN 0x0004
|
#define MOUSE_BUTTON_2_DOWN 0x0004
|
||||||
|
@ -27,6 +32,16 @@
|
||||||
#define MOUSE_MIDDLE_BUTTON_DOWN MOUSE_BUTTON_3_DOWN
|
#define MOUSE_MIDDLE_BUTTON_DOWN MOUSE_BUTTON_3_DOWN
|
||||||
#define MOUSE_MIDDLE_BUTTON_UP MOUSE_BUTTON_3_UP
|
#define MOUSE_MIDDLE_BUTTON_UP MOUSE_BUTTON_3_UP
|
||||||
|
|
||||||
|
#define MOUSE_SERIAL_HARDWARE 0x0004
|
||||||
|
#define WHEELMOUSE_SERIAL_HARDWARE 0x0040
|
||||||
|
|
||||||
|
typedef struct _MOUSE_ATTRIBUTES {
|
||||||
|
USHORT MouseIdentifier;
|
||||||
|
USHORT NumberOfButtons;
|
||||||
|
USHORT SampleRate;
|
||||||
|
ULONG InputDataQueueLength;
|
||||||
|
} MOUSE_ATTRIBUTES, *PMOUSE_ATTRIBUTES;
|
||||||
|
|
||||||
/* Mouse input data structure */
|
/* Mouse input data structure */
|
||||||
typedef struct _MOUSE_INPUT_DATA {
|
typedef struct _MOUSE_INPUT_DATA {
|
||||||
USHORT UnitId;
|
USHORT UnitId;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue