update for HEAD-2003091401
[reactos.git] / drivers / input / sermouse / sermouse.c
1 /*
2  * Serial Mouse driver 0.0.8
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 #include <ddk/ntddk.h>
12 #include <ddk/ntddmou.h>
13
14 /*
15  * Compile time options
16  */
17
18 /* Support for the IOCTL_MOUSE_QUERY_ATTRIBUTES I/O control code */
19 #define SERMOUSE_QUERYATTRIBUTES_SUPPORT
20 /* Check for mouse on COM1? */
21 #define SERMOUSE_COM1_SUPPORT
22 /* Check for mouse on COM2? */
23 //#define SERMOUSE_COM2_SUPPORT
24 /* Create \??\Mouse* symlink for device? */
25 #define SERMOUSE_MOUSESYMLINK_SUPPORT
26
27 /*
28  * Definitions
29  */
30
31 #define MOUSE_IRQ_COM1                  4
32 #define MOUSE_IRQ_COM2                  3
33 #define MOUSE_PORT_COM1                 0x3f8
34 #define MOUSE_PORT_COM2                 0x2f8
35
36 /* Maximum value plus one for \Device\PointerClass* device name */
37 #define POINTER_PORTS_MAXIMUM   8
38 /* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */
39 #define SUFFIX_MAXIMUM_SIZE             (1 * sizeof(WCHAR))
40
41 /* No Mouse */
42 #define MOUSE_TYPE_NONE                 0
43 /* Microsoft Mouse with 2 buttons */
44 #define MOUSE_TYPE_MICROSOFT    1
45 /* Logitech Mouse with 3 buttons */
46 #define MOUSE_TYPE_LOGITECH             2
47 /* Microsoft Wheel Mouse (aka Z Mouse) */
48 #define MOUSE_TYPE_WHEELZ               3
49 /* Mouse Systems Mouse */
50 #define MOUSE_TYPE_MOUSESYSTEMS 4
51
52 /* Size for packet buffer used in interrupt routine */
53 #define PACKET_BUFFER_SIZE              4
54
55 /* Hardware byte mask for left button */
56 #define LEFT_BUTTON_MASK                0x20
57 /* Hardware to Microsoft specific code byte shift for left button */
58 #define LEFT_BUTTON_SHIFT               5
59 /* Hardware byte mask for right button */
60 #define RIGHT_BUTTON_MASK               0x10
61 /* Hardware to Microsoft specific code byte shift for right button */
62 #define RIGHT_BUTTON_SHIFT              3
63 /* Hardware byte mask for middle button */
64 #define MIDDLE_BUTTON_MASK              0x20
65 /* Hardware to Microsoft specific code byte shift for middle button */
66 #define MIDDLE_BUTTON_SHIFT             3
67
68 /* Microsoft byte mask for left button */
69 #define MOUSE_BUTTON_LEFT               0x01
70 /* Microsoft byte mask for right button */
71 #define MOUSE_BUTTON_RIGHT              0x02
72 /* Microsoft byte mask for middle button */
73 #define MOUSE_BUTTON_MIDDLE             0x04
74
75 /*
76  * Structures
77  */
78
79 typedef struct _DEVICE_EXTENSION {
80         PDEVICE_OBJECT DeviceObject;
81         ULONG ActiveQueue;
82         ULONG InputDataCount[2];
83         MOUSE_INPUT_DATA MouseInputData[2][MOUSE_BUFFER_SIZE];
84         CLASS_INFORMATION ClassInformation;
85         PKINTERRUPT MouseInterrupt;
86         KDPC IsrDpc;
87         ULONG MousePort;
88         ULONG MouseType;
89         UCHAR PacketBuffer[PACKET_BUFFER_SIZE];
90         ULONG PacketBufferPosition;
91         ULONG PreviousButtons;
92 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
93         MOUSE_ATTRIBUTES AttributesInformation;
94 #endif
95 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
96
97 /*
98  * Functions
99  */
100
101 void ClearMouse(ULONG Port)
102 {
103         /* Waits until the mouse calms down but also quits out after a while
104          * in case some destructive user wants to keep moving the mouse
105          * before we're done */
106         unsigned int Restarts = 0, i;
107         for (i = 0; i < 60000; i++)
108         {
109         unsigned Temp = READ_PORT_UCHAR((PUCHAR)Port);
110             if (Temp != 0)
111         {
112                         Restarts++;
113                         if (Restarts < 300000)
114                                 i = 0;
115                         else
116                                 i = 60000;
117                 }
118         }
119 }
120
121 BOOLEAN STDCALL
122 SerialMouseInterruptService(IN PKINTERRUPT Interrupt, PVOID ServiceContext)
123 {
124         PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
125         PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
126         UCHAR *PacketBuffer = DeviceExtension->PacketBuffer;
127         ULONG MousePort = DeviceExtension->MousePort;
128         UCHAR InterruptId = READ_PORT_UCHAR((PUCHAR)MousePort + 2);
129         UCHAR RecievedByte;
130         ULONG Queue;
131         PMOUSE_INPUT_DATA Input;
132         ULONG ButtonsDifference;
133
134         /* Is the interrupt for us? */
135         if ((InterruptId & 0x01) == 0x01)
136         {
137                 return FALSE;
138         }
139
140         /* Not a Receive Data Available interrupt? */
141         if ((InterruptId & 0x04) == 0)
142         {
143                 return TRUE;
144         }
145
146         /* Read all available data and process */
147         while ((READ_PORT_UCHAR((PUCHAR)MousePort + 5) & 0x01) != 0)
148         {
149                 RecievedByte = READ_PORT_UCHAR((PUCHAR)MousePort);
150
151                 /* Synchronize */
152                 if ((RecievedByte & 0x40) == 0x40)
153                         DeviceExtension->PacketBufferPosition = 0;
154
155                 PacketBuffer[DeviceExtension->PacketBufferPosition] =
156                         (RecievedByte & 0x7f);
157                 ++DeviceExtension->PacketBufferPosition;
158
159                 /* Process packet if complete */
160                 if (DeviceExtension->PacketBufferPosition >= 3)
161                 {
162                         Queue = DeviceExtension->ActiveQueue % 2;
163         
164                         /* Prevent buffer overflow */
165                         if (DeviceExtension->InputDataCount[Queue] == MOUSE_BUFFER_SIZE)
166                                 continue;
167
168                         Input = &DeviceExtension->MouseInputData[Queue][DeviceExtension->InputDataCount[Queue]];
169
170                         if (DeviceExtension->PacketBufferPosition == 3)
171                         {
172                                 /* Retrieve change in x and y from packet */
173                 Input->LastX = (signed char)(PacketBuffer[1] | ((PacketBuffer[0] & 0x03) << 6));
174                     Input->LastY = (signed char)(PacketBuffer[2] | ((PacketBuffer[0] & 0x0c) << 4));
175         
176                                 /* Determine the current state of the buttons */
177                                 Input->RawButtons = (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE) |
178                                         ((UCHAR)(PacketBuffer[0] & LEFT_BUTTON_MASK) >> LEFT_BUTTON_SHIFT) |
179                                         ((UCHAR)(PacketBuffer[0] & RIGHT_BUTTON_MASK) >> RIGHT_BUTTON_SHIFT);
180                         } else
181                         if (DeviceExtension->PacketBufferPosition == 4)
182                         {
183                                 DeviceExtension->PacketBufferPosition = 0;
184                                 /* If middle button state changed than report event */
185                                 if (((UCHAR)(PacketBuffer[3] & MIDDLE_BUTTON_MASK) >> MIDDLE_BUTTON_SHIFT) ^
186                                         (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE))
187                                 {
188                                         Input->RawButtons ^= MOUSE_BUTTON_MIDDLE;
189                                         Input->LastX = 0;
190                                         Input->LastY = 0;
191                                 }
192                                 else
193                                 {
194                                         continue;
195                                 }
196                         }
197
198                         /* Determine ButtonFlags */
199                         Input->ButtonFlags = 0;
200                         ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons;
201
202                         if (ButtonsDifference != 0)
203                         {
204                                 if (ButtonsDifference & MOUSE_BUTTON_LEFT)
205                                 {
206                                         if (Input->RawButtons & MOUSE_BUTTON_LEFT)
207                                                 Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
208                                         else
209                                                 Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
210                                 }
211                                 if (ButtonsDifference & MOUSE_BUTTON_RIGHT)
212                                 {
213                                         if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
214                                                 Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
215                                         else
216                                                 Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
217                                 }
218                                 if (ButtonsDifference & MOUSE_BUTTON_MIDDLE)
219                                 {
220                                         if (Input->RawButtons & MOUSE_BUTTON_MIDDLE)
221                                                 Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
222                                         else
223                                                 Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
224                                 }
225                         }
226
227                         /* Send the Input data to the Mouse Class driver */
228                         DeviceExtension->InputDataCount[Queue]++;
229                         KeInsertQueueDpc(&DeviceExtension->IsrDpc, DeviceObject->CurrentIrp, NULL);
230
231                         /* Copy RawButtons to Previous Buttons for Input */
232                         DeviceExtension->PreviousButtons = Input->RawButtons;
233                 }
234         }
235
236         return TRUE;
237 }
238
239 VOID
240 SerialMouseInitializeDataQueue(PVOID Context)
241 {
242 }
243
244 BOOLEAN STDCALL
245 MouseSynchronizeRoutine(PVOID Context)
246 {
247         return TRUE;
248 }
249
250 VOID STDCALL
251 SerialMouseStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
252 {
253         PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
254
255         if (KeSynchronizeExecution(DeviceExtension->MouseInterrupt, MouseSynchronizeRoutine, Irp))
256         {
257                 Irp->IoStatus.Status = STATUS_SUCCESS;
258                 Irp->IoStatus.Information = 0;
259                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
260                 IoStartNextPacket(DeviceObject, FALSE);
261         }
262 }
263
264 NTSTATUS STDCALL
265 SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
266 {
267         PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
268         PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
269         NTSTATUS Status;
270
271         switch (Stack->Parameters.DeviceIoControl.IoControlCode)
272         {
273                 case IOCTL_INTERNAL_MOUSE_CONNECT:
274                         DeviceExtension->ClassInformation =
275                                 *((PCLASS_INFORMATION)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
276
277                         /* Reinitialize the port input data queue synchronously */
278                         KeSynchronizeExecution(DeviceExtension->MouseInterrupt,
279                                 (PKSYNCHRONIZE_ROUTINE)SerialMouseInitializeDataQueue,
280                                 DeviceExtension);
281
282                         Status = STATUS_SUCCESS;
283                         break;
284
285 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
286                 case IOCTL_MOUSE_QUERY_ATTRIBUTES:
287                         if (Stack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(MOUSE_ATTRIBUTES))
288                         {
289                                 *(PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer =
290                                         DeviceExtension->AttributesInformation;
291                                 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
292                 Status = STATUS_SUCCESS;                                
293             } else {
294                                 Status = STATUS_BUFFER_TOO_SMALL;
295                         }
296                         break;
297 #endif
298
299                 default:
300                         Status = STATUS_INVALID_DEVICE_REQUEST;
301                         break;
302         }
303
304         Irp->IoStatus.Status = Status;
305         if (Status == STATUS_PENDING)
306         {
307                 IoMarkIrpPending(Irp);
308                 IoStartPacket(DeviceObject, Irp, NULL, NULL);
309         }
310         else
311         {
312                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
313         }
314
315         return Status;
316 }
317
318 NTSTATUS STDCALL
319 SerialMouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
320 {
321         PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
322         NTSTATUS Status;
323
324         switch (Stack->MajorFunction)
325         {
326                 case IRP_MJ_CREATE:
327                 case IRP_MJ_CLOSE:
328                         Status = STATUS_SUCCESS;
329                         break;
330
331                 default:
332                         DbgPrint("NOT IMPLEMENTED\n");
333                         Status = STATUS_NOT_IMPLEMENTED;
334                         break;
335         }
336
337         if (Status == STATUS_PENDING)
338         {
339                 IoMarkIrpPending(Irp);
340         }
341         else
342         {
343                 Irp->IoStatus.Status = Status;
344                 Irp->IoStatus.Information = 0;
345                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
346     }
347
348         return Status;
349 }
350
351 VOID SerialMouseIsrDpc(PKDPC Dpc, PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
352 {
353    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
354    ULONG Queue;
355
356    Queue = DeviceExtension->ActiveQueue % 2;
357    InterlockedIncrement(&DeviceExtension->ActiveQueue);
358    (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassInformation.CallBack)(
359                         DeviceExtension->ClassInformation.DeviceObject,
360                         DeviceExtension->MouseInputData[Queue],
361                         NULL,
362                         &DeviceExtension->InputDataCount[Queue]);
363
364    DeviceExtension->InputDataCount[Queue] = 0;
365 }
366
367 void InitializeSerialPort(ULONG Port, unsigned int LineControl)
368 {
369         WRITE_PORT_UCHAR((PUCHAR)Port + 3, 0x80);  /* set DLAB on   */
370         WRITE_PORT_UCHAR((PUCHAR)Port,     0x60);  /* speed LO byte */
371         WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0);     /* speed HI byte */
372         WRITE_PORT_UCHAR((PUCHAR)Port + 3, LineControl);
373         WRITE_PORT_UCHAR((PUCHAR)Port + 1, 0);     /* set comm and DLAB to 0 */
374         WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x09);  /* DR int enable */
375         (void) READ_PORT_UCHAR((PUCHAR)Port + 5);  /* clear error bits */
376 }
377
378 ULONG DetectMicrosoftMouse(ULONG Port)
379 {
380         CHAR Buffer[4];
381         ULONG i;
382         ULONG TimeOut = 250;
383     UCHAR LineControl;
384     
385     /* Shutdown mouse or something like that */ 
386     LineControl = READ_PORT_UCHAR((PUCHAR)Port + 4);
387         WRITE_PORT_UCHAR((PUCHAR)Port + 4, (LineControl & ~0x02) | 0x01);
388     KeStallExecutionProcessor(500000);
389
390     /* Clear buffer */
391         while (READ_PORT_UCHAR((PUCHAR)Port + 5) & 0x01)
392                 (void)READ_PORT_UCHAR((PUCHAR)Port);
393
394         /* Send modem control with 'Data Terminal Ready', 'Request To Send' and
395          * 'Output Line 2' message. This enables mouse to identify. */
396         WRITE_PORT_UCHAR((PUCHAR)Port + 4, 0x0b);
397         /* Wait 10 milliseconds for the mouse getting ready */
398         KeStallExecutionProcessor(10000);
399
400         /* Read first four bytes, which contains Microsoft Mouse signs */
401         for (i = 0; i < 4; i++)
402         {
403                 while (((READ_PORT_UCHAR((PUCHAR)Port + 5) & 1) == 0) && (TimeOut > 0))
404                 {
405                         KeStallExecutionProcessor(1000);
406                         --TimeOut;
407                         if (TimeOut == 0)
408                                 return MOUSE_TYPE_NONE;
409                 }
410                 Buffer[i] = READ_PORT_UCHAR((PUCHAR)Port);
411         }
412
413         /* Check that four bytes for signs */
414         for (i = 0; i < 4; ++i)
415         {
416                 /* Sign for Microsoft Ballpoint */
417         if (Buffer[i] == 'B')
418             {
419                         DbgPrint("Microsoft Ballpoint device detected");
420                         DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET");
421                         return MOUSE_TYPE_NONE;
422                 } else
423                 /* Sign for Microsoft Mouse protocol followed by button specifier */
424                 if (Buffer[i] == 'M')
425                 {
426                         if (i == 3)
427                         {
428                                 /* Overflow Error */
429                                 return MOUSE_TYPE_NONE;
430                         }
431                         switch (Buffer[i + 1])
432                         {
433                                 case '3':
434                                         DbgPrint("Microsoft Mouse with 3-buttons detected\n");
435                                         return MOUSE_TYPE_LOGITECH;
436                                 case 'Z':
437                                         DbgPrint("Microsoft Wheel Mouse detected\n");
438                                         return MOUSE_TYPE_WHEELZ;
439                                 /* case '2': */
440                                 default:
441                                         DbgPrint("Microsoft Mouse with 2-buttons detected\n");
442                                         return MOUSE_TYPE_MICROSOFT;
443                         }
444                 }
445         }
446
447         return MOUSE_TYPE_NONE;
448 }
449
450 PDEVICE_OBJECT
451 AllocatePointerDevice(PDRIVER_OBJECT DriverObject)
452 {
453         PDEVICE_OBJECT DeviceObject;
454         UNICODE_STRING DeviceName;
455         UNICODE_STRING SuffixString;
456         UNICODE_STRING SymlinkName;
457         PDEVICE_EXTENSION DeviceExtension;
458         ULONG Suffix;
459         NTSTATUS Status;
460
461         /* Allocate buffer for full device name */   
462         RtlInitUnicodeString(&DeviceName, NULL);
463         DeviceName.MaximumLength = sizeof(DD_MOUSE_DEVICE_NAME_U) + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
464         DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
465         RtlAppendUnicodeToString(&DeviceName, DD_MOUSE_DEVICE_NAME_U);
466
467         /* Allocate buffer for device name suffix */
468         RtlInitUnicodeString(&SuffixString, NULL);
469         SuffixString.MaximumLength = SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
470         SuffixString.Buffer = ExAllocatePool(PagedPool, SuffixString.MaximumLength);
471
472         /* Generate full qualified name with suffix */
473         for (Suffix = 0; Suffix < POINTER_PORTS_MAXIMUM; ++Suffix)
474         {
475                 RtlIntegerToUnicodeString(Suffix, 10, &SuffixString);
476                 RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
477                 Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
478                         &DeviceName, FILE_DEVICE_SERIAL_MOUSE_PORT, 0, TRUE, &DeviceObject);
479                 /* Device successfully created, leave the cyclus */
480                 if (NT_SUCCESS(Status))
481                         break;
482                 DeviceName.Length -= SuffixString.Length;
483         }
484  
485         ExFreePool(DeviceName.Buffer);
486
487         /* Couldn't create device */
488         if (!NT_SUCCESS(Status))
489         {
490                 ExFreePool(SuffixString.Buffer);
491                 return NULL;
492         }
493
494         DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
495
496 #ifdef SERMOUSE_MOUSESYMLINK_SUPPORT
497         /* Create symlink */
498         /* FIXME: Why? FiN 20/08/2003 */
499         RtlInitUnicodeString(&SymlinkName, NULL);
500         SymlinkName.MaximumLength = sizeof(L"\\??\\Mouse") + SUFFIX_MAXIMUM_SIZE + sizeof(UNICODE_NULL);
501         SymlinkName.Buffer = ExAllocatePool(PagedPool, SymlinkName.MaximumLength);
502         RtlAppendUnicodeToString(&SymlinkName, L"\\??\\Mouse");
503         RtlAppendUnicodeToString(&DeviceName, SuffixString.Buffer);
504         IoCreateSymbolicLink(&SymlinkName, &DeviceName);
505 #endif
506         ExFreePool(SuffixString.Buffer);
507
508         DeviceExtension = DeviceObject->DeviceExtension;
509         KeInitializeDpc(&DeviceExtension->IsrDpc, (PKDEFERRED_ROUTINE)SerialMouseIsrDpc, DeviceObject);
510
511         return DeviceObject;
512 }
513
514 BOOLEAN
515 InitializeMouse(ULONG Port, ULONG Irq, PDRIVER_OBJECT DriverObject)
516 {
517         PDEVICE_EXTENSION DeviceExtension;
518         PDEVICE_OBJECT DeviceObject;
519         ULONG MappedIrq;
520         KIRQL Dirql;
521         KAFFINITY Affinity;
522         ULONG MouseType;
523
524         /* Try to detect mouse on specified port */
525         InitializeSerialPort(Port, 2);
526         MouseType = DetectMicrosoftMouse(Port);
527
528         /* Enable interrupts */
529         WRITE_PORT_UCHAR((PUCHAR)(Port) + 1, 1);
530         ClearMouse(Port);
531
532         /* No mouse, no need to continue */
533         if (MouseType == MOUSE_TYPE_NONE)
534                 return FALSE;
535
536     /* Allocate new device */
537     DeviceObject = AllocatePointerDevice(DriverObject);
538     if (!DeviceObject)
539     {
540         DbgPrint("Oops, couldn't creat device object.\n");
541         return FALSE;
542     }
543     DeviceExtension = DeviceObject->DeviceExtension;
544
545     /* Setup device extension structure */
546         DeviceExtension->ActiveQueue = 0;
547         DeviceExtension->MouseType = MouseType;
548         DeviceExtension->MousePort = Port;
549         DeviceExtension->PacketBufferPosition = 0;
550         DeviceExtension->PreviousButtons = 0;
551 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
552         switch (MouseType)
553         {
554                 case MOUSE_TYPE_MICROSOFT:
555                         DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
556                         DeviceExtension->AttributesInformation.NumberOfButtons = 2;
557                         break;
558                 case MOUSE_TYPE_LOGITECH:
559                         DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
560                         DeviceExtension->AttributesInformation.NumberOfButtons = 3;
561                         break;
562                 case MOUSE_TYPE_WHEELZ:
563                         DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE;
564                         DeviceExtension->AttributesInformation.NumberOfButtons = 3;
565                         break;
566         };
567         DeviceExtension->AttributesInformation.SampleRate = 40;
568         DeviceExtension->AttributesInformation.InputDataQueueLength = MOUSE_BUFFER_SIZE;
569 #endif
570
571         MappedIrq = HalGetInterruptVector(Internal, 0, 0, Irq, &Dirql, &Affinity);
572
573         IoConnectInterrupt(
574                 &DeviceExtension->MouseInterrupt, SerialMouseInterruptService,
575                 DeviceObject, NULL, MappedIrq, Dirql, Dirql, 0, FALSE,
576                 Affinity, FALSE);               
577
578         return TRUE;
579 }
580
581 NTSTATUS STDCALL
582 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
583 {
584         BOOL MouseFound = FALSE;
585
586         DbgPrint("Serial Mouse Driver 0.0.8\n");
587 #ifdef SERMOUSE_COM1_SUPPORT
588         DbgPrint("Trying to find mouse on COM1\n");
589         MouseFound |= InitializeMouse(MOUSE_PORT_COM1, MOUSE_IRQ_COM1, DriverObject);
590 #endif
591 #ifdef SERMOUSE_COM2_SUPPORT
592         DbgPrint("Trying to find mouse on COM2\n");
593         MouseFound |= InitializeMouse(MOUSE_PORT_COM2, MOUSE_IRQ_COM2, DriverObject);
594 #endif
595
596         if (!MouseFound)
597         {
598                 DbgPrint("No serial mouse found.\n");
599                 return STATUS_UNSUCCESSFUL;
600         }
601
602         DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)SerialMouseDispatch;
603         DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)SerialMouseDispatch;
604         DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)SerialMouseInternalDeviceControl;
605         DriverObject->DriverStartIo = SerialMouseStartIo;
606
607         return STATUS_SUCCESS;
608 }