3 ** Mouse class driver 0.0.1
4 ** Written by Jason Filby (jasonfilby@yahoo.com)
5 ** For ReactOS (www.reactos.com)
7 ** The class driver between win32k and the various mouse port drivers
9 ** TODO: Change interface to win32k to a callback instead of ReadFile IO
10 Add support for multiple port devices
14 #include <ddk/ntddk.h>
15 #include <ddk/ntddmou.h>
21 BOOLEAN AlreadyOpened
= FALSE
;
23 VOID
MouseClassPassiveCallback(PDEVICE_OBJECT ClassDeviceObject
, PVOID Context
)
25 PDEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
26 MOUSE_INPUT_DATA PortData
[MOUSE_BUFFER_SIZE
];
30 assert(NULL
!= ClassDeviceExtension
->GDIInformation
.CallBack
);
31 KeAcquireSpinLock(&(ClassDeviceExtension
->SpinLock
), &OldIrql
);
32 DPRINT("Entering MouseClassPassiveCallback\n");
33 while (0 != ClassDeviceExtension
->InputCount
) {
34 ClassDeviceExtension
->PortData
-= ClassDeviceExtension
->InputCount
;
35 RtlMoveMemory(PortData
, ClassDeviceExtension
->PortData
,
36 ClassDeviceExtension
->InputCount
* sizeof(MOUSE_INPUT_DATA
));
37 InputCount
= ClassDeviceExtension
->InputCount
;
38 ClassDeviceExtension
->InputCount
= 0;
39 KeReleaseSpinLock(&(ClassDeviceExtension
->SpinLock
), OldIrql
);
41 DPRINT("MouseClassPassiveCallBack() Calling GDI callback at %p\n",
42 ClassDeviceExtension
->GDIInformation
.CallBack
);
43 /* We're jumping through hoops to get to run at PASSIVE_LEVEL, let's make
45 ASSERT_IRQL(PASSIVE_LEVEL
);
46 (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
)
47 (PortData
, InputCount
);
49 KeAcquireSpinLock(&(ClassDeviceExtension
->SpinLock
), &OldIrql
);
52 ClassDeviceExtension
->PassiveCallbackQueued
= FALSE
;
53 DPRINT("Leaving MouseClassPassiveCallback\n");
54 KeReleaseSpinLock(&(ClassDeviceExtension
->SpinLock
), OldIrql
);
57 BOOLEAN
MouseClassCallBack(PDEVICE_OBJECT ClassDeviceObject
, PMOUSE_INPUT_DATA MouseDataStart
,
58 PMOUSE_INPUT_DATA MouseDataEnd
, PULONG InputCount
)
60 PDEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
63 PIO_STACK_LOCATION Stack
;
66 // In classical NT, you would take the input data and pipe it through the IO system, for the GDI to read.
67 // In ReactOS, however, we use a GDI callback for increased mouse responsiveness. The reason we don't
68 // simply call from the port driver is so that our mouse class driver can support NT mouse port drivers.
70 DPRINT("Entering MouseClassCallBack\n");
71 /* if(ClassDeviceExtension->ReadIsPending == TRUE)
73 Irp = ClassDeviceObject->CurrentIrp;
74 ClassDeviceObject->CurrentIrp = NULL;
75 Stack = IoGetCurrentIrpStackLocation(Irp);
77 ReadSize = sizeof(MOUSE_INPUT_DATA) * (*InputCount);
79 // A read request is waiting for input, so go straight to it
80 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)MouseDataStart, ReadSize);
82 // Go to next packet and complete this request with STATUS_SUCCESS
83 Irp->IoStatus.Status = STATUS_SUCCESS;
84 Irp->IoStatus.Information = ReadSize;
85 Stack->Parameters.Read.Length = ReadSize;
87 IoStartNextPacket(ClassDeviceObject, FALSE);
88 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
89 ClassDeviceExtension->ReadIsPending = FALSE;
92 // If we have data from the port driver and a higher service to send the data to
93 if((*InputCount
>0) && (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
!= NULL
))
95 KeAcquireSpinLock(&(ClassDeviceExtension
->SpinLock
), &OldIrql
);
97 if(ClassDeviceExtension
->InputCount
+ *InputCount
> MOUSE_BUFFER_SIZE
)
99 ReadSize
= MOUSE_BUFFER_SIZE
- ClassDeviceExtension
->InputCount
;
101 ReadSize
= *InputCount
;
104 // FIXME: If we exceed the buffer, mouse data gets thrown away.. better solution?
107 // Move the mouse input data from the port data queue to our class data queue
108 RtlMoveMemory(ClassDeviceExtension
->PortData
, (PCHAR
)MouseDataStart
,
109 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
111 // Move the pointer and counter up
112 ClassDeviceExtension
->PortData
+= ReadSize
;
113 ClassDeviceExtension
->InputCount
+= ReadSize
;
115 if(*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
!= NULL
) {
116 if (! ClassDeviceExtension
->PassiveCallbackQueued
) {
117 if (NULL
== ClassDeviceExtension
->WorkItem
) {
118 ClassDeviceExtension
->WorkItem
= IoAllocateWorkItem(ClassDeviceObject
);
120 if (NULL
!= ClassDeviceExtension
->WorkItem
) {
121 DPRINT("Queueing workitem\n");
122 IoQueueWorkItem(ClassDeviceExtension
->WorkItem
, MouseClassPassiveCallback
, CriticalWorkQueue
, NULL
);
123 ClassDeviceExtension
->PassiveCallbackQueued
= TRUE
;
127 DPRINT("MouseClassCallBack() NO GDI callback installed\n");
129 KeReleaseSpinLock(&(ClassDeviceExtension
->SpinLock
), OldIrql
);
131 DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount
);
134 DPRINT("Leaving MouseClassCallBack\n");
138 NTSTATUS
ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject
)
140 PDEVICE_OBJECT PortDeviceObject
= NULL
;
141 PFILE_OBJECT FileObject
= NULL
;
143 UNICODE_STRING PortName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\PointerClass0");
144 IO_STATUS_BLOCK ioStatus
;
147 CLASS_INFORMATION ClassInformation
;
148 PDEVICE_EXTENSION DeviceExtension
= ClassDeviceObject
->DeviceExtension
;
150 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
152 // Get the port driver's DeviceObject
153 // FIXME: The name might change.. find a way to be more dynamic?
155 status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
157 if(status
!= STATUS_SUCCESS
)
159 DPRINT("MOUCLASS: Could not connect to mouse port driver\n");
160 DPRINT("Status: %x\n", status
);
164 DeviceExtension
->PortDeviceObject
= PortDeviceObject
;
165 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, MOUSE_BUFFER_SIZE
* sizeof(MOUSE_INPUT_DATA
));
166 DeviceExtension
->InputCount
= 0;
167 DeviceExtension
->ReadIsPending
= FALSE
;
168 DeviceExtension
->WorkItem
= NULL
;
169 KeInitializeSpinLock(&(DeviceExtension
->SpinLock
));
170 DeviceExtension
->PassiveCallbackQueued
= FALSE
;
172 // Connect our callback to the port driver
174 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
176 ClassInformation
.DeviceObject
= ClassDeviceObject
;
177 ClassInformation
.CallBack
= MouseClassCallBack
;
179 irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
180 PortDeviceObject
, &ClassInformation
, sizeof(CLASS_INFORMATION
), NULL
, 0, TRUE
, &event
, &ioStatus
);
182 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
184 if (status
== STATUS_PENDING
) {
185 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
187 ioStatus
.Status
= status
;
190 return ioStatus
.Status
;
193 NTSTATUS STDCALL_FUNC
MouseClassDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
195 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
198 switch (Stack
->MajorFunction
)
201 if (AlreadyOpened
== TRUE
)
203 Status
= STATUS_SUCCESS
;
207 Status
= STATUS_SUCCESS
;
208 AlreadyOpened
= TRUE
;
213 Status
= STATUS_SUCCESS
;
218 if (Stack
->Parameters
.Read
.Length
== 0) {
219 Status
= STATUS_SUCCESS
;
221 Status
= STATUS_PENDING
;
226 DPRINT1("NOT IMPLEMENTED\n");
227 Status
= STATUS_NOT_IMPLEMENTED
;
231 Irp
->IoStatus
.Status
= Status
;
232 Irp
->IoStatus
.Information
= 0;
233 if (Status
==STATUS_PENDING
)
235 IoMarkIrpPending(Irp
);
236 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
238 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
243 VOID
MouseClassStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
245 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
246 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
249 if(DeviceExtension
->InputCount
>0)
251 // FIXME: We should not send too much input data.. depends on the max buffer size of the win32k
252 ReadSize
= DeviceExtension
->InputCount
* sizeof(MOUSE_INPUT_DATA
);
254 // Bring the PortData back to base so that it can be copied
255 DeviceExtension
->PortData
-= DeviceExtension
->InputCount
;
256 DeviceExtension
->InputCount
= 0;
257 DeviceExtension
->ReadIsPending
= FALSE
;
259 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
, (PCHAR
)DeviceExtension
->PortData
, ReadSize
);
261 // Go to next packet and complete this request with STATUS_SUCCESS
262 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
264 Irp
->IoStatus
.Information
= ReadSize
;
265 Stack
->Parameters
.Read
.Length
= ReadSize
;
267 IoStartNextPacket(DeviceObject
, FALSE
);
268 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
270 DeviceExtension
->ReadIsPending
= TRUE
;
274 NTSTATUS STDCALL_FUNC
MouseClassInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
276 // Retrieve GDI's callback
278 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
279 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
282 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
284 case IOCTL_INTERNAL_MOUSE_CONNECT
:
286 DeviceExtension
->GDIInformation
=
287 *((PGDI_INFORMATION
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
289 DPRINT("MouseClassInternalDeviceControl() installed GDI callback at %p\n", DeviceExtension
->GDIInformation
.CallBack
);
291 status
= STATUS_SUCCESS
;
294 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
296 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
298 status
= STATUS_SUCCESS
;
302 status
= STATUS_INVALID_DEVICE_REQUEST
;
306 Irp
->IoStatus
.Status
= status
;
307 if (status
== STATUS_PENDING
) {
308 IoMarkIrpPending(Irp
);
309 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
311 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
318 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
320 PDEVICE_OBJECT DeviceObject
;
321 UNICODE_STRING DeviceName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\MouseClass");
322 UNICODE_STRING SymlinkName
= UNICODE_STRING_INITIALIZER(L
"\\??\\MouseClass"); NTSTATUS Status
;
325 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = (PDRIVER_DISPATCH
)MouseClassDispatch
;
326 // DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)MouseClassDispatch;
327 // DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)MouseClassDispatch;
328 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = (PDRIVER_DISPATCH
)MouseClassInternalDeviceControl
; // to get GDI callback
329 // DriverObject->DriverStartIo = (PDRIVER_STARTIO)MouseClassStartIo;
331 Status
= IoCreateDevice(DriverObject
,
332 sizeof(DEVICE_EXTENSION
),
338 if (!NT_SUCCESS(Status
))
342 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
344 Status
= IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
345 if (!NT_SUCCESS(Status
))
347 IoDeleteDevice(DeviceObject
);
351 Status
= ConnectMousePortDriver(DeviceObject
);
352 if (!NT_SUCCESS(Status
))
354 IoDeleteSymbolicLink(&SymlinkName
);
355 IoDeleteDevice(DeviceObject
);
358 return(STATUS_SUCCESS
);