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 ConsumedCount
)
26 PDEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
29 PIO_STACK_LOCATION Stack
;
30 ULONG InputCount
= MouseDataEnd
- MouseDataStart
;
33 DPRINT("Entering MouseClassCallBack\n");
34 /* A filter driver might have consumed all the data already; I'm
35 * not sure if they are supposed to move the packets when they
36 * consume them though.
38 if (ClassDeviceExtension
->ReadIsPending
== TRUE
&&
41 Irp
= ClassDeviceObject
->CurrentIrp
;
42 ClassDeviceObject
->CurrentIrp
= NULL
;
43 Stack
= IoGetCurrentIrpStackLocation(Irp
);
45 /* A read request is waiting for input, so go straight to it */
46 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
, MouseDataStart
,
47 sizeof(MOUSE_INPUT_DATA
));
49 /* Go to next packet and complete this request with STATUS_SUCCESS */
50 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
51 Irp
->IoStatus
.Information
= sizeof(MOUSE_INPUT_DATA
);
52 Stack
->Parameters
.Read
.Length
= sizeof(MOUSE_INPUT_DATA
);
54 IoStartNextPacket(ClassDeviceObject
, FALSE
);
55 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
56 ClassDeviceExtension
->ReadIsPending
= FALSE
;
58 /* Skip the packet we just sent away */
64 /* If we have data from the port driver and a higher service to send the data to */
67 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
69 if (ClassDeviceExtension
->InputCount
+ InputCount
> MOUSE_BUFFER_SIZE
)
71 ReadSize
= MOUSE_BUFFER_SIZE
- ClassDeviceExtension
->InputCount
;
73 ReadSize
= InputCount
;
77 * FIXME: If we exceed the buffer, mouse data gets thrown away.. better
82 * Move the mouse input data from the port data queue to our class data
85 RtlMoveMemory(ClassDeviceExtension
->PortData
, (PCHAR
)MouseDataStart
,
86 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
88 /* Move the pointer and counter up */
89 ClassDeviceExtension
->PortData
+= ReadSize
;
90 ClassDeviceExtension
->InputCount
+= ReadSize
;
92 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
93 (*ConsumedCount
) += ReadSize
;
95 DPRINT("MouseClassCallBack() entered, InputCount = %d - DOING NOTHING\n", *InputCount
);
98 DPRINT("Leaving MouseClassCallBack\n");
102 NTSTATUS
ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject
)
104 PDEVICE_OBJECT PortDeviceObject
= NULL
;
105 PFILE_OBJECT FileObject
= NULL
;
107 UNICODE_STRING PortName
= ROS_STRING_INITIALIZER(L
"\\Device\\PointerClass0");
108 IO_STATUS_BLOCK ioStatus
;
111 CLASS_INFORMATION ClassInformation
;
112 PDEVICE_EXTENSION DeviceExtension
= ClassDeviceObject
->DeviceExtension
;
114 // Get the port driver's DeviceObject
115 // FIXME: The name might change.. find a way to be more dynamic?
117 status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
119 if(status
!= STATUS_SUCCESS
)
121 DPRINT("MOUCLASS: Could not connect to mouse port driver\n");
122 DPRINT("Status: %x\n", status
);
126 DeviceExtension
->PortDeviceObject
= PortDeviceObject
;
127 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, MOUSE_BUFFER_SIZE
* sizeof(MOUSE_INPUT_DATA
));
128 DeviceExtension
->InputCount
= 0;
129 DeviceExtension
->ReadIsPending
= FALSE
;
130 DeviceExtension
->WorkItem
= NULL
;
131 KeInitializeSpinLock(&(DeviceExtension
->SpinLock
));
132 DeviceExtension
->PassiveCallbackQueued
= FALSE
;
134 // Connect our callback to the port driver
136 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
138 ClassInformation
.DeviceObject
= ClassDeviceObject
;
139 ClassInformation
.CallBack
= MouseClassCallBack
;
141 irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
142 PortDeviceObject
, &ClassInformation
, sizeof(CLASS_INFORMATION
), NULL
, 0, TRUE
, &event
, &ioStatus
);
144 status
= IoCallDriver(DeviceExtension
->PortDeviceObject
, irp
);
146 if (status
== STATUS_PENDING
) {
147 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
149 ioStatus
.Status
= status
;
152 return ioStatus
.Status
;
155 NTSTATUS STDCALL
MouseClassDispatch(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
157 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
160 switch (Stack
->MajorFunction
)
163 Status
= STATUS_SUCCESS
;
167 Status
= STATUS_SUCCESS
;
171 if (Stack
->Parameters
.Read
.Length
< sizeof(MOUSE_INPUT_DATA
))
173 Status
= STATUS_BUFFER_TOO_SMALL
;
176 IoMarkIrpPending(Irp
);
177 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
178 return STATUS_PENDING
;
181 DPRINT1("NOT IMPLEMENTED\n");
182 Status
= STATUS_NOT_IMPLEMENTED
;
186 Irp
->IoStatus
.Status
= Status
;
187 Irp
->IoStatus
.Information
= 0;
188 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
194 MouseClassStartIo(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
196 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
197 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
199 if (DeviceExtension
->InputCount
> 0)
203 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &oldIrql
);
205 RtlMoveMemory(Irp
->AssociatedIrp
.SystemBuffer
,
206 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
207 sizeof(MOUSE_INPUT_DATA
));
209 if (DeviceExtension
->InputCount
> 1)
212 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
213 DeviceExtension
->PortData
- DeviceExtension
->InputCount
+ 1,
214 (DeviceExtension
->InputCount
- 1) * sizeof(MOUSE_INPUT_DATA
));
216 DeviceExtension
->PortData
--;
217 DeviceExtension
->InputCount
--;
218 DeviceExtension
->ReadIsPending
= FALSE
;
220 /* Go to next packet and complete this request with STATUS_SUCCESS */
221 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
222 Irp
->IoStatus
.Information
= sizeof(MOUSE_INPUT_DATA
);
223 Stack
->Parameters
.Read
.Length
= sizeof(MOUSE_INPUT_DATA
);
224 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
226 IoStartNextPacket(DeviceObject
, FALSE
);
227 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, oldIrql
);
229 DeviceExtension
->ReadIsPending
= TRUE
;
234 DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
236 PDEVICE_OBJECT DeviceObject
;
237 UNICODE_STRING DeviceName
= ROS_STRING_INITIALIZER(L
"\\Device\\Mouse");
238 UNICODE_STRING SymlinkName
= ROS_STRING_INITIALIZER(L
"\\??\\Mouse");
241 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouseClassDispatch
;
242 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouseClassDispatch
;
243 DriverObject
->MajorFunction
[IRP_MJ_READ
] = MouseClassDispatch
;
244 DriverObject
->DriverStartIo
= MouseClassStartIo
;
246 Status
= IoCreateDevice(DriverObject
,
247 sizeof(DEVICE_EXTENSION
),
253 if (!NT_SUCCESS(Status
))
258 DeviceObject
->Flags
= DeviceObject
->Flags
| DO_BUFFERED_IO
;
260 Status
= IoCreateSymbolicLink(&SymlinkName
, &DeviceName
);
261 if (!NT_SUCCESS(Status
))
263 IoDeleteDevice(DeviceObject
);
267 Status
= ConnectMousePortDriver(DeviceObject
);
268 if (!NT_SUCCESS(Status
))
270 IoDeleteSymbolicLink(&SymlinkName
);
271 IoDeleteDevice(DeviceObject
);
275 return STATUS_SUCCESS
;