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 "../include/mouse.h"
18 BOOLEAN AlreadyOpened
= FALSE
;
20 BOOLEAN
MouseClassCallBack(PDEVICE_OBJECT ClassDeviceObject
, PMOUSE_INPUT_DATA MouseDataStart
,
21 PMOUSE_INPUT_DATA MouseDataEnd
, PULONG InputCount
)
23 PDEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
26 PIO_STACK_LOCATION Stack
;
28 // In classical NT, you would take the input data and pipe it through the IO system, for the GDI to read.
29 // In ReactOS, however, we use a GDI callback for increased mouse responsiveness. The reason we don't
30 // simply call from the port driver is so that our mouse class driver can support NT mouse port drivers.
32 /* if(ClassDeviceExtension->ReadIsPending == TRUE)
34 Irp = ClassDeviceObject->CurrentIrp;
35 ClassDeviceObject->CurrentIrp = NULL;
36 Stack = IoGetCurrentIrpStackLocation(Irp);
38 ReadSize = sizeof(MOUSE_INPUT_DATA) * (*InputCount);
40 // A read request is waiting for input, so go straight to it
41 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)MouseDataStart, ReadSize);
43 // Go to next packet and complete this request with STATUS_SUCCESS
44 Irp->IoStatus.Status = STATUS_SUCCESS;
45 Irp->IoStatus.Information = ReadSize;
46 Stack->Parameters.Read.Length = ReadSize;
48 IoStartNextPacket(ClassDeviceObject, FALSE);
49 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
50 ClassDeviceExtension->ReadIsPending = FALSE;
53 // If we have data from the port driver and a higher service to send the data to
54 if((*InputCount
>0) && (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
!= NULL
))
56 if(ClassDeviceExtension
->InputCount
+ *InputCount
> MOUSE_BUFFER_SIZE
)
58 ReadSize
= MOUSE_BUFFER_SIZE
- ClassDeviceExtension
->InputCount
;
60 ReadSize
= *InputCount
;
63 // FIXME: If we exceed the buffer, mouse data gets thrown away.. better solution?
66 // Move the mouse input data from the port data queue to our class data queue
67 RtlMoveMemory(ClassDeviceExtension
->PortData
, (PCHAR
)MouseDataStart
,
68 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
70 // Move the pointer and counter up
71 ClassDeviceExtension
->PortData
+= ReadSize
;
72 ClassDeviceExtension
->InputCount
+= ReadSize
;
74 // Throw data up to GDI callback
75 if(*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
!= NULL
) {
76 DbgPrint("MouseClassCallBack() Calling GDI callback at %p\n", ClassDeviceExtension
->GDIInformation
.CallBack
);
77 (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
)
78 (ClassDeviceExtension
->PortData
- ReadSize
, ReadSize
);
80 DbgPrint("MouseClassCallBack() NO GDI callback installed\n");
83 ClassDeviceExtension
->PortData
-= ReadSize
;
84 ClassDeviceExtension
->InputCount
-= ReadSize
;
85 ClassDeviceExtension
->ReadIsPending
= FALSE
;
87 DbgPrint("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount
);
93 NTSTATUS
ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject
)
95 PDEVICE_OBJECT PortDeviceObject
= NULL
;
96 PFILE_OBJECT FileObject
= NULL
;
98 UNICODE_STRING PortName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\Mouse");
99 IO_STATUS_BLOCK ioStatus
;
102 CLASS_INFORMATION ClassInformation
;
103 PDEVICE_EXTENSION DeviceExtension
= ClassDeviceObject
->DeviceExtension
;
105 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
107 // Get the port driver's DeviceObject
108 // FIXME: The name might change.. find a way to be more dynamic?
110 status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
112 if(status
!= STATUS_SUCCESS
)
114 DbgPrint("MOUCLASS: Could not connect to mouse port driver\n");
118 DeviceExtension
->PortDeviceObject
= PortDeviceObject
;
119 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, MOUSE_BUFFER_SIZE
* sizeof(MOUSE_INPUT_DATA
));
120 DeviceExtension
->InputCount
= 0;
121 DeviceExtension
->ReadIsPending
= FALSE
;
123 // Connect our callback to the port driver
125 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
127 ClassInformation
.DeviceObject
= ClassDeviceObject
;
128 ClassInformation
.CallBack
= MouseClassCallBack
;
130 irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
131 PortDeviceObject
, &ClassInformation
, sizeof(CLASS_INFORMATION
), NULL
, 0, TRUE
, &event
, &ioStatus
);
133 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
135 if (status
== STATUS_PENDING
) {
136 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
138 ioStatus
.Status
= status
;
141 return ioStatus
.Status
;
144 NTSTATUS STDCALL
MouseClassDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
146 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
149 switch (Stack
->MajorFunction
)
152 if (AlreadyOpened
== TRUE
)
154 Status
= STATUS_SUCCESS
;
158 Status
= STATUS_SUCCESS
;
159 AlreadyOpened
= TRUE
;
164 Status
= STATUS_SUCCESS
;
169 if (Stack
->Parameters
.Read
.Length
== 0) {
170 Status
= STATUS_SUCCESS
;
172 Status
= STATUS_PENDING
;
177 DbgPrint("NOT IMPLEMENTED\n");
178 Status
= STATUS_NOT_IMPLEMENTED
;
182 Irp
->IoStatus
.Status
= Status
;
183 Irp
->IoStatus
.Information
= 0;
184 if (Status
==STATUS_PENDING
)
186 IoMarkIrpPending(Irp
);
187 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
189 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
194 VOID
MouseClassStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
196 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
197 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
200 if(DeviceExtension
->InputCount
>0)
202 // FIXME: We should not send too much input data.. depends on the max buffer size of the win32k
203 ReadSize
= DeviceExtension
->InputCount
* sizeof(MOUSE_INPUT_DATA
);
205 // Bring the PortData back to base so that it can be copied
206 DeviceExtension
->PortData
-= DeviceExtension
->InputCount
;
207 DeviceExtension
->InputCount
= 0;
208 DeviceExtension
->ReadIsPending
= FALSE
;
210 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
, (PCHAR
)DeviceExtension
->PortData
, ReadSize
);
212 // Go to next packet and complete this request with STATUS_SUCCESS
213 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
215 Irp
->IoStatus
.Information
= ReadSize
;
216 Stack
->Parameters
.Read
.Length
= ReadSize
;
218 IoStartNextPacket(DeviceObject
, FALSE
);
219 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
221 DeviceExtension
->ReadIsPending
= TRUE
;
225 NTSTATUS STDCALL
MouseClassInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
227 // Retrieve GDI's callback
229 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
230 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
233 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
235 case IOCTL_INTERNAL_MOUSE_CONNECT
:
237 DeviceExtension
->GDIInformation
=
238 *((PGDI_INFORMATION
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
240 DbgPrint("MouseClassInternalDeviceControl() installed GDI callback at %p\n", DeviceExtension
->GDIInformation
.CallBack
);
242 status
= STATUS_SUCCESS
;
245 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
247 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
249 status
= STATUS_SUCCESS
;
253 status
= STATUS_INVALID_DEVICE_REQUEST
;
257 Irp
->IoStatus
.Status
= status
;
258 if (status
== STATUS_PENDING
) {
259 IoMarkIrpPending(Irp
);
260 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
262 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
269 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
271 PDEVICE_OBJECT DeviceObject
;
272 UNICODE_STRING DeviceName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\MouseClass");
273 UNICODE_STRING SymlinkName
= UNICODE_STRING_INITIALIZER(L
"\\??\\MouseClass");
275 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouseClassDispatch
;
276 // DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch;
277 // DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch;
278 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouseClassInternalDeviceControl
; // to get GDI callback
279 // DriverObject->DriverStartIo = MouseClassStartIo;
281 IoCreateDevice(DriverObject
,
282 sizeof(DEVICE_EXTENSION
),
288 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
290 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
292 return ConnectMousePortDriver(DeviceObject
);