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"
21 BOOLEAN AlreadyOpened
= FALSE
;
23 BOOLEAN
MouseClassCallBack(PDEVICE_OBJECT ClassDeviceObject
, PMOUSE_INPUT_DATA MouseDataStart
,
24 PMOUSE_INPUT_DATA MouseDataEnd
, PULONG InputCount
)
26 PDEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
29 PIO_STACK_LOCATION Stack
;
31 // In classical NT, you would take the input data and pipe it through the IO system, for the GDI to read.
32 // In ReactOS, however, we use a GDI callback for increased mouse responsiveness. The reason we don't
33 // simply call from the port driver is so that our mouse class driver can support NT mouse port drivers.
35 /* if(ClassDeviceExtension->ReadIsPending == TRUE)
37 Irp = ClassDeviceObject->CurrentIrp;
38 ClassDeviceObject->CurrentIrp = NULL;
39 Stack = IoGetCurrentIrpStackLocation(Irp);
41 ReadSize = sizeof(MOUSE_INPUT_DATA) * (*InputCount);
43 // A read request is waiting for input, so go straight to it
44 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)MouseDataStart, ReadSize);
46 // Go to next packet and complete this request with STATUS_SUCCESS
47 Irp->IoStatus.Status = STATUS_SUCCESS;
48 Irp->IoStatus.Information = ReadSize;
49 Stack->Parameters.Read.Length = ReadSize;
51 IoStartNextPacket(ClassDeviceObject, FALSE);
52 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
53 ClassDeviceExtension->ReadIsPending = FALSE;
56 // If we have data from the port driver and a higher service to send the data to
57 if((*InputCount
>0) && (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
!= NULL
))
59 if(ClassDeviceExtension
->InputCount
+ *InputCount
> MOUSE_BUFFER_SIZE
)
61 ReadSize
= MOUSE_BUFFER_SIZE
- ClassDeviceExtension
->InputCount
;
63 ReadSize
= *InputCount
;
66 // FIXME: If we exceed the buffer, mouse data gets thrown away.. better solution?
69 // Move the mouse input data from the port data queue to our class data queue
70 RtlMoveMemory(ClassDeviceExtension
->PortData
, (PCHAR
)MouseDataStart
,
71 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
73 // Move the pointer and counter up
74 ClassDeviceExtension
->PortData
+= ReadSize
;
75 ClassDeviceExtension
->InputCount
+= ReadSize
;
77 // Throw data up to GDI callback
78 if(*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
!= NULL
) {
79 DPRINT("MouseClassCallBack() Calling GDI callback at %p\n", ClassDeviceExtension
->GDIInformation
.CallBack
);
80 (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
)
81 (ClassDeviceExtension
->PortData
- ReadSize
, ReadSize
);
83 DPRINT("MouseClassCallBack() NO GDI callback installed\n");
86 ClassDeviceExtension
->PortData
-= ReadSize
;
87 ClassDeviceExtension
->InputCount
-= ReadSize
;
88 ClassDeviceExtension
->ReadIsPending
= FALSE
;
90 DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount
);
96 NTSTATUS
ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject
)
98 PDEVICE_OBJECT PortDeviceObject
= NULL
;
99 PFILE_OBJECT FileObject
= NULL
;
101 UNICODE_STRING PortName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\Mouse");
102 IO_STATUS_BLOCK ioStatus
;
105 CLASS_INFORMATION ClassInformation
;
106 PDEVICE_EXTENSION DeviceExtension
= ClassDeviceObject
->DeviceExtension
;
108 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
110 // Get the port driver's DeviceObject
111 // FIXME: The name might change.. find a way to be more dynamic?
113 status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
115 if(status
!= STATUS_SUCCESS
)
117 DbgPrint("MOUCLASS: Could not connect to mouse port driver\n");
121 DeviceExtension
->PortDeviceObject
= PortDeviceObject
;
122 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, MOUSE_BUFFER_SIZE
* sizeof(MOUSE_INPUT_DATA
));
123 DeviceExtension
->InputCount
= 0;
124 DeviceExtension
->ReadIsPending
= FALSE
;
126 // Connect our callback to the port driver
128 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
130 ClassInformation
.DeviceObject
= ClassDeviceObject
;
131 ClassInformation
.CallBack
= MouseClassCallBack
;
133 irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
134 PortDeviceObject
, &ClassInformation
, sizeof(CLASS_INFORMATION
), NULL
, 0, TRUE
, &event
, &ioStatus
);
136 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
138 if (status
== STATUS_PENDING
) {
139 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
141 ioStatus
.Status
= status
;
144 return ioStatus
.Status
;
147 NTSTATUS STDCALL
MouseClassDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
149 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
152 switch (Stack
->MajorFunction
)
155 if (AlreadyOpened
== TRUE
)
157 Status
= STATUS_SUCCESS
;
161 Status
= STATUS_SUCCESS
;
162 AlreadyOpened
= TRUE
;
167 Status
= STATUS_SUCCESS
;
172 if (Stack
->Parameters
.Read
.Length
== 0) {
173 Status
= STATUS_SUCCESS
;
175 Status
= STATUS_PENDING
;
180 DbgPrint("NOT IMPLEMENTED\n");
181 Status
= STATUS_NOT_IMPLEMENTED
;
185 Irp
->IoStatus
.Status
= Status
;
186 Irp
->IoStatus
.Information
= 0;
187 if (Status
==STATUS_PENDING
)
189 IoMarkIrpPending(Irp
);
190 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
192 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
197 VOID
MouseClassStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
199 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
200 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
203 if(DeviceExtension
->InputCount
>0)
205 // FIXME: We should not send too much input data.. depends on the max buffer size of the win32k
206 ReadSize
= DeviceExtension
->InputCount
* sizeof(MOUSE_INPUT_DATA
);
208 // Bring the PortData back to base so that it can be copied
209 DeviceExtension
->PortData
-= DeviceExtension
->InputCount
;
210 DeviceExtension
->InputCount
= 0;
211 DeviceExtension
->ReadIsPending
= FALSE
;
213 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
, (PCHAR
)DeviceExtension
->PortData
, ReadSize
);
215 // Go to next packet and complete this request with STATUS_SUCCESS
216 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
218 Irp
->IoStatus
.Information
= ReadSize
;
219 Stack
->Parameters
.Read
.Length
= ReadSize
;
221 IoStartNextPacket(DeviceObject
, FALSE
);
222 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
224 DeviceExtension
->ReadIsPending
= TRUE
;
228 NTSTATUS STDCALL
MouseClassInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
230 // Retrieve GDI's callback
232 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
233 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
236 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
238 case IOCTL_INTERNAL_MOUSE_CONNECT
:
240 DeviceExtension
->GDIInformation
=
241 *((PGDI_INFORMATION
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
243 DbgPrint("MouseClassInternalDeviceControl() installed GDI callback at %p\n", DeviceExtension
->GDIInformation
.CallBack
);
245 status
= STATUS_SUCCESS
;
248 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
250 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
252 status
= STATUS_SUCCESS
;
256 status
= STATUS_INVALID_DEVICE_REQUEST
;
260 Irp
->IoStatus
.Status
= status
;
261 if (status
== STATUS_PENDING
) {
262 IoMarkIrpPending(Irp
);
263 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
265 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
272 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
274 PDEVICE_OBJECT DeviceObject
;
275 UNICODE_STRING DeviceName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\MouseClass");
276 UNICODE_STRING SymlinkName
= UNICODE_STRING_INITIALIZER(L
"\\??\\MouseClass");
278 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouseClassDispatch
;
279 // DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch;
280 // DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch;
281 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouseClassInternalDeviceControl
; // to get GDI callback
282 // DriverObject->DriverStartIo = MouseClassStartIo;
284 IoCreateDevice(DriverObject
,
285 sizeof(DEVICE_EXTENSION
),
291 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
293 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
295 return ConnectMousePortDriver(DeviceObject
);