Serial mouse driver rewrite by Filip Navara

svn path=/trunk/; revision=5906
This commit is contained in:
Gé van Geldorp 2003-08-28 19:44:00 +00:00
parent d6a2479e6a
commit eee0086bc9
6 changed files with 698 additions and 464 deletions

View file

@ -140,7 +140,7 @@ NTSTATUS ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject)
PDEVICE_OBJECT PortDeviceObject = NULL;
PFILE_OBJECT FileObject = NULL;
NTSTATUS status;
UNICODE_STRING PortName = UNICODE_STRING_INITIALIZER(L"\\Device\\Mouse");
UNICODE_STRING PortName = UNICODE_STRING_INITIALIZER(L"\\Device\\PointerClass0");
IO_STATUS_BLOCK ioStatus;
KEVENT event;
PIRP irp;

View file

@ -147,6 +147,80 @@ VOID PS2MouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Cont
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
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
@ -162,28 +236,12 @@ DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
return STATUS_UNSUCCESSFUL;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = PS2MouseDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PS2MouseDispatch;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = PS2MouseInternalDeviceControl;
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)PS2MouseDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)PS2MouseDispatch;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PS2MouseInternalDeviceControl;
DriverObject->DriverStartIo = PS2MouseStartIo;
RtlInitUnicodeStringFromLiteral(&DeviceName,
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);
DeviceObject = AllocatePointerDevice(DriverObject);
mouse_init(DeviceObject);

View file

@ -1,377 +1,250 @@
/*
* Mouse driver 0.0.6
* Serial Mouse driver 0.0.8
* Written by Jason Filby (jasonfilby@yahoo.com)
* And heavily rewritten by Filip Navara (xnavara@volny.cz)
* For ReactOS (www.reactos.com)
*
* Note: The serial.o driver must be loaded before loading this driver
*
* 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.
*
* Technical information about mouse protocols can be found
* in the file sermouse.txt.
*/
#include <ddk/ntddk.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_COM2 3
#define MOUSE_PORT_COM1 0x3f8
#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 {
PDEVICE_OBJECT DeviceObject;
ULONG ActiveQueue;
ULONG InputDataCount[2];
MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE];
CLASS_INFORMATION ClassInformation;
PKINTERRUPT MouseInterrupt;
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;
static unsigned int MOUSE_IRQ = MOUSE_IRQ_COM1;
static unsigned int MOUSE_COM = MOUSE_PORT_COM1;
/*
* Functions
*/
static unsigned int bytepos=0, coordinate;
static unsigned char mpacket[3];
static unsigned char mouse_button1, mouse_button2;
// Previous button state
static ULONG PreviousButtons = 0;
void ClearMouse(ULONG Port)
{
/* 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)Port);
if (Temp != 0)
{
Restarts++;
if (Restarts < 300000)
i = 0;
else
i = 60000;
}
}
}
BOOLEAN STDCALL
microsoft_mouse_handler(IN PKINTERRUPT Interrupt, PVOID ServiceContext)
SerialMouseInterruptService(IN PKINTERRUPT Interrupt, PVOID 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;
ULONG Queue, ButtonsDiff;
unsigned int mbyte;
int change_x;
int change_y;
UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 2);
ULONG ButtonsDifference;
/* Is the interrupt for us? */
if (0 != (InterruptId & 0x01))
if ((InterruptId & 0x01) == 0x01)
{
return FALSE;
}
/* Not a Receive Data Available interrupt? */
if (0 == (InterruptId & 0x04))
if ((InterruptId & 0x04) == 0)
{
return TRUE;
}
/* 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 */
if (0x40 == (mbyte & 0x40))
bytepos=0;
if ((RecievedByte & 0x40) == 0x40)
DeviceExtension->PacketBufferPosition = 0;
mpacket[bytepos] = (mbyte & 0x7f);
bytepos++;
PacketBuffer[DeviceExtension->PacketBufferPosition] =
(RecievedByte & 0x7f);
++DeviceExtension->PacketBufferPosition;
/* 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;
/* Prevent buffer overflow */
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;
}
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 */
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
{
Input->ButtonFlags |= MOUSE_BUTTON_1_UP;
Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
}
}
if (0 != (ButtonsDiff & 0x10))
if (ButtonsDifference & MOUSE_BUTTON_RIGHT)
{
if (0 != (Input->RawButtons & 0x10))
{
Input->ButtonFlags |= MOUSE_BUTTON_2_DOWN;
}
if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
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 */
DeviceExtension->InputDataCount[Queue]++;
KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
/* Copy RawButtons to Previous Buttons for Input */
PreviousButtons = Input->RawButtons;
DeviceExtension->PreviousButtons = Input->RawButtons;
}
}
return TRUE;
}
void InitializeMouseHardware(unsigned int mtype)
{
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)
VOID
SerialMouseInitializeDataQueue(PVOID Context)
{
}
BOOLEAN STDCALL
MouseSynchronizeRoutine(PVOID Context)
{
PIRP Irp = (PIRP)Context;
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);
return TRUE;
}
VOID STDCALL
@ -393,59 +266,68 @@ SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
NTSTATUS Status;
switch (Stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_INTERNAL_MOUSE_CONNECT:
/* Enable interrupts */
WRITE_PORT_UCHAR((PUCHAR)(DeviceExtension->MousePort) + 1, 1);
ClearMouse(DeviceExtension->MousePort);
DeviceExtension->ClassInformation =
*((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
/* Reinitialize the port input data queue synchronously */
KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
(PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue, DeviceExtension);
(PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue,
DeviceExtension);
status = STATUS_SUCCESS;
Status = STATUS_SUCCESS;
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:
status = STATUS_INVALID_DEVICE_REQUEST;
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
Irp->IoStatus.Status = status;
if (status == STATUS_PENDING) {
Irp->IoStatus.Status = Status;
if (Status == STATUS_PENDING)
{
IoMarkIrpPending(Irp);
IoStartPacket(DeviceObject, Irp, NULL, NULL);
} else {
}
else
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
return Status;
}
NTSTATUS STDCALL
SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status;
static BOOLEAN AlreadyOpened = FALSE;
switch (stk->MajorFunction)
switch (Stack->MajorFunction)
{
case IRP_MJ_CREATE:
if (AlreadyOpened == TRUE)
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_SUCCESS;
AlreadyOpened = TRUE;
}
break;
case IRP_MJ_CLOSE:
Status = STATUS_SUCCESS;
break;
@ -466,7 +348,8 @@ SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return(Status);
return Status;
}
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;
}
NTSTATUS STDCALL
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
void InitializeSerialPort(ULONG Port, unsigned int LineControl)
{
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;
UNICODE_STRING DeviceName;
UNICODE_STRING SuffixString;
UNICODE_STRING SymlinkName;
PDEVICE_EXTENSION DeviceExtension;
ULONG Suffix;
NTSTATUS Status;
DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialMouseDispatch;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SerialMouseInternalDeviceControl;
DriverObject->DriverStartIo = SerialMouseStartIo;
/* 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);
RtlInitUnicodeStringFromLiteral(&DeviceName,
L"\\Device\\Mouse"); /* FIXME: find correct device name */
IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_SERIAL_MOUSE_PORT,
0,
TRUE,
&DeviceObject);
DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
/* Allocate buffer for device name suffix */
RtlInitUnicodeString(&SuffixString, NULL);
SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength);
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");
} else {
IoDeleteDevice(DeviceObject);
DbgPrint("Serial mouse not found.\n");
return STATUS_UNSUCCESSFUL;
RtlIntegerToUnicodeString(Suffix, 10, &SuffixString);
RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
&DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject);
/* Device successfully created, leave the cyclus */
if (NT_SUCCESS(Status))
break;
DeviceName.Length -= SuffixString.Length;
}
RtlInitUnicodeStringFromLiteral(&SymlinkName,
L"\\??\\Mouse"); /* FIXME: find correct device name */
ExFreePool(DeviceName.Buffer);
/* 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);
#endif
ExFreePool(SuffixString.Buffer);
DeviceExtension = DeviceObject->DeviceExtension;
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;
}

View file

@ -23,7 +23,7 @@ BEGIN
BEGIN
VALUE "CompanyName", RES_STR_COMPANY_NAME
VALUE "FileDescription", "Serial Mouse Device Driver\0"
VALUE "FileVersion", "0.0.1\0"
VALUE "FileVersion", "0.0.8\0"
VALUE "InternalName", "sermouse\0"
VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
VALUE "OriginalFilename", "sermouse.sys\0"

View file

@ -0,0 +1,82 @@
Following information obtained from Tomi Engdahl (then@delta.hut.fi),
http://www.hut.fi/~then/mytexts/mouse.html
Microsoft serial mouse
Serial data parameters:
1200bps, 7 databits, 1 stop-bit
Data packet format:
Data packet is 3 byte packet. It is send to the computer every time mouse
state changes (mouse moves or keys are pressed/released).
D7 D6 D5 D4 D3 D2 D1 D0
1. X 1 LB RB Y7 Y6 X7 X6
2. X 0 X5 X4 X3 X2 X1 X0
3. X 0 Y5 Y4 Y3 Y2 Y1 Y0
Note: The bit marked with X is 0 if the mouse received with 7 databits
and 2 stop bits format. It is also possible to use 8 databits and 1 stop
bit format for receiving. In this case X gets value 1. The safest thing
to get everything working is to use 7 databits and 1 stopbit when
receiving mouse information (and if you are making mouse then send out
7 databits and 2 stop bits).
The byte marked with 1. is send first, then the others. The bit D6 in
the first byte is used for 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.

View file

@ -1,5 +1,8 @@
/* 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 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_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_UP 0x0002
#define MOUSE_BUTTON_2_DOWN 0x0004
@ -27,6 +32,16 @@
#define MOUSE_MIDDLE_BUTTON_DOWN MOUSE_BUTTON_3_DOWN
#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 */
typedef struct _MOUSE_INPUT_DATA {
USHORT UnitId;