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 (*(PGDI_SERVICE_CALLBACK_ROUTINE
)ClassDeviceExtension
->GDIInformation
.CallBack
)
77 (ClassDeviceExtension
->PortData
- ReadSize
, ReadSize
);
80 ClassDeviceExtension
->PortData
-= ReadSize
;
81 ClassDeviceExtension
->InputCount
-= ReadSize
;
82 ClassDeviceExtension
->ReadIsPending
= FALSE
;
88 NTSTATUS
ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject
)
90 PDEVICE_OBJECT PortDeviceObject
= NULL
;
91 PFILE_OBJECT FileObject
= NULL
;
93 UNICODE_STRING PortName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\Mouse");
94 IO_STATUS_BLOCK ioStatus
;
97 CLASS_INFORMATION ClassInformation
;
98 PDEVICE_EXTENSION DeviceExtension
= ClassDeviceObject
->DeviceExtension
;
100 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
102 // Get the port driver's DeviceObject
103 // FIXME: The name might change.. find a way to be more dynamic?
105 status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
107 if(status
!= STATUS_SUCCESS
)
109 DbgPrint("MOUCLASS: Could not connect to mouse port driver\n");
113 DeviceExtension
->PortDeviceObject
= PortDeviceObject
;
114 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, MOUSE_BUFFER_SIZE
* sizeof(MOUSE_INPUT_DATA
));
115 DeviceExtension
->InputCount
= 0;
116 DeviceExtension
->ReadIsPending
= FALSE
;
118 // Connect our callback to the port driver
120 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
122 ClassInformation
.DeviceObject
= ClassDeviceObject
;
123 ClassInformation
.CallBack
= MouseClassCallBack
;
125 irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
126 PortDeviceObject
, &ClassInformation
, sizeof(CLASS_INFORMATION
), NULL
, 0, TRUE
, &event
, &ioStatus
);
128 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
130 if (status
== STATUS_PENDING
) {
131 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
133 ioStatus
.Status
= status
;
136 return ioStatus
.Status
;
139 NTSTATUS STDCALL
MouseClassDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
141 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
144 switch (Stack
->MajorFunction
)
147 if (AlreadyOpened
== TRUE
)
149 Status
= STATUS_SUCCESS
;
153 Status
= STATUS_SUCCESS
;
154 AlreadyOpened
= TRUE
;
159 Status
= STATUS_SUCCESS
;
164 if (Stack
->Parameters
.Read
.Length
== 0) {
165 Status
= STATUS_SUCCESS
;
167 Status
= STATUS_PENDING
;
172 DbgPrint("NOT IMPLEMENTED\n");
173 Status
= STATUS_NOT_IMPLEMENTED
;
177 Irp
->IoStatus
.Status
= Status
;
178 Irp
->IoStatus
.Information
= 0;
179 if (Status
==STATUS_PENDING
)
181 IoMarkIrpPending(Irp
);
182 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
184 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
189 VOID
MouseClassStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
191 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
192 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
195 if(DeviceExtension
->InputCount
>0)
197 // FIXME: We should not send too much input data.. depends on the max buffer size of the win32k
198 ReadSize
= DeviceExtension
->InputCount
* sizeof(MOUSE_INPUT_DATA
);
200 // Bring the PortData back to base so that it can be copied
201 DeviceExtension
->PortData
-= DeviceExtension
->InputCount
;
202 DeviceExtension
->InputCount
= 0;
203 DeviceExtension
->ReadIsPending
= FALSE
;
205 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
, (PCHAR
)DeviceExtension
->PortData
, ReadSize
);
207 // Go to next packet and complete this request with STATUS_SUCCESS
208 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
210 Irp
->IoStatus
.Information
= ReadSize
;
211 Stack
->Parameters
.Read
.Length
= ReadSize
;
213 IoStartNextPacket(DeviceObject
, FALSE
);
214 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
216 DeviceExtension
->ReadIsPending
= TRUE
;
220 NTSTATUS STDCALL
MouseClassInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
222 // Retrieve GDI's callback
224 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
225 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
228 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
230 case IOCTL_INTERNAL_MOUSE_CONNECT
:
232 DeviceExtension
->GDIInformation
=
233 *((PGDI_INFORMATION
)Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
);
235 status
= STATUS_SUCCESS
;
238 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
240 DeviceExtension
->GDIInformation
.CallBack
= NULL
;
242 status
= STATUS_SUCCESS
;
246 status
= STATUS_INVALID_DEVICE_REQUEST
;
250 Irp
->IoStatus
.Status
= status
;
251 if (status
== STATUS_PENDING
) {
252 IoMarkIrpPending(Irp
);
253 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
255 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
262 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
264 PDEVICE_OBJECT DeviceObject
;
265 UNICODE_STRING DeviceName
= UNICODE_STRING_INITIALIZER(L
"\\Device\\MouseClass");
266 UNICODE_STRING SymlinkName
= UNICODE_STRING_INITIALIZER(L
"\\??\\MouseClass");
268 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouseClassDispatch
;
269 // DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch;
270 // DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch;
271 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouseClassInternalDeviceControl
; // to get GDI callback
272 // DriverObject->DriverStartIo = MouseClassStartIo;
274 IoCreateDevice(DriverObject
,
275 sizeof(DEVICE_EXTENSION
),
281 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
283 IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
285 return ConnectMousePortDriver(DeviceObject
);