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>
16 #include <rosrtl/string.h>
22 BOOLEAN
MouseClassCallBack(
23 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
;
30 ULONG SafeInputCount
= *InputCount
;
33 DPRINT("Entering MouseClassCallBack\n");
34 if (ClassDeviceExtension
->ReadIsPending
== TRUE
)
36 Irp
= ClassDeviceObject
->CurrentIrp
;
37 ClassDeviceObject
->CurrentIrp
= NULL
;
38 Stack
= IoGetCurrentIrpStackLocation(Irp
);
40 /* A read request is waiting for input, so go straight to it */
41 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
, MouseDataStart
,
42 sizeof(MOUSE_INPUT_DATA
));
44 /* Go to next packet and complete this request with STATUS_SUCCESS */
45 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
46 Irp
->IoStatus
.Information
= sizeof(MOUSE_INPUT_DATA
);
47 Stack
->Parameters
.Read
.Length
= sizeof(MOUSE_INPUT_DATA
);
49 IoStartNextPacket(ClassDeviceObject
, FALSE
);
50 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
51 ClassDeviceExtension
->ReadIsPending
= FALSE
;
53 /* Skip the packet we just sent away */
58 /* If we have data from the port driver and a higher service to send the data to */
59 if (SafeInputCount
!= 0)
61 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
63 if (ClassDeviceExtension
->InputCount
+ SafeInputCount
> MOUSE_BUFFER_SIZE
)
65 ReadSize
= MOUSE_BUFFER_SIZE
- ClassDeviceExtension
->InputCount
;
67 ReadSize
= SafeInputCount
;
71 * FIXME: If we exceed the buffer, mouse data gets thrown away.. better
76 * Move the mouse input data from the port data queue to our class data
79 RtlMoveMemory(ClassDeviceExtension
->PortData
, (PCHAR
)MouseDataStart
,
80 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
82 /* Move the pointer and counter up */
83 ClassDeviceExtension
->PortData
+= ReadSize
;
84 ClassDeviceExtension
->InputCount
+= ReadSize
;
86 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
88 DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount
);
91 DPRINT("Leaving MouseClassCallBack\n");
95 NTSTATUS
ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject
)
97 PDEVICE_OBJECT PortDeviceObject
= NULL
;
98 PFILE_OBJECT FileObject
= NULL
;
100 UNICODE_STRING PortName
= ROS_STRING_INITIALIZER(L
"\\Device\\PointerClass0");
101 IO_STATUS_BLOCK ioStatus
;
104 CLASS_INFORMATION ClassInformation
;
105 PDEVICE_EXTENSION DeviceExtension
= ClassDeviceObject
->DeviceExtension
;
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 DPRINT("MOUCLASS: Could not connect to mouse port driver\n");
115 DPRINT("Status: %x\n", status
);
119 DeviceExtension
->PortDeviceObject
= PortDeviceObject
;
120 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, MOUSE_BUFFER_SIZE
* sizeof(MOUSE_INPUT_DATA
));
121 DeviceExtension
->InputCount
= 0;
122 DeviceExtension
->ReadIsPending
= FALSE
;
123 DeviceExtension
->WorkItem
= NULL
;
124 KeInitializeSpinLock(&(DeviceExtension
->SpinLock
));
125 DeviceExtension
->PassiveCallbackQueued
= FALSE
;
127 // Connect our callback to the port driver
129 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
131 ClassInformation
.DeviceObject
= ClassDeviceObject
;
132 ClassInformation
.CallBack
= MouseClassCallBack
;
134 irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
135 PortDeviceObject
, &ClassInformation
, sizeof(CLASS_INFORMATION
), NULL
, 0, TRUE
, &event
, &ioStatus
);
137 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
139 if (status
== STATUS_PENDING
) {
140 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
142 ioStatus
.Status
= status
;
145 return ioStatus
.Status
;
148 NTSTATUS STDCALL
MouseClassDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
150 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
153 switch (Stack
->MajorFunction
)
156 Status
= STATUS_SUCCESS
;
160 Status
= STATUS_SUCCESS
;
164 if (Stack
->Parameters
.Read
.Length
< sizeof(MOUSE_INPUT_DATA
))
166 Status
= STATUS_BUFFER_TOO_SMALL
;
169 IoMarkIrpPending(Irp
);
170 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
171 return STATUS_PENDING
;
174 DPRINT1("NOT IMPLEMENTED\n");
175 Status
= STATUS_NOT_IMPLEMENTED
;
179 Irp
->IoStatus
.Status
= Status
;
180 Irp
->IoStatus
.Information
= 0;
181 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
187 MouseClassStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
189 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
190 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
192 if (DeviceExtension
->InputCount
> 0)
196 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &oldIrql
);
198 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
199 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
200 sizeof(MOUSE_INPUT_DATA
));
202 if (DeviceExtension
->InputCount
> 1)
205 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
206 DeviceExtension
->PortData
- DeviceExtension
->InputCount
+ 1,
207 (DeviceExtension
->InputCount
- 1) * sizeof(MOUSE_INPUT_DATA
));
209 DeviceExtension
->PortData
--;
210 DeviceExtension
->InputCount
--;
211 DeviceExtension
->ReadIsPending
= FALSE
;
213 /* Go to next packet and complete this request with STATUS_SUCCESS */
214 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
215 Irp
->IoStatus
.Information
= sizeof(MOUSE_INPUT_DATA
);
216 Stack
->Parameters
.Read
.Length
= sizeof(MOUSE_INPUT_DATA
);
217 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
219 IoStartNextPacket(DeviceObject
, FALSE
);
220 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, oldIrql
);
222 DeviceExtension
->ReadIsPending
= TRUE
;
227 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
229 PDEVICE_OBJECT DeviceObject
;
230 UNICODE_STRING DeviceName
= ROS_STRING_INITIALIZER(L
"\\Device\\Mouse");
231 UNICODE_STRING SymlinkName
= ROS_STRING_INITIALIZER(L
"\\??\\Mouse");
234 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouseClassDispatch
;
235 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouseClassDispatch
;
236 DriverObject
->MajorFunction
[IRP_MJ_READ
] = MouseClassDispatch
;
237 DriverObject
->DriverStartIo
= MouseClassStartIo
;
239 Status
= IoCreateDevice(DriverObject
,
240 sizeof(DEVICE_EXTENSION
),
246 if (!NT_SUCCESS(Status
))
251 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
253 Status
= IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
254 if (!NT_SUCCESS(Status
))
256 IoDeleteDevice(DeviceObject
);
260 Status
= ConnectMousePortDriver(DeviceObject
);
261 if (!NT_SUCCESS(Status
))
263 IoDeleteSymbolicLink(&SymlinkName
);
264 IoDeleteDevice(DeviceObject
);
268 return STATUS_SUCCESS
;