3 * Written by Jason Filby (jasonfilby@yahoo.com)
4 * For ReactOS (www.reactos.com)
6 * Note: The serial.o driver must be loaded before loading this driver
9 * Only supports Microsoft mice on COM port 1
11 * Following information obtained from Tomi Engdahl (then@delta.hut.fi),
12 * http://www.hut.fi/~then/mytexts/mouse.html
14 * Microsoft serial mouse
16 * Serial data parameters:
17 * 1200bps, 7 databits, 1 stop-bit
20 * Data packet is 3 byte packet. It is send to the computer every time mouse
21 * state changes (mouse moves or keys are pressed/released).
22 * D7 D6 D5 D4 D3 D2 D1 D0
23 * 1. X 1 LB RB Y7 Y6 X7 X6
24 * 2. X 0 X5 X4 X3 X2 X1 X0
25 * 3. X 0 Y5 Y4 Y3 Y2 Y1 Y0
27 * Note: The bit marked with X is 0 if the mouse received with 7 databits
28 * and 2 stop bits format. It is also possible to use 8 databits and 1 stop
29 * bit format for receiving. In this case X gets value 1. The safest thing
30 * to get everything working is to use 7 databits and 1 stopbit when
31 * receiving mouse information (and if you are making mouse then send out
32 * 7 databits and 2 stop bits).
33 * The byte marked with 1. is send first, then the others. The bit D6 in
34 * the first byte is used for syncronizing the software to mouse packets
35 * if it goes out of sync.
37 * LB is the state of the left button (1 means pressed down)
38 * RB is the state of the right button (1 means pressed down)
39 * X7-X0 movement in X direction since last packet (signed byte)
40 * Y7-Y0 movement in Y direction since last packet (signed byte)
42 * Mouse identification
43 * When DTR line is toggled, mouse should send one data byte containing
44 * letter 'M' (ascii 77).
47 * Logitech serial mouse
49 * Logitech uses the Microsoft serial mouse protocol in their mouses (for
50 * example Logitech Pilot mouse and others). The origianal protocol supports
51 * only two buttons, but logitech as added third button to some of their
52 * mouse models. To make this possible logitech has made one extension to
54 * I have not seen any documentation about the exact documents, but here is
55 * what I have found out: The information of the third button state is sent
56 * using one extra byte which is send after the normal packet when needed.
57 * Value 32 (dec) is sent every time when the center button is pressed down.
58 * It is also sent every time with the data packet when center button is kept
59 * down and the mouse data packet is sent for other reasons. When center
60 * button is released, the mouse sends the normal data packet followed by
61 * data bythe which has value 0 (dec). As you can see the extra data byte
62 * is sent only when you mess with the center button.
67 * Serial data parameters:
68 * 1200bps, 8 databits, 1 stop-bit
71 * D7 D6 D5 D4 D3 D2 D1 D0
72 * 1. 1 0 0 0 0 LB CB RB
73 * 2. X7 X6 X5 X4 X3 X2 X1 X0
74 * 3. Y7 Y6 Y5 Y4 Y3 Y4 Y1 Y0
75 * 4. X7' X6' X5' X4' X3' X2' X1' X0'
76 * 5. Y7' Y6' Y5' Y4' Y3' Y4' Y1' Y0'
78 * LB is left button state (0 = pressed, 1 = released)
79 * CB is center button state (0 = pressed, 1 = released)
80 * RB is right button state (0 = pressed, 1 = released)
81 * X7-X0 movement in X direction since last packet in signed byte
82 * format (-128..+127), positive direction right
83 * Y7-Y0 movement in Y direction since last packet in signed byte
84 * format (-128..+127), positive direction up
85 * X7'-X0' movement in X direction since sending of X7-X0 packet in
86 * signed byte format (-128..+127), positive direction right
87 * Y7'-Y0' movement in Y direction since sending of Y7-Y0 packet in
88 * signed byte format (-128..+127), positive direction up
90 * The last two bytes in the packet (bytes 4 and 5) contains information
91 * about movement data changes which have occured after data bytes 2 and 3
96 #include <ddk/ntddk.h>
97 #include <ddk/ntddmou.h>
99 #define MOUSE_IRQ_COM1 4
100 #define MOUSE_IRQ_COM2 3
102 #define MOUSE_PORT_COM1 0x3f8
103 #define MOUSE_PORT_COM2 0x2f8
105 typedef struct _DEVICE_EXTENSION {
106 PDEVICE_OBJECT DeviceObject;
108 ULONG InputDataCount[2];
109 MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE];
110 CLASS_INFORMATION ClassInformation;
112 PKINTERRUPT MouseInterrupt;
114 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
116 static unsigned int MOUSE_IRQ = MOUSE_IRQ_COM1;
117 static unsigned int MOUSE_COM = MOUSE_PORT_COM1;
119 static unsigned int bytepos=0, coordinate;
120 static unsigned char mpacket[3];
121 static unsigned char mouse_button1, mouse_button2;
123 // Previous button state
124 static ULONG PreviousButtons = 0;
127 microsoft_mouse_handler(IN PKINTERRUPT Interrupt, PVOID ServiceContext)
129 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
130 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
131 PMOUSE_INPUT_DATA Input;
132 ULONG Queue, ButtonsDiff;
136 UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 2);
138 /* Is the interrupt for us? */
139 if (0 != (InterruptId & 0x01))
144 /* Not a Receive Data Available interrupt? */
145 if (0 == (InterruptId & 0x04))
150 /* Read all available data and process */
151 while (0 != (READ_PORT_UCHAR((PUCHAR)MOUSE_COM + 5) & 0x01))
153 mbyte = READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
156 if (0x40 == (mbyte & 0x40))
159 mpacket[bytepos] = (mbyte & 0x7f);
162 /* Process packet if complete */
165 /* Set local variables for DeviceObject and DeviceExtension */
166 DeviceObject = (PDEVICE_OBJECT)ServiceContext;
167 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
168 Queue = DeviceExtension->ActiveQueue % 2;
170 /* Prevent buffer overflow */
171 if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
176 Input = &DeviceExtension->MouseInputData[Queue]
177 [DeviceExtension->InputDataCount[Queue]];
179 /* Retrieve change in x and y from packet */
180 change_x = (int)(signed char)((mpacket[0] & 0x03) << 6) + mpacket[1];
181 change_y = (int)(signed char)((mpacket[0] & 0x0c) << 4) + mpacket[2];
183 /* Some mice need this */
191 /* Change to signed */
194 change_x = change_x - 256;
198 change_y = change_y - 256;
202 Input->LastX = 2 * change_x;
203 Input->LastY = - 3 * change_y;
205 /* Retrieve mouse button status from packet */
206 mouse_button1 = mpacket[0] & 0x20;
207 mouse_button2 = mpacket[0] & 0x10;
209 /* Determine the current state of the buttons */
210 Input->RawButtons = mouse_button1 + mouse_button2;
212 /* Determine ButtonFlags */
213 Input->ButtonFlags = 0;
214 ButtonsDiff = PreviousButtons ^ Input->RawButtons;
216 if (0 != (ButtonsDiff & 0x20))
218 if (0 != (Input->RawButtons & 0x20))
220 Input->ButtonFlags |= MOUSE_BUTTON_1_DOWN;
224 Input->ButtonFlags |= MOUSE_BUTTON_1_UP;
228 if (0 != (ButtonsDiff & 0x10))
230 if (0 != (Input->RawButtons & 0x10))
232 Input->ButtonFlags |= MOUSE_BUTTON_2_DOWN;
236 Input->ButtonFlags |= MOUSE_BUTTON_2_UP;
242 /* Send the Input data to the Mouse Class driver */
243 DeviceExtension->InputDataCount[Queue]++;
244 KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
246 /* Copy RawButtons to Previous Buttons for Input */
247 PreviousButtons = Input->RawButtons;
254 void InitializeMouseHardware(unsigned int mtype)
256 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 3, 0x80); /* set DLAB on */
257 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM, 0x60); /* speed LO byte */
258 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 1, 0); /* speed HI byte */
259 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 3, mtype); /* 2=MS Mouse; 3=Mouse systems mouse */
260 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 1, 0); /* set comm and DLAB to 0 */
261 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM + 4, 0x09); /* DR int enable */
263 (void) READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5); /* clear error bits */
266 int DetMicrosoft(void)
269 int buttons=0, i, timeout=250;
270 LARGE_INTEGER Timeout;
272 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 0x0b);
273 tmp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
275 /* Check the first four bytes for signs that this is an MS mouse */
277 while(((READ_PORT_UCHAR((PUCHAR)MOUSE_COM+5) & 1)==0) && (timeout>0))
279 Timeout.QuadPart = 1;
280 KeDelayExecutionThread (KernelMode, FALSE, &Timeout);
283 ind=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
284 if(ind==0x33) buttons=3;
285 if(ind==0x4d) buttons=2;
291 int CheckMouseType(unsigned int mtype)
293 unsigned int retval=0;
295 InitializeMouseHardware(mtype);
296 if(mtype==2) retval=DetMicrosoft();
298 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+4, 11);
301 WRITE_PORT_UCHAR((PUCHAR)MOUSE_COM+1, 1);
306 void ClearMouse(void)
308 /* Waits until the mouse calms down but also quits out after a while
309 * in case some destructive user wants to keep moving the mouse
310 * before we're done */
312 unsigned int restarts=0, i;
313 for (i=0; i<60000; i++)
315 unsigned temp=READ_PORT_UCHAR((PUCHAR)MOUSE_COM);
318 if(restarts<300000) {
328 BOOLEAN InitializeMouse(PDEVICE_OBJECT DeviceObject)
330 int mbuttons=0, gotmouse=0;
331 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
336 /* Check for Microsoft mouse (2 buttons) */
337 if(CheckMouseType(2)!=0)
340 DbgPrint("Microsoft Mouse Detected\n");
345 /* Check for Microsoft Systems mouse (3 buttons) */
347 if(CheckMouseType(3)!=0)
350 DbgPrint("Mouse Systems Mouse Detected\n");
356 if(gotmouse==0) return FALSE;
358 DeviceExtension->ActiveQueue = 0;
359 MappedIrq = HalGetInterruptVector(Internal, 0, 0, MOUSE_IRQ, &Dirql, &Affinity);
361 IoConnectInterrupt(&DeviceExtension->MouseInterrupt, microsoft_mouse_handler,
362 DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE,
368 VOID SerialMouseInitializeDataQueue(PVOID Context)
373 MouseSynchronizeRoutine(PVOID Context)
375 PIRP Irp = (PIRP)Context;
376 PMOUSE_INPUT_DATA rec = (PMOUSE_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
377 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
378 ULONG NrToRead = stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA);
381 if ((stk->Parameters.Read.Length/sizeof(MOUSE_INPUT_DATA))==NrToRead)
390 SerialMouseStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
392 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
394 if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp))
396 Irp->IoStatus.Status = STATUS_SUCCESS;
397 Irp->IoStatus.Information = 0;
398 IoCompleteRequest(Irp, IO_NO_INCREMENT);
399 IoStartNextPacket(DeviceObject, FALSE);
404 SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
406 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
407 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
410 switch(Stack->Parameters.DeviceIoControl.IoControlCode)
412 case IOCTL_INTERNAL_MOUSE_CONNECT:
414 DeviceExtension->ClassInformation =
415 *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
417 /* Reinitialize the port input data queue synchronously */
418 KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
419 (PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue, DeviceExtension);
421 status = STATUS_SUCCESS;
425 status = STATUS_INVALID_DEVICE_REQUEST;
429 Irp->IoStatus.Status = status;
430 if (status == STATUS_PENDING) {
431 IoMarkIrpPending(Irp);
432 IoStartPacket(DeviceObject, Irp, NULL, NULL);
434 IoCompleteRequest(Irp, IO_NO_INCREMENT);
441 SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
443 PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
445 static BOOLEAN AlreadyOpened = FALSE;
447 switch (stk->MajorFunction)
450 if (AlreadyOpened == TRUE)
452 Status = STATUS_SUCCESS;
456 Status = STATUS_SUCCESS;
457 AlreadyOpened = TRUE;
462 Status = STATUS_SUCCESS;
466 DbgPrint("NOT IMPLEMENTED\n");
467 Status = STATUS_NOT_IMPLEMENTED;
471 if (Status==STATUS_PENDING)
473 IoMarkIrpPending(Irp);
477 Irp->IoStatus.Status = Status;
478 Irp->IoStatus.Information = 0;
479 IoCompleteRequest(Irp,IO_NO_INCREMENT);
484 VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
486 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
489 Queue = DeviceExtension->ActiveQueue % 2;
490 InterlockedIncrement(&DeviceExtension->ActiveQueue);
491 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.CallBack)(
492 DeviceExtension->ClassInformation.DeviceObject,
493 DeviceExtension->MouseInputData[Queue],
495 &DeviceExtension->InputDataCount[Queue]);
497 DeviceExtension->InputDataCount[Queue] = 0;
501 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
503 PDEVICE_OBJECT DeviceObject;
504 UNICODE_STRING DeviceName;
505 UNICODE_STRING SymlinkName;
506 PDEVICE_EXTENSION DeviceExtension;
508 DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseDispatch;
509 DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialMouseDispatch;
510 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SerialMouseInternalDeviceControl;
511 DriverObject->DriverStartIo = SerialMouseStartIo;
513 RtlInitUnicodeStringFromLiteral(&DeviceName,
514 L"\\Device\\Mouse"); /* FIXME: find correct device name */
515 IoCreateDevice(DriverObject,
516 sizeof(DEVICE_EXTENSION),
518 FILE_DEVICE_SERIAL_MOUSE_PORT,
522 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
524 if(InitializeMouse(DeviceObject) == TRUE)
526 DbgPrint("Serial Mouse Driver 0.0.5\n");
528 IoDeleteDevice(DeviceObject);
529 DbgPrint("Serial mouse not found.\n");
530 return STATUS_UNSUCCESSFUL;
533 RtlInitUnicodeStringFromLiteral(&SymlinkName,
534 L"\\??\\Mouse"); /* FIXME: find correct device name */
535 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
537 DeviceExtension = DeviceObject->DeviceExtension;
538 KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
540 return(STATUS_SUCCESS);