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)
7 * Technical information about mouse protocols can be found
8 * in the file sermouse.txt.
11 #include <ddk/ntddk.h>
12 #include <ddk/ntddmou.h>
15 * HAL:KdComPortInUse used to prevent detecting mouse on port
16 * that is occupied by kernel debugger.
18 ULONG DECLSPEC_IMPORT KdComPortInUse
;
21 * Compile time options
24 /* Support for the IOCTL_MOUSE_QUERY_ATTRIBUTES I/O control code */
25 #define SERMOUSE_QUERYATTRIBUTES_SUPPORT
26 /* Check for mouse on COM1? */
27 #define SERMOUSE_COM1_SUPPORT
28 /* Check for mouse on COM2? */
29 #define SERMOUSE_COM2_SUPPORT
30 /* Create \??\Mouse* symlink for device? */
31 #define SERMOUSE_MOUSESYMLINK_SUPPORT
37 #define MOUSE_IRQ_COM1 4
38 #define MOUSE_IRQ_COM2 3
39 #define MOUSE_PORT_COM1 0x3f8
40 #define MOUSE_PORT_COM2 0x2f8
42 /* Maximum value plus one for \Device\PointerClass* device name */
43 #define POINTER_PORTS_MAXIMUM 8
44 /* Letter count for POINTER_PORTS_MAXIMUM variable * sizeof(WCHAR) */
45 #define SUFFIX_MAXIMUM_SIZE (1 * sizeof(WCHAR))
48 #define MOUSE_TYPE_NONE 0
49 /* Microsoft Mouse with 2 buttons */
50 #define MOUSE_TYPE_MICROSOFT 1
51 /* Logitech Mouse with 3 buttons */
52 #define MOUSE_TYPE_LOGITECH 2
53 /* Microsoft Wheel Mouse (aka Z Mouse) */
54 #define MOUSE_TYPE_WHEELZ 3
55 /* Mouse Systems Mouse */
56 #define MOUSE_TYPE_MOUSESYSTEMS 4
58 /* Size for packet buffer used in interrupt routine */
59 #define PACKET_BUFFER_SIZE 4
61 /* Hardware byte mask for left button */
62 #define LEFT_BUTTON_MASK 0x20
63 /* Hardware to Microsoft specific code byte shift for left button */
64 #define LEFT_BUTTON_SHIFT 5
65 /* Hardware byte mask for right button */
66 #define RIGHT_BUTTON_MASK 0x10
67 /* Hardware to Microsoft specific code byte shift for right button */
68 #define RIGHT_BUTTON_SHIFT 3
69 /* Hardware byte mask for middle button */
70 #define MIDDLE_BUTTON_MASK 0x20
71 /* Hardware to Microsoft specific code byte shift for middle button */
72 #define MIDDLE_BUTTON_SHIFT 3
74 /* Microsoft byte mask for left button */
75 #define MOUSE_BUTTON_LEFT 0x01
76 /* Microsoft byte mask for right button */
77 #define MOUSE_BUTTON_RIGHT 0x02
78 /* Microsoft byte mask for middle button */
79 #define MOUSE_BUTTON_MIDDLE 0x04
85 typedef struct _DEVICE_EXTENSION
{
86 PDEVICE_OBJECT DeviceObject
;
88 ULONG InputDataCount
[2];
89 MOUSE_INPUT_DATA MouseInputData
[2][MOUSE_BUFFER_SIZE
];
90 CLASS_INFORMATION ClassInformation
;
91 PKINTERRUPT MouseInterrupt
;
95 UCHAR PacketBuffer
[PACKET_BUFFER_SIZE
];
96 ULONG PacketBufferPosition
;
97 ULONG PreviousButtons
;
98 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
99 MOUSE_ATTRIBUTES AttributesInformation
;
101 } DEVICE_EXTENSION
, *PDEVICE_EXTENSION
;
107 void ClearMouse(ULONG Port
)
109 /* Waits until the mouse calms down but also quits out after a while
110 * in case some destructive user wants to keep moving the mouse
111 * before we're done */
112 unsigned int Restarts
= 0, i
;
113 for (i
= 0; i
< 60000; i
++)
115 unsigned Temp
= READ_PORT_UCHAR((PUCHAR
)Port
);
119 if (Restarts
< 300000)
128 SerialMouseInterruptService(IN PKINTERRUPT Interrupt
, PVOID ServiceContext
)
130 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)ServiceContext
;
131 PDEVICE_EXTENSION DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
132 UCHAR
*PacketBuffer
= DeviceExtension
->PacketBuffer
;
133 ULONG MousePort
= DeviceExtension
->MousePort
;
134 UCHAR InterruptId
= READ_PORT_UCHAR((PUCHAR
)MousePort
+ 2);
137 PMOUSE_INPUT_DATA Input
;
138 ULONG ButtonsDifference
;
140 /* Is the interrupt for us? */
141 if ((InterruptId
& 0x01) == 0x01)
146 /* Not a Receive Data Available interrupt? */
147 if ((InterruptId
& 0x04) == 0)
152 /* Read all available data and process */
153 while ((READ_PORT_UCHAR((PUCHAR
)MousePort
+ 5) & 0x01) != 0)
155 RecievedByte
= READ_PORT_UCHAR((PUCHAR
)MousePort
);
158 if ((RecievedByte
& 0x40) == 0x40)
159 DeviceExtension
->PacketBufferPosition
= 0;
161 PacketBuffer
[DeviceExtension
->PacketBufferPosition
] =
162 (RecievedByte
& 0x7f);
163 ++DeviceExtension
->PacketBufferPosition
;
165 /* Process packet if complete */
166 if (DeviceExtension
->PacketBufferPosition
>= 3)
168 Queue
= DeviceExtension
->ActiveQueue
% 2;
170 /* Prevent buffer overflow */
171 if (DeviceExtension
->InputDataCount
[Queue
] == MOUSE_BUFFER_SIZE
)
174 Input
= &DeviceExtension
->MouseInputData
[Queue
][DeviceExtension
->InputDataCount
[Queue
]];
176 if (DeviceExtension
->PacketBufferPosition
== 3)
178 /* Retrieve change in x and y from packet */
179 Input
->LastX
= (signed char)(PacketBuffer
[1] | ((PacketBuffer
[0] & 0x03) << 6));
180 Input
->LastY
= (signed char)(PacketBuffer
[2] | ((PacketBuffer
[0] & 0x0c) << 4));
182 /* Determine the current state of the buttons */
183 Input
->RawButtons
= (DeviceExtension
->PreviousButtons
& MOUSE_BUTTON_MIDDLE
) |
184 ((UCHAR
)(PacketBuffer
[0] & LEFT_BUTTON_MASK
) >> LEFT_BUTTON_SHIFT
) |
185 ((UCHAR
)(PacketBuffer
[0] & RIGHT_BUTTON_MASK
) >> RIGHT_BUTTON_SHIFT
);
187 if (DeviceExtension
->PacketBufferPosition
== 4)
189 DeviceExtension
->PacketBufferPosition
= 0;
190 /* If middle button state changed than report event */
191 if (((UCHAR
)(PacketBuffer
[3] & MIDDLE_BUTTON_MASK
) >> MIDDLE_BUTTON_SHIFT
) ^
192 (DeviceExtension
->PreviousButtons
& MOUSE_BUTTON_MIDDLE
))
194 Input
->RawButtons
^= MOUSE_BUTTON_MIDDLE
;
204 /* Determine ButtonFlags */
205 Input
->ButtonFlags
= 0;
206 ButtonsDifference
= DeviceExtension
->PreviousButtons
^ Input
->RawButtons
;
208 if (ButtonsDifference
!= 0)
210 if (ButtonsDifference
& MOUSE_BUTTON_LEFT
)
212 if (Input
->RawButtons
& MOUSE_BUTTON_LEFT
)
213 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_DOWN
;
215 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_UP
;
217 if (ButtonsDifference
& MOUSE_BUTTON_RIGHT
)
219 if (Input
->RawButtons
& MOUSE_BUTTON_RIGHT
)
220 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_DOWN
;
222 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_UP
;
224 if (ButtonsDifference
& MOUSE_BUTTON_MIDDLE
)
226 if (Input
->RawButtons
& MOUSE_BUTTON_MIDDLE
)
227 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_DOWN
;
229 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_UP
;
233 /* Send the Input data to the Mouse Class driver */
234 DeviceExtension
->InputDataCount
[Queue
]++;
235 KeInsertQueueDpc(&DeviceExtension
->IsrDpc
, DeviceObject
->CurrentIrp
, NULL
);
237 /* Copy RawButtons to Previous Buttons for Input */
238 DeviceExtension
->PreviousButtons
= Input
->RawButtons
;
246 SerialMouseInitializeDataQueue(PVOID Context
)
251 MouseSynchronizeRoutine(PVOID Context
)
257 SerialMouseStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
259 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
261 if (KeSynchronizeExecution(DeviceExtension
->MouseInterrupt
, MouseSynchronizeRoutine
, Irp
))
264 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
265 Irp
->IoStatus
.Information
= 0;
266 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
267 oldIrql
= KeGetCurrentIrql();
268 if (oldIrql
< DISPATCH_LEVEL
)
270 KeRaiseIrql(DISPATCH_LEVEL
, &oldIrql
);
271 IoStartNextPacket(DeviceObject
, FALSE
);
272 KeLowerIrql(oldIrql
);
276 IoStartNextPacket (DeviceObject
, FALSE
);
282 SerialMouseInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
284 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
285 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
288 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
290 case IOCTL_INTERNAL_MOUSE_CONNECT
:
291 DeviceExtension
->ClassInformation
=
292 *((PCLASS_INFORMATION
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
294 /* Reinitialize the port input data queue synchronously */
295 KeSynchronizeExecution(DeviceExtension
->MouseInterrupt
,
296 (PKSYNCHRONIZE_ROUTINE
)SerialMouseInitializeDataQueue
,
299 Status
= STATUS_SUCCESS
;
302 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
303 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
304 if (Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
>= sizeof(MOUSE_ATTRIBUTES
))
306 *(PMOUSE_ATTRIBUTES
)Irp
->AssociatedIrp
.SystemBuffer
=
307 DeviceExtension
->AttributesInformation
;
308 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
309 Status
= STATUS_SUCCESS
;
311 Status
= STATUS_BUFFER_TOO_SMALL
;
317 Status
= STATUS_INVALID_DEVICE_REQUEST
;
321 Irp
->IoStatus
.Status
= Status
;
322 if (Status
== STATUS_PENDING
)
324 IoMarkIrpPending(Irp
);
325 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
329 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
336 SerialMouseDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
338 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
341 switch (Stack
->MajorFunction
)
345 Status
= STATUS_SUCCESS
;
349 DbgPrint("NOT IMPLEMENTED\n");
350 Status
= STATUS_NOT_IMPLEMENTED
;
354 if (Status
== STATUS_PENDING
)
356 IoMarkIrpPending(Irp
);
360 Irp
->IoStatus
.Status
= Status
;
361 Irp
->IoStatus
.Information
= 0;
362 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
368 VOID
SerialMouseIsrDpc(PKDPC Dpc
, PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID Context
)
370 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
373 Queue
= DeviceExtension
->ActiveQueue
% 2;
374 InterlockedIncrement(&DeviceExtension
->ActiveQueue
);
375 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassInformation
.CallBack
)(
376 DeviceExtension
->ClassInformation
.DeviceObject
,
377 DeviceExtension
->MouseInputData
[Queue
],
379 &DeviceExtension
->InputDataCount
[Queue
]);
381 DeviceExtension
->InputDataCount
[Queue
] = 0;
384 void InitializeSerialPort(ULONG Port
)
387 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 3, 0);
388 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 2, 0); /* FCR: disable FIFO */
389 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 1, 0); /* IER: disable ints */
391 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 3, 0x80);
392 /* Set serial port speed */
393 WRITE_PORT_UCHAR((PUCHAR
)Port
, 0x60);
394 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 1, 0);
395 /* Set DLAB off and set LCR */
396 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 3, 2);
399 BOOL
UARTReadChar(ULONG Port
, CHAR
*Value
, ULONG Timeout
)
403 for (i
= 0; i
< Timeout
; i
++)
405 for (j
= 0; j
< 1000; j
++)
407 /* Is there a character ready? */
408 if (READ_PORT_UCHAR((PUCHAR
)Port
+ 5) & 0x01)
410 /* Yes, read it and return */
411 *Value
= READ_PORT_UCHAR((PUCHAR
)Port
);
417 KeStallExecutionProcessor(1);
425 ULONG
DetectMicrosoftMouse(ULONG Port
)
431 /* Save original LCR/MCR */
432 LCR
= READ_PORT_UCHAR((PUCHAR
)Port
+ 3); /* LCR (line ctrl reg) */
433 MCR
= READ_PORT_UCHAR((PUCHAR
)Port
+ 4); /* MCR (modem ctrl reg) */
436 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 4, 0); /* MCR: DTR/RTS/OUT2 off */
438 /* Set communications parameters */
439 InitializeSerialPort(Port
);
441 /* Flush receive buffer */
442 (void) READ_PORT_UCHAR((PUCHAR
)Port
);
443 /* right? -> wait two ticks (approx 1/9 sec) */
444 KeStallExecutionProcessor(100000);
446 /* Enable DTR/RTS (OUT2 disabled) */
447 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 4, 3);
449 if (UARTReadChar(Port
, &Buffer
[0], 500))
454 if (UARTReadChar(Port
, &Buffer
[Count
], 100))
461 return MOUSE_TYPE_NONE
;
463 /* Restore LCR/MCR */
464 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 3, LCR
); /* LCR (line ctrl reg) */
465 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 4, MCR
); /* MCR (modem ctrl reg) */
467 for (i
= 0; i
< Count
; ++i
)
469 /* Sign for Microsoft Ballpoint */
470 if (Buffer
[i
] == 'B')
472 DbgPrint("Microsoft Ballpoint device detected");
473 DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET");
474 return MOUSE_TYPE_NONE
;
476 /* Sign for Microsoft Mouse protocol followed by button specifier */
477 if (Buffer
[i
] == 'M')
482 return MOUSE_TYPE_NONE
;
484 switch (Buffer
[i
+ 1])
487 DbgPrint("Microsoft Mouse with 3-buttons detected\n");
488 return MOUSE_TYPE_LOGITECH
;
490 DbgPrint("Microsoft Wheel Mouse detected\n");
491 return MOUSE_TYPE_WHEELZ
;
494 DbgPrint("Microsoft Mouse with 2-buttons detected\n");
495 return MOUSE_TYPE_MICROSOFT
;
500 return MOUSE_TYPE_NONE
;
504 AllocatePointerDevice(PDRIVER_OBJECT DriverObject
)
506 PDEVICE_OBJECT DeviceObject
;
507 UNICODE_STRING DeviceName
;
508 UNICODE_STRING SuffixString
;
509 UNICODE_STRING SymlinkName
;
510 PDEVICE_EXTENSION DeviceExtension
;
514 /* Allocate buffer for full device name */
515 RtlInitUnicodeString(&DeviceName
, NULL
);
516 DeviceName
.MaximumLength
= sizeof(DD_MOUSE_DEVICE_NAME_U
) + SUFFIX_MAXIMUM_SIZE
+ sizeof(UNICODE_NULL
);
517 DeviceName
.Buffer
= ExAllocatePool(PagedPool
, DeviceName
.MaximumLength
);
518 RtlAppendUnicodeToString(&DeviceName
, DD_MOUSE_DEVICE_NAME_U
);
520 /* Allocate buffer for device name suffix */
521 RtlInitUnicodeString(&SuffixString
, NULL
);
522 SuffixString
.MaximumLength
= SUFFIX_MAXIMUM_SIZE
+ sizeof(UNICODE_NULL
);
523 SuffixString
.Buffer
= ExAllocatePool(PagedPool
, SuffixString
.MaximumLength
);
525 /* Generate full qualified name with suffix */
526 for (Suffix
= 0; Suffix
< POINTER_PORTS_MAXIMUM
; ++Suffix
)
528 RtlIntegerToUnicodeString(Suffix
, 10, &SuffixString
);
529 RtlAppendUnicodeToString(&DeviceName
, SuffixString
.Buffer
);
530 Status
= IoCreateDevice(DriverObject
, sizeof(DEVICE_EXTENSION
),
531 &DeviceName
, FILE_DEVICE_SERIAL_MOUSE_PORT
, 0, TRUE
, &DeviceObject
);
532 /* Device successfully created, leave the cyclus */
533 if (NT_SUCCESS(Status
))
535 DeviceName
.Length
-= SuffixString
.Length
;
538 ExFreePool(DeviceName
.Buffer
);
540 /* Couldn't create device */
541 if (!NT_SUCCESS(Status
))
543 ExFreePool(SuffixString
.Buffer
);
547 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
549 #ifdef SERMOUSE_MOUSESYMLINK_SUPPORT
551 /* FIXME: Why? FiN 20/08/2003 */
552 RtlInitUnicodeString(&SymlinkName
, NULL
);
553 SymlinkName
.MaximumLength
= sizeof(L
"\\??\\Mouse") + SUFFIX_MAXIMUM_SIZE
+ sizeof(UNICODE_NULL
);
554 SymlinkName
.Buffer
= ExAllocatePool(PagedPool
, SymlinkName
.MaximumLength
);
555 RtlAppendUnicodeToString(&SymlinkName
, L
"\\??\\Mouse");
556 RtlAppendUnicodeToString(&DeviceName
, SuffixString
.Buffer
);
557 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
559 ExFreePool(SuffixString
.Buffer
);
561 DeviceExtension
= DeviceObject
->DeviceExtension
;
562 KeInitializeDpc(&DeviceExtension
->IsrDpc
, (PKDEFERRED_ROUTINE
)SerialMouseIsrDpc
, DeviceObject
);
568 InitializeMouse(ULONG Port
, ULONG Irq
, PDRIVER_OBJECT DriverObject
)
570 PDEVICE_EXTENSION DeviceExtension
;
571 PDEVICE_OBJECT DeviceObject
;
577 /* Don't detect mouse on port that is occupied by kernel debugger */
578 if (KdComPortInUse
== Port
)
581 /* Try to detect mouse on specified port */
582 MouseType
= DetectMicrosoftMouse(Port
);
584 /* No mouse, no need to continue */
585 if (MouseType
== MOUSE_TYPE_NONE
)
590 /* Enable interrupts */
591 WRITE_PORT_UCHAR((PUCHAR
)(Port
) + 1, 1);
595 /* Enable RTS, DTR and OUT2 */
596 WRITE_PORT_UCHAR((PUCHAR
)Port
+ 4, 0x0b);
598 /* Allocate new device */
599 DeviceObject
= AllocatePointerDevice(DriverObject
);
602 DbgPrint("Oops, couldn't creat device object.\n");
606 DeviceExtension
= DeviceObject
->DeviceExtension
;
608 /* Setup device extension structure */
609 DeviceExtension
->ActiveQueue
= 0;
610 DeviceExtension
->MouseType
= MouseType
;
611 DeviceExtension
->MousePort
= Port
;
612 DeviceExtension
->PacketBufferPosition
= 0;
613 DeviceExtension
->PreviousButtons
= 0;
614 #ifdef SERMOUSE_QUERYATTRIBUTES_SUPPORT
617 case MOUSE_TYPE_MICROSOFT
:
618 DeviceExtension
->AttributesInformation
.MouseIdentifier
= MOUSE_SERIAL_HARDWARE
;
619 DeviceExtension
->AttributesInformation
.NumberOfButtons
= 2;
621 case MOUSE_TYPE_LOGITECH
:
622 DeviceExtension
->AttributesInformation
.MouseIdentifier
= MOUSE_SERIAL_HARDWARE
;
623 DeviceExtension
->AttributesInformation
.NumberOfButtons
= 3;
625 case MOUSE_TYPE_WHEELZ
:
626 DeviceExtension
->AttributesInformation
.MouseIdentifier
= WHEELMOUSE_SERIAL_HARDWARE
;
627 DeviceExtension
->AttributesInformation
.NumberOfButtons
= 3;
630 DeviceExtension
->AttributesInformation
.SampleRate
= 40;
631 DeviceExtension
->AttributesInformation
.InputDataQueueLength
= MOUSE_BUFFER_SIZE
;
634 MappedIrq
= HalGetInterruptVector(Internal
, 0, 0, Irq
, &Dirql
, &Affinity
);
637 &DeviceExtension
->MouseInterrupt
, SerialMouseInterruptService
,
638 DeviceObject
, NULL
, MappedIrq
, Dirql
, Dirql
, 0, FALSE
,
645 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
647 BOOL MouseFound
= FALSE
;
649 DbgPrint("Serial Mouse Driver 0.0.9\n");
650 #ifdef SERMOUSE_COM1_SUPPORT
651 DbgPrint("Trying to find mouse on COM1\n");
652 MouseFound
|= InitializeMouse(MOUSE_PORT_COM1
, MOUSE_IRQ_COM1
, DriverObject
);
654 #ifdef SERMOUSE_COM2_SUPPORT
655 DbgPrint("Trying to find mouse on COM2\n");
656 MouseFound
|= InitializeMouse(MOUSE_PORT_COM2
, MOUSE_IRQ_COM2
, DriverObject
);
661 DbgPrint("No serial mouse found.\n");
662 return STATUS_UNSUCCESSFUL
;
665 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = (PDRIVER_DISPATCH
)SerialMouseDispatch
;
666 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = (PDRIVER_DISPATCH
)SerialMouseDispatch
;
667 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = (PDRIVER_DISPATCH
)SerialMouseInternalDeviceControl
;
668 DriverObject
->DriverStartIo
= SerialMouseStartIo
;
670 return STATUS_SUCCESS
;