remove whitespace from end of lines
[reactos.git] / reactos / drivers / input / sermouse / sermouse.c
1 /*
2 * Serial Mouse driver 0.0.9
3 * Written by Jason Filby (jasonfilby@yahoo.com)
4 * And heavily rewritten by Filip Navara (xnavara@volny.cz)
5 * For ReactOS (www.reactos.com)
6 *
7 * Technical information about mouse protocols can be found
8 * in the file sermouse.txt.
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <ddk/ntddmou.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /*
20 * Compile time options
21 */
22
23 /* Support for the IOCTL_MOUSE_QUERY_ATTRIBUTES I/O control code */
24 #define SERMOUSE_QUERYATTRIBUTES_SUPPORT
25 /* Check for mouse on COM1? */
26 #define SERMOUSE_COM1_SUPPORT
27 /* Check for mouse on COM2? */
28 /* #define SERMOUSE_COM2_SUPPORT */
29
30 /*
31 * Definitions
32 */
33
34 #define MOUSE_IRQ_COM1 4
35 #define MOUSE_IRQ_COM2 3
36 #define MOUSE_PORT_COM1 0x3f8
37 #define MOUSE_PORT_COM2 0x2f8
38
39 /* Maximum value plus one for \Device\PointerClass* device name */
40 #define POINTER_PORTS_MAXIMUM 8
41 /* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */
42 #define SUFFIX_MAXIMUM_SIZE (1 * sizeof(WCHAR))
43
44 /* No Mouse */
45 #define MOUSE_TYPE_NONE 0
46 /* Microsoft Mouse with 2 buttons */
47 #define MOUSE_TYPE_MICROSOFT 1
48 /* Logitech Mouse with 3 buttons */
49 #define MOUSE_TYPE_LOGITECH 2
50 /* Microsoft Wheel Mouse (aka Z Mouse) */
51 #define MOUSE_TYPE_WHEELZ 3
52 /* Mouse Systems Mouse */
53 #define MOUSE_TYPE_MOUSESYSTEMS 4
54
55 /* Size for packet buffer used in interrupt routine */
56 #define PACKET_BUFFER_SIZE 4
57
58 /* Hardware byte mask for left button */
59 #define LEFT_BUTTON_MASK 0x20
60 /* Hardware to Microsoft specific code byte shift for left button */
61 #define LEFT_BUTTON_SHIFT 5
62 /* Hardware byte mask for right button */
63 #define RIGHT_BUTTON_MASK 0x10
64 /* Hardware to Microsoft specific code byte shift for right button */
65 #define RIGHT_BUTTON_SHIFT 3
66 /* Hardware byte mask for middle button */
67 #define MIDDLE_BUTTON_MASK 0x20
68 /* Hardware to Microsoft specific code byte shift for middle button */
69 #define MIDDLE_BUTTON_SHIFT 3
70
71 /* Microsoft byte mask for left button */
72 #define MOUSE_BUTTON_LEFT 0x01
73 /* Microsoft byte mask for right button */
74 #define MOUSE_BUTTON_RIGHT 0x02
75 /* Microsoft byte mask for middle button */
76 #define MOUSE_BUTTON_MIDDLE 0x04
77
78 /*
79 * Structures
80 */
81
82 typedef struct _DEVICE_EXTENSION
83 {
84 PDEVICE_OBJECT DeviceObject;
85 ULONG ActiveQueue;
86 ULONG InputDataCount[2];
87 MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE];
88 CLASS_INFORMATION ClassInformation;
89 PKINTERRUPT MouseInterrupt;
90 KDPC IsrDpc;
91 ULONG MousePort;
92 ULONG MouseType;
93 UCHAR PacketBuffer[PACKET_BUFFER_SIZE];
94 ULONG PacketBufferPosition;
95 ULONG PreviousButtons;
96 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
97 MOUSE_ATTRIBUTES AttributesInformation;
98 #endif
99 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
100
101 /*
102 * Functions
103 */
104
105 /* Waits until the mouse calms down but also quits out after a while
106 * in case some destructive user wants to keep moving the mouse
107 * before we're done */
108 VOID ClearMouse(ULONG Port)
109 {
110 ULONG Restarts = 0;
111 ULONG i;
112 UCHAR Temp;
113
114 for (i = 0; i < 60000; i++)
115 {
116 Temp = READ_PORT_UCHAR((PUCHAR)Port);
117 if (Temp != 0)
118 {
119 Restarts++;
120 if (Restarts < 300000)
121 i = 0;
122 else
123 i = 60000;
124 }
125 }
126 }
127
128 BOOLEAN STDCALL
129 SerialMouseInterruptService(IN PKINTERRUPT Interrupt, PVOID ServiceContext)
130 {
131 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
132 PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
133 UCHAR *PacketBuffer = DeviceExtension->PacketBuffer;
134 ULONG MousePort = DeviceExtension->MousePort;
135 UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MousePort + 2);
136 UCHAR RecievedByte;
137 ULONG Queue;
138 PMOUSE_INPUT_DATA Input;
139 ULONG ButtonsDifference;
140
141 /* Is the interrupt for us? */
142 if ((InterruptId & 0x01) == 0x01)
143 {
144 return FALSE;
145 }
146
147 /* Not a Receive Data Available interrupt? */
148 if ((InterruptId & 0x04) == 0)
149 {
150 return TRUE;
151 }
152
153 /* Read all available data and process */
154 while ((READ_PORT_UCHAR((PUCHAR)MousePort + 5) & 0x01) != 0)
155 {
156 RecievedByte = READ_PORT_UCHAR((PUCHAR)MousePort);
157
158 /* Synchronize */
159 if ((RecievedByte & 0x40) == 0x40)
160 DeviceExtension->PacketBufferPosition = 0;
161
162 PacketBuffer[DeviceExtension->PacketBufferPosition] =
163 (RecievedByte & 0x7f);
164 ++DeviceExtension->PacketBufferPosition;
165
166 /* Process packet if complete */
167 if (DeviceExtension->PacketBufferPosition >= 3)
168 {
169 Queue = DeviceExtension->ActiveQueue % 2;
170
171 /* Prevent buffer overflow */
172 if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
173 continue;
174
175 Input = &DeviceExtension->MouseInputData[Queue][DeviceExtension->InputDataCount[Queue]];
176
177 if (DeviceExtension->PacketBufferPosition == 3)
178 {
179 /* Retrieve change in x and y from packet */
180 Input->LastX = (signed char)(PacketBuffer[1] | ((PacketBuffer[0] & 0x03) << 6));
181 Input->LastY = (signed char)(PacketBuffer[2] | ((PacketBuffer[0] & 0x0c) << 4));
182
183 /* Determine the current state of the buttons */
184 Input->RawButtons = (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE) |
185 ((UCHAR)(PacketBuffer[0] & LEFT_BUTTON_MASK) >> LEFT_BUTTON_SHIFT) |
186 ((UCHAR)(PacketBuffer[0] & RIGHT_BUTTON_MASK) >> RIGHT_BUTTON_SHIFT);
187 }
188 else if (DeviceExtension->PacketBufferPosition == 4)
189 {
190 DeviceExtension->PacketBufferPosition = 0;
191 /* If middle button state changed than report event */
192 if (((UCHAR)(PacketBuffer[3] & MIDDLE_BUTTON_MASK) >> MIDDLE_BUTTON_SHIFT) ^
193 (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE))
194 {
195 Input->RawButtons ^= MOUSE_BUTTON_MIDDLE;
196 Input->LastX = 0;
197 Input->LastY = 0;
198 }
199 else
200 {
201 continue;
202 }
203 }
204
205 /* Determine ButtonFlags */
206 Input->ButtonFlags = 0;
207 ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons;
208
209 if (ButtonsDifference != 0)
210 {
211 if (ButtonsDifference & MOUSE_BUTTON_LEFT)
212 {
213 if (Input->RawButtons & MOUSE_BUTTON_LEFT)
214 Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
215 else
216 Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
217 }
218
219 if (ButtonsDifference & MOUSE_BUTTON_RIGHT)
220 {
221 if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
222 Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
223 else
224 Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
225 }
226
227 if (ButtonsDifference & MOUSE_BUTTON_MIDDLE)
228 {
229 if (Input->RawButtons & MOUSE_BUTTON_MIDDLE)
230 Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
231 else
232 Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
233 }
234 }
235
236 /* Send the Input data to the Mouse Class driver */
237 DeviceExtension->InputDataCount[Queue]++;
238 KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
239
240 /* Copy RawButtons to Previous Buttons for Input */
241 DeviceExtension->PreviousButtons = Input->RawButtons;
242 }
243 }
244
245 return TRUE;
246 }
247
248 VOID
249 SerialMouseInitializeDataQueue(PVOID Context)
250 {
251 }
252
253 BOOLEAN STDCALL
254 MouseSynchronizeRoutine(PVOID Context)
255 {
256 return TRUE;
257 }
258
259 VOID STDCALL
260 SerialMouseStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
261 {
262 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
263
264 if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp))
265 {
266 KIRQL oldIrql;
267 Irp->IoStatus.Status = STATUS_SUCCESS;
268 Irp->IoStatus.Information = 0;
269 IoCompleteRequest(Irp, IO_NO_INCREMENT);
270 oldIrql = KeGetCurrentIrql();
271 if (oldIrql < DISPATCH_LEVEL)
272 {
273 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
274 IoStartNextPacket(DeviceObject, FALSE);
275 KeLowerIrql(oldIrql);
276 }
277 else
278 {
279 IoStartNextPacket (DeviceObject, FALSE);
280 }
281 }
282 }
283
284 NTSTATUS STDCALL
285 SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
286 {
287 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
288 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
289 NTSTATUS Status;
290
291 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
292 {
293 case IOCTL_INTERNAL_MOUSE_CONNECT:
294 DeviceExtension->ClassInformation =
295 *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
296
297 /* Reinitialize the port input data queue synchronously */
298 KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
299 (PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue,
300 DeviceExtension);
301
302 Status = STATUS_SUCCESS;
303 break;
304
305 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
306 case IOCTL_MOUSE_QUERY_ATTRIBUTES:
307 if (Stack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(MOUSE_ATTRIBUTES))
308 {
309 *(PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer =
310 DeviceExtension->AttributesInformation;
311 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
312 Status = STATUS_SUCCESS;
313 } else {
314 Status = STATUS_BUFFER_TOO_SMALL;
315 }
316 break;
317 #endif
318
319 default:
320 Status = STATUS_INVALID_DEVICE_REQUEST;
321 break;
322 }
323
324 Irp->IoStatus.Status = Status;
325 if (Status == STATUS_PENDING)
326 {
327 IoMarkIrpPending(Irp);
328 IoStartPacket(DeviceObject, Irp, NULL, NULL);
329 }
330 else
331 {
332 IoCompleteRequest(Irp, IO_NO_INCREMENT);
333 }
334
335 return Status;
336 }
337
338 NTSTATUS STDCALL
339 SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
340 {
341 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
342 NTSTATUS Status;
343
344 switch (Stack->MajorFunction)
345 {
346 case IRP_MJ_CREATE:
347 case IRP_MJ_CLOSE:
348 Status = STATUS_SUCCESS;
349 break;
350
351 default:
352 DbgPrint("NOT IMPLEMENTED\n");
353 Status = STATUS_NOT_IMPLEMENTED;
354 break;
355 }
356
357 if (Status == STATUS_PENDING)
358 {
359 IoMarkIrpPending(Irp);
360 }
361 else
362 {
363 Irp->IoStatus.Status = Status;
364 Irp->IoStatus.Information = 0;
365 IoCompleteRequest(Irp, IO_NO_INCREMENT);
366 }
367
368 return Status;
369 }
370
371 VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
372 {
373 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
374 ULONG Queue;
375
376 Queue = DeviceExtension->ActiveQueue % 2;
377 InterlockedIncrement((PLONG)&DeviceExtension->ActiveQueue);
378 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.CallBack)(
379 DeviceExtension->ClassInformation.DeviceObject,
380 DeviceExtension->MouseInputData[Queue],
381 NULL,
382 &DeviceExtension->InputDataCount[Queue]);
383
384 DeviceExtension->InputDataCount[Queue] = 0;
385 }
386
387 VOID InitializeSerialPort(ULONG Port)
388 {
389 /* DLAB off */
390 WRITE_PORT_UCHAR((PUCHAR)Port + 3, 0);
391 WRITE_PORT_UCHAR((PUCHAR)Port + 2, 0); /* FCR: disable FIFO */
392 WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0); /* IER: disable ints */
393 /* Set DLAB on */
394 WRITE_PORT_UCHAR((PUCHAR)Port + 3, 0x80);
395 /* Set serial port speed */
396 WRITE_PORT_UCHAR((PUCHAR)Port, 0x60);
397 WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0);
398 /* Set DLAB off and set LCR */
399 WRITE_PORT_UCHAR((PUCHAR)Port + 3, 2);
400 }
401
402 BOOLEAN UARTReadChar(ULONG Port, CHAR *Value, ULONG Timeout)
403 {
404 ULONG i, j;
405
406 for (i = 0; i < Timeout; i++)
407 {
408 for (j = 0; j < 1000; j++)
409 {
410 /* Is there a character ready? */
411 if (READ_PORT_UCHAR((PUCHAR)Port + 5) & 0x01)
412 {
413 /* Yes, read it and return */
414 *Value = READ_PORT_UCHAR((PUCHAR)Port);
415 return TRUE;
416 }
417 else
418 {
419 /* No, wait */
420 KeStallExecutionProcessor(1);
421 }
422 }
423 }
424
425 return FALSE;
426 }
427
428 ULONG DetectMicrosoftMouse(ULONG Port)
429 {
430 CHAR Buffer[8];
431 ULONG Count, i;
432 UCHAR LCR, MCR;
433
434 /* Save original LCR/MCR */
435 LCR = READ_PORT_UCHAR((PUCHAR)Port + 3); /* LCR (line ctrl reg) */
436 MCR = READ_PORT_UCHAR((PUCHAR)Port + 4); /* MCR (modem ctrl reg) */
437
438 /* Reset UART */
439 WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0); /* MCR: DTR/RTS/OUT2 off */
440
441 /* Set communications parameters */
442 InitializeSerialPort(Port);
443
444 /* Flush receive buffer */
445 (void) READ_PORT_UCHAR((PUCHAR)Port);
446 /* right? -> wait two ticks (approx 1/9 sec) */
447 KeStallExecutionProcessor(100000);
448
449 /* Enable DTR/RTS (OUT2 disabled) */
450 WRITE_PORT_UCHAR((PUCHAR)Port + 4, 3);
451
452 if (UARTReadChar(Port, &Buffer[0], 500))
453 {
454 Count = 1;
455 while (Count < 8)
456 {
457 if (UARTReadChar(Port, &Buffer[Count], 100))
458 Count++;
459 else
460 break;
461 }
462 }
463 else
464 return MOUSE_TYPE_NONE;
465
466 /* Restore LCR/MCR */
467 WRITE_PORT_UCHAR((PUCHAR)Port + 3, LCR); /* LCR (line ctrl reg) */
468 WRITE_PORT_UCHAR((PUCHAR)Port + 4, MCR); /* MCR (modem ctrl reg) */
469
470 for (i = 0; i < Count; ++i)
471 {
472 /* Sign for Microsoft Ballpoint */
473 if (Buffer[i] == 'B')
474 {
475 DbgPrint("Microsoft Ballpoint device detected");
476 DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET");
477 return MOUSE_TYPE_NONE;
478 } else
479 /* Sign for Microsoft Mouse protocol followed by button specifier */
480 if (Buffer[i] == 'M')
481 {
482 if (i == 3)
483 {
484 /* Overflow Error */
485 return MOUSE_TYPE_NONE;
486 }
487 switch (Buffer[i + 1])
488 {
489 case '3':
490 DbgPrint("Microsoft Mouse with 3-buttons detected\n");
491 return MOUSE_TYPE_LOGITECH;
492 case 'Z':
493 DbgPrint("Microsoft Wheel Mouse detected\n");
494 return MOUSE_TYPE_WHEELZ;
495 /* case '2': */
496 default:
497 DbgPrint("Microsoft Mouse with 2-buttons detected\n");
498 return MOUSE_TYPE_MICROSOFT;
499 }
500 }
501 }
502
503 return MOUSE_TYPE_NONE;
504 }
505
506 PDEVICE_OBJECT
507 AllocatePointerDevice(PDRIVER_OBJECT DriverObject)
508 {
509 PDEVICE_OBJECT DeviceObject;
510 UNICODE_STRING DeviceName;
511 UNICODE_STRING SuffixString;
512 PDEVICE_EXTENSION DeviceExtension;
513 ULONG Suffix;
514 NTSTATUS Status;
515
516 /* Allocate buffer for full device name */
517 RtlInitUnicodeString(&DeviceName, NULL);
518 DeviceName.MaximumLength = sizeof(DD_MOUSE_DEVICE_NAME_U) + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
519 DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
520 RtlAppendUnicodeToString(&DeviceName, DD_MOUSE_DEVICE_NAME_U);
521
522 /* Allocate buffer for device name suffix */
523 RtlInitUnicodeString(&SuffixString, NULL);
524 SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
525 SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength);
526
527 /* Generate full qualified name with suffix */
528 for (Suffix = 0; Suffix < POINTER_PORTS_MAXIMUM; ++Suffix)
529 {
530 RtlIntegerToUnicodeString(Suffix, 10, &SuffixString);
531 RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
532 Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
533 &DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject);
534 /* Device successfully created, leave the cyclus */
535 if (NT_SUCCESS(Status))
536 break;
537 DeviceName.Length -= SuffixString.Length;
538 }
539
540 ExFreePool(DeviceName.Buffer);
541 ExFreePool(SuffixString.Buffer);
542
543 /* Couldn't create device */
544 if (!NT_SUCCESS(Status))
545 {
546 return NULL;
547 }
548
549 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
550
551 DeviceExtension = DeviceObject->DeviceExtension;
552 KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
553
554 return DeviceObject;
555 }
556
557 BOOLEAN
558 InitializeMouse(ULONG Port, ULONG Irq, PDRIVER_OBJECT DriverObject)
559 {
560 PDEVICE_EXTENSION DeviceExtension;
561 PDEVICE_OBJECT DeviceObject;
562 ULONG MappedIrq;
563 KIRQL Dirql;
564 KAFFINITY Affinity;
565 ULONG MouseType;
566
567 /* Try to detect mouse on specified port */
568 MouseType = DetectMicrosoftMouse(Port);
569
570 /* No mouse, no need to continue */
571 if (MouseType == MOUSE_TYPE_NONE)
572 {
573 return FALSE;
574 }
575
576 /* Enable interrupts */
577 WRITE_PORT_UCHAR((PUCHAR)(Port) + 1, 1);
578
579 ClearMouse(Port);
580
581 /* Enable RTS, DTR and OUT2 */
582 WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x0b);
583
584 /* Allocate new device */
585 DeviceObject = AllocatePointerDevice(DriverObject);
586 if (!DeviceObject)
587 {
588 DbgPrint("Oops, couldn't creat device object.\n");
589 return FALSE;
590 }
591
592 DeviceExtension = DeviceObject->DeviceExtension;
593
594 /* Setup device extension structure */
595 DeviceExtension->ActiveQueue = 0;
596 DeviceExtension->MouseType = MouseType;
597 DeviceExtension->MousePort = Port;
598 DeviceExtension->PacketBufferPosition = 0;
599 DeviceExtension->PreviousButtons = 0;
600 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
601 switch (MouseType)
602 {
603 case MOUSE_TYPE_MICROSOFT:
604 DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
605 DeviceExtension->AttributesInformation.NumberOfButtons = 2;
606 break;
607 case MOUSE_TYPE_LOGITECH:
608 DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
609 DeviceExtension->AttributesInformation.NumberOfButtons = 3;
610 break;
611 case MOUSE_TYPE_WHEELZ:
612 DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE;
613 DeviceExtension->AttributesInformation.NumberOfButtons = 3;
614 break;
615 };
616 DeviceExtension->AttributesInformation.SampleRate = 40;
617 DeviceExtension->AttributesInformation.InputDataQueueLength = MOUSE_BUFFER_SIZE;
618 #endif
619
620 MappedIrq = HalGetInterruptVector(Internal, 0, 0, Irq, &Dirql, &Affinity);
621
622 IoConnectInterrupt(
623 &DeviceExtension->MouseInterrupt, SerialMouseInterruptService,
624 DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE,
625 Affinity, FALSE);
626
627 return TRUE;
628 }
629
630
631 static VOID
632 GetMouseResourceData(PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor,
633 PULONG Port,
634 PULONG Interrupt)
635 {
636 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
637 ULONG i;
638
639 for (i = 0; i < FullDescriptor->PartialResourceList.Count; i++)
640 {
641 PartialDescriptor = &FullDescriptor->PartialResourceList.PartialDescriptors[i];
642
643 switch (PartialDescriptor->Type)
644 {
645 case CmResourceTypePort:
646 *Port = (ULONG)PartialDescriptor->u.Port.Start.u.LowPart;
647 break;
648
649 case CmResourceTypeInterrupt:
650 *Interrupt = (ULONG)PartialDescriptor->u.Interrupt.Level;
651 break;
652 }
653 }
654 }
655
656
657 static BOOLEAN
658 GetMouseResources(PULONG Port,
659 PULONG Interrupt)
660 {
661 OBJECT_ATTRIBUTES ObjectAttributes;
662 UNICODE_STRING KeyName;
663 WCHAR Buffer[32];
664 HANDLE BusKey;
665 HANDLE BusInstanceKey;
666 HANDLE ControllerKey;
667 HANDLE ControllerInstanceKey;
668 HANDLE PeripheralKey;
669 HANDLE PeripheralInstanceKey;
670 ULONG BusInstance;
671 ULONG ControllerInstance;
672 ULONG PeripheralInstance;
673 ULONG BufferLength;
674 ULONG ReturnedLength;
675 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
676 NTSTATUS Status;
677
678 DPRINT("GetMouseResources() called\n");
679
680 /* Open the bus key */
681 RtlInitUnicodeString(&KeyName,
682 L"\\Registry\\Machine\\HARDWARE\\Description\\System\\MultifunctionAdapter");
683 InitializeObjectAttributes(&ObjectAttributes,
684 &KeyName,
685 OBJ_CASE_INSENSITIVE,
686 NULL,
687 NULL);
688 Status = ZwOpenKey(&BusKey,
689 KEY_ALL_ACCESS,
690 &ObjectAttributes);
691 if (!NT_SUCCESS(Status))
692 {
693 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
694 return FALSE;
695 }
696
697 BusInstance = 0;
698 while (TRUE)
699 {
700 sprintf((PCHAR)Buffer, "%lu", (ULONG)0);
701 swprintf(Buffer, L"%lu", BusInstance);
702 RtlInitUnicodeString(&KeyName,
703 Buffer);
704 InitializeObjectAttributes(&ObjectAttributes,
705 &KeyName,
706 OBJ_CASE_INSENSITIVE,
707 BusKey,
708 NULL);
709 Status = ZwOpenKey(&BusInstanceKey,
710 KEY_ALL_ACCESS,
711 &ObjectAttributes);
712 if (!NT_SUCCESS(Status))
713 {
714 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
715 ZwClose(BusKey);
716 return FALSE;
717 }
718
719 /* Open the controller type key */
720 RtlInitUnicodeString(&KeyName,
721 L"SerialController");
722 InitializeObjectAttributes(&ObjectAttributes,
723 &KeyName,
724 OBJ_CASE_INSENSITIVE,
725 BusInstanceKey,
726 NULL);
727 Status = ZwOpenKey(&ControllerKey,
728 KEY_ALL_ACCESS,
729 &ObjectAttributes);
730 if (NT_SUCCESS(Status))
731 {
732 ControllerInstance = 0;
733 while (TRUE)
734 {
735 /* Open the pointer controller instance key */
736 swprintf(Buffer, L"%lu", ControllerInstance);
737 RtlInitUnicodeString(&KeyName,
738 Buffer);
739 InitializeObjectAttributes(&ObjectAttributes,
740 &KeyName,
741 OBJ_CASE_INSENSITIVE,
742 ControllerKey,
743 NULL);
744 Status = ZwOpenKey(&ControllerInstanceKey,
745 KEY_ALL_ACCESS,
746 &ObjectAttributes);
747 if (!NT_SUCCESS(Status))
748 {
749 DPRINT("NtOpenKey() failed (Status %lx)\n", Status);
750 ZwClose(ControllerKey);
751 ZwClose(BusInstanceKey);
752 ZwClose(BusKey);
753 return FALSE;
754 }
755
756 /* Open the 'PointerPeripheral' key */
757 RtlInitUnicodeString(&KeyName,
758 L"PointerPeripheral");
759 InitializeObjectAttributes(&ObjectAttributes,
760 &KeyName,
761 OBJ_CASE_INSENSITIVE,
762 ControllerInstanceKey,
763 NULL);
764 Status = ZwOpenKey(&PeripheralKey,
765 KEY_ALL_ACCESS,
766 &ObjectAttributes);
767 if (NT_SUCCESS(Status))
768 {
769 PeripheralInstance = 0;
770 while (TRUE)
771 {
772 /* Open the pointer peripheral instance key */
773 swprintf(Buffer, L"%lu", PeripheralInstance);
774 RtlInitUnicodeString(&KeyName,
775 Buffer);
776 InitializeObjectAttributes(&ObjectAttributes,
777 &KeyName,
778 OBJ_CASE_INSENSITIVE,
779 PeripheralKey,
780 NULL);
781 Status = ZwOpenKey(&PeripheralInstanceKey,
782 KEY_ALL_ACCESS,
783 &ObjectAttributes);
784 if (!NT_SUCCESS(Status))
785 {
786 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status);
787 ZwClose(PeripheralKey);
788 ZwClose(ControllerInstanceKey);
789 ZwClose(ControllerKey);
790 ZwClose(BusInstanceKey);
791 ZwClose(BusKey);
792 return FALSE;
793 }
794
795 /* Get peripheral identifier */
796 RtlInitUnicodeString(&KeyName,
797 L"Configuration Data");
798
799 BufferLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
800 ReturnedLength = 0;
801 ValueInfo = ExAllocatePool(NonPagedPool,
802 BufferLength);
803 if (ValueInfo == NULL)
804 {
805 DPRINT("ExAllocatePool() failed\n");
806 ZwClose(PeripheralInstanceKey);
807 ZwClose(PeripheralKey);
808 ZwClose(ControllerInstanceKey);
809 ZwClose(ControllerKey);
810 ZwClose(BusInstanceKey);
811 ZwClose(BusKey);
812 return FALSE;
813 }
814
815 Status = ZwQueryValueKey(ControllerInstanceKey,
816 &KeyName,
817 KeyValuePartialInformation,
818 ValueInfo,
819 BufferLength,
820 &ReturnedLength);
821 DPRINT("ZwQueryValueKey() called (Status %lx)\n", Status);
822 DPRINT("ReturnedLength %ld\n", ReturnedLength);
823
824 ExFreePool(ValueInfo);
825 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
826 {
827 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status);
828 ZwClose(PeripheralInstanceKey);
829 ZwClose(PeripheralKey);
830 ZwClose(ControllerInstanceKey);
831 ZwClose(ControllerKey);
832 ZwClose(BusInstanceKey);
833 ZwClose(BusKey);
834 return FALSE;
835 }
836
837 BufferLength = ReturnedLength;
838 ValueInfo = ExAllocatePool(NonPagedPool,
839 BufferLength);
840 if (ValueInfo == NULL)
841 {
842 DPRINT("ExAllocatePool() failed\n");
843 ZwClose(PeripheralInstanceKey);
844 ZwClose(PeripheralKey);
845 ZwClose(ControllerInstanceKey);
846 ZwClose(ControllerKey);
847 ZwClose(BusInstanceKey);
848 ZwClose(BusKey);
849 return FALSE;
850 }
851
852 Status = ZwQueryValueKey(ControllerInstanceKey,
853 &KeyName,
854 KeyValuePartialInformation,
855 ValueInfo,
856 BufferLength,
857 &ReturnedLength);
858 if (NT_SUCCESS(Status))
859 {
860 DPRINT("Done\n");
861 GetMouseResourceData((PCM_FULL_RESOURCE_DESCRIPTOR)(ValueInfo->Data),
862 Port,
863 Interrupt);
864
865 ExFreePool(ValueInfo);
866 ZwClose(PeripheralInstanceKey);
867 ZwClose(PeripheralKey);
868 ZwClose(ControllerInstanceKey);
869 ZwClose(ControllerKey);
870 ZwClose(BusInstanceKey);
871 ZwClose(BusKey);
872 return TRUE;
873 }
874
875 ExFreePool(ValueInfo);
876
877 ZwClose(PeripheralInstanceKey);
878
879 PeripheralInstance++;
880 }
881
882 ZwClose(PeripheralKey);
883 }
884
885 ZwClose(ControllerInstanceKey);
886
887 ControllerInstance++;
888 }
889
890 ZwClose(ControllerKey);
891 }
892
893 ZwClose(BusInstanceKey);
894
895 BusInstance++;
896 }
897
898 ZwClose(BusKey);
899
900 return FALSE;
901 }
902
903
904
905 NTSTATUS STDCALL
906 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
907 {
908 BOOLEAN MouseFound = FALSE;
909 ULONG BaseAddress = (ULONG)-1;
910 ULONG Interrupt = (ULONG)-1;
911
912 DPRINT1("Serial Mouse Driver 0.0.9\n");
913
914 if (GetMouseResources(&BaseAddress, &Interrupt))
915 {
916 if (BaseAddress != (ULONG)-1 && Interrupt != (ULONG)-1)
917 {
918 DPRINT1("Found mouse: Port %lx Interupt %lu\n", BaseAddress, Interrupt);
919 MouseFound |= InitializeMouse(BaseAddress, Interrupt, DriverObject);
920 }
921 }
922 else
923 {
924 #ifdef SERMOUSE_COM1_SUPPORT
925 DPRINT1("Trying to find mouse on COM1\n");
926 MouseFound |= InitializeMouse(MOUSE_PORT_COM1, MOUSE_IRQ_COM1, DriverObject);
927 #endif
928 #ifdef SERMOUSE_COM2_SUPPORT
929 DPRINT1("Trying to find mouse on COM2\n");
930 MouseFound |= InitializeMouse(MOUSE_PORT_COM2, MOUSE_IRQ_COM2, DriverObject);
931 #endif
932 }
933
934 if (!MouseFound)
935 {
936 DPRINT1("No serial mouse found.\n");
937 return STATUS_UNSUCCESSFUL;
938 }
939
940 DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialMouseDispatch;
941 DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialMouseDispatch;
942 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = SerialMouseInternalDeviceControl;
943 DriverObject->DriverStartIo = SerialMouseStartIo;
944
945 return STATUS_SUCCESS;
946 }