2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Mouse class driver
4 * FILE: drivers/mouclass/mouclass.c
5 * PURPOSE: Mouse class driver
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
17 DriverUnload(IN PDRIVER_OBJECT DriverObject
)
19 // nothing to do here yet
24 IN PDEVICE_OBJECT DeviceObject
,
27 DPRINT("IRP_MJ_CREATE\n");
29 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
30 return ForwardIrpAndForget(DeviceObject
, Irp
);
32 /* FIXME: open all associated Port devices */
33 return STATUS_SUCCESS
;
38 IN PDEVICE_OBJECT DeviceObject
,
41 DPRINT("IRP_MJ_CLOSE\n");
43 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
44 return ForwardIrpAndForget(DeviceObject
, Irp
);
46 /* FIXME: close all associated Port devices */
47 return STATUS_SUCCESS
;
52 IN PDEVICE_OBJECT DeviceObject
,
55 DPRINT("IRP_MJ_READ\n");
57 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
58 return ForwardIrpAndForget(DeviceObject
, Irp
);
60 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
< sizeof(MOUSE_INPUT_DATA
))
62 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
63 Irp
->IoStatus
.Information
= 0;
64 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
66 return STATUS_BUFFER_TOO_SMALL
;
69 IoMarkIrpPending(Irp
);
70 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
71 return STATUS_PENDING
;
76 IN PDEVICE_OBJECT DeviceObject
,
79 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
81 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
83 /* Forward some IRPs to lower device */
84 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
86 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
87 return ForwardIrpAndForget(DeviceObject
, Irp
);
90 DPRINT1("Port DO stub for major function 0x%lx\n",
91 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
93 Status
= Irp
->IoStatus
.Status
;
97 else if (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
) /* HACK FOR I8042PRT */
99 Status
= STATUS_SUCCESS
;
103 DPRINT1("Class DO stub for major function 0x%lx\n",
104 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
106 Status
= Irp
->IoStatus
.Status
;
109 Irp
->IoStatus
.Status
= Status
;
110 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
116 IN PUNICODE_STRING RegistryPath
,
117 IN PMOUCLASS_DRIVER_EXTENSION DriverExtension
)
119 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
122 ULONG DefaultConnectMultiplePorts
= 1;
123 ULONG DefaultMouseDataQueueSize
= 0x64;
124 UNICODE_STRING DefaultPointerDeviceBaseName
= RTL_CONSTANT_STRING(L
"PointerClassPnp");
126 RtlZeroMemory(Parameters
, sizeof(Parameters
));
128 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
129 Parameters
[0].Name
= L
"ConnectMultiplePorts";
130 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
131 Parameters
[0].DefaultType
= REG_DWORD
;
132 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
133 Parameters
[0].DefaultLength
= sizeof(ULONG
);
135 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
136 Parameters
[1].Name
= L
"MouseDataQueueSize";
137 Parameters
[1].EntryContext
= &DriverExtension
->MouseDataQueueSize
;
138 Parameters
[1].DefaultType
= REG_DWORD
;
139 Parameters
[1].DefaultData
= &DefaultMouseDataQueueSize
;
140 Parameters
[1].DefaultLength
= sizeof(ULONG
);
142 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
143 Parameters
[2].Name
= L
"PointerDeviceBaseName";
144 Parameters
[2].EntryContext
= &DriverExtension
->PointerDeviceBaseName
;
145 Parameters
[2].DefaultType
= REG_SZ
;
146 Parameters
[2].DefaultData
= &DefaultPointerDeviceBaseName
;
147 Parameters
[2].DefaultLength
= sizeof(ULONG
);
149 Status
= RtlQueryRegistryValues(
150 RTL_REGISTRY_ABSOLUTE
,
151 RegistryPath
->Buffer
,
156 if (NT_SUCCESS(Status
))
159 if (DriverExtension
->ConnectMultiplePorts
!= 0
160 && DriverExtension
->ConnectMultiplePorts
!= 1)
162 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
164 if (DriverExtension
->MouseDataQueueSize
== 0)
166 DriverExtension
->MouseDataQueueSize
= DefaultMouseDataQueueSize
;
174 CreatePointerClassDeviceObject(
175 IN PDRIVER_OBJECT DriverObject
,
176 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
178 PMOUCLASS_DRIVER_EXTENSION DriverExtension
;
181 UNICODE_STRING DeviceNameU
;
182 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
184 PMOUCLASS_DEVICE_EXTENSION DeviceExtension
;
187 DPRINT("CreatePointerClassDeviceObject(0x%p)\n", DriverObject
);
189 /* Create new device object */
190 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
191 DeviceNameU
.Length
= 0;
192 DeviceNameU
.MaximumLength
=
193 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
194 + DriverExtension
->PointerDeviceBaseName
.Length
/* "PointerClass" */
195 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
196 + sizeof(UNICODE_NULL
); /* Final NULL char */
197 DeviceNameU
.Buffer
= ExAllocatePool(PagedPool
, DeviceNameU
.MaximumLength
);
198 if (!DeviceNameU
.Buffer
)
200 DPRINT("ExAllocatePool() failed\n");
201 return STATUS_INSUFFICIENT_RESOURCES
;
203 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
204 if (!NT_SUCCESS(Status
))
206 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
209 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->PointerDeviceBaseName
);
210 if (!NT_SUCCESS(Status
))
212 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
215 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
216 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
217 while (DeviceId
< 9999)
219 DeviceNameU
.Length
= PrefixLength
+ swprintf(DeviceIdW
, L
"%ld", DeviceId
) * sizeof(WCHAR
);
220 Status
= IoCreateDevice(
222 sizeof(MOUCLASS_DEVICE_EXTENSION
),
225 FILE_DEVICE_SECURE_OPEN
,
228 if (NT_SUCCESS(Status
))
230 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
232 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
237 DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension
->PointerDeviceBaseName
);
238 Status
= STATUS_UNSUCCESSFUL
;
240 ExFreePool(DeviceNameU
.Buffer
);
241 if (!NT_SUCCESS(Status
))
244 DeviceExtension
= (PMOUCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
245 RtlZeroMemory(DeviceExtension
, sizeof(MOUCLASS_DEVICE_EXTENSION
));
246 DeviceExtension
->Common
.IsClassDO
= TRUE
;
247 DeviceExtension
->DriverExtension
= DriverExtension
;
248 DeviceExtension
->PnpState
= dsStopped
;
249 KeInitializeSpinLock(&(DeviceExtension
->SpinLock
));
250 DeviceExtension
->ReadIsPending
= FALSE
;
251 DeviceExtension
->InputCount
= 0;
252 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, DeviceExtension
->DriverExtension
->MouseDataQueueSize
* sizeof(MOUSE_INPUT_DATA
));
253 Fdo
->Flags
|= DO_POWER_PAGABLE
;
254 Fdo
->Flags
|= DO_BUFFERED_IO
;
255 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
257 /* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
262 return STATUS_SUCCESS
;
267 IN PDEVICE_OBJECT ClassDeviceObject
,
268 IN OUT PMOUSE_INPUT_DATA MouseDataStart
,
269 IN PMOUSE_INPUT_DATA MouseDataEnd
,
270 IN OUT PULONG ConsumedCount
)
272 PMOUCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
275 PIO_STACK_LOCATION Stack
;
276 ULONG InputCount
= MouseDataEnd
- MouseDataStart
;
279 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
281 DPRINT("MouclassCallback()\n");
282 /* A filter driver might have consumed all the data already; I'm
283 * not sure if they are supposed to move the packets when they
284 * consume them though.
286 if (ClassDeviceExtension
->ReadIsPending
== TRUE
&& InputCount
)
288 Irp
= ClassDeviceObject
->CurrentIrp
;
289 ClassDeviceObject
->CurrentIrp
= NULL
;
290 Stack
= IoGetCurrentIrpStackLocation(Irp
);
292 /* A read request is waiting for input, so go straight to it */
294 Irp
->AssociatedIrp
.SystemBuffer
,
296 sizeof(MOUSE_INPUT_DATA
));
298 /* Go to next packet and complete this request with STATUS_SUCCESS */
299 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
300 Irp
->IoStatus
.Information
= sizeof(MOUSE_INPUT_DATA
);
301 Stack
->Parameters
.Read
.Length
= sizeof(MOUSE_INPUT_DATA
);
303 ClassDeviceExtension
->ReadIsPending
= FALSE
;
305 /* Skip the packet we just sent away */
311 /* If we have data from the port driver and a higher service to send the data to */
314 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
316 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->MouseDataQueueSize
)
317 ReadSize
= ClassDeviceExtension
->DriverExtension
->MouseDataQueueSize
- ClassDeviceExtension
->InputCount
;
319 ReadSize
= InputCount
;
322 * FIXME: If we exceed the buffer, mouse data gets thrown away.. better
327 * Move the mouse input data from the port data queue to our class data
331 ClassDeviceExtension
->PortData
,
332 (PCHAR
)MouseDataStart
,
333 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
335 /* Move the pointer and counter up */
336 ClassDeviceExtension
->PortData
+= ReadSize
;
337 ClassDeviceExtension
->InputCount
+= ReadSize
;
339 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
340 (*ConsumedCount
) += ReadSize
;
344 DPRINT("MouclassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount
);
349 IoStartNextPacket(ClassDeviceObject
, FALSE
);
350 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
353 DPRINT("Leaving MouclassCallback()\n");
357 /* Send IOCTL_INTERNAL_MOUSE_CONNECT to pointer port */
359 ConnectMousePortDriver(
360 IN PDEVICE_OBJECT PointerPortDO
,
361 IN PDEVICE_OBJECT PointerClassDO
)
365 IO_STATUS_BLOCK IoStatus
;
366 CONNECT_DATA ConnectData
;
369 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
371 ConnectData
.ClassDeviceObject
= PointerClassDO
;
372 ConnectData
.ClassService
= MouclassCallback
;
374 Irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT
,
376 &ConnectData
, sizeof(CONNECT_DATA
),
378 TRUE
, &Event
, &IoStatus
);
380 Status
= IoCallDriver(PointerPortDO
, Irp
);
382 if (Status
== STATUS_PENDING
)
383 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
385 IoStatus
.Status
= Status
;
387 return IoStatus
.Status
;
390 static NTSTATUS NTAPI
392 IN PDRIVER_OBJECT DriverObject
,
393 IN PDEVICE_OBJECT Pdo
)
395 PMOUCLASS_DRIVER_EXTENSION DriverExtension
;
397 PMOUCLASS_DEVICE_EXTENSION DeviceExtension
;
400 DPRINT("MouclassAddDevice called. Pdo = 0x%p\n", Pdo
);
402 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
404 /* Create new device object */
405 Status
= IoCreateDevice(
407 sizeof(MOUCLASS_DEVICE_EXTENSION
),
410 FILE_DEVICE_SECURE_OPEN
,
413 if (!NT_SUCCESS(Status
))
415 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
419 DeviceExtension
= (PMOUCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
420 RtlZeroMemory(DeviceExtension
, sizeof(MOUCLASS_DEVICE_EXTENSION
));
421 DeviceExtension
->Common
.IsClassDO
= FALSE
;
422 DeviceExtension
->PnpState
= dsStopped
;
423 Fdo
->Flags
|= DO_POWER_PAGABLE
;
424 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
425 if (!NT_SUCCESS(Status
))
427 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
431 Fdo
->Flags
|= DO_BUFFERED_IO
;
432 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
434 if (DriverExtension
->ConnectMultiplePorts
)
435 Status
= ConnectMousePortDriver(Fdo
, DriverExtension
->MainMouclassDeviceObject
);
437 Status
= ConnectMousePortDriver(Fdo
, Fdo
);
438 if (!NT_SUCCESS(Status
))
440 DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status
);
441 /* FIXME: why can't I cleanup without error? */
442 //IoDetachDevice(Fdo);
443 //IoDeleteDevice(Fdo);
447 /* Register GUID_DEVINTERFACE_MOUSE interface */
448 Status
= IoRegisterDeviceInterface(
450 &GUID_DEVINTERFACE_MOUSE
,
452 &DeviceExtension
->MouseInterfaceName
);
453 if (!NT_SUCCESS(Status
))
455 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status
);
459 return STATUS_SUCCESS
;
464 IN PDEVICE_OBJECT DeviceObject
,
467 PMOUCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
468 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
470 ASSERT(DeviceExtension
->Common
.IsClassDO
);
472 if (DeviceExtension
->InputCount
> 0)
476 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &oldIrql
);
479 Irp
->AssociatedIrp
.SystemBuffer
,
480 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
481 sizeof(MOUSE_INPUT_DATA
));
483 if (DeviceExtension
->InputCount
> 1)
486 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
487 DeviceExtension
->PortData
- DeviceExtension
->InputCount
+ 1,
488 (DeviceExtension
->InputCount
- 1) * sizeof(MOUSE_INPUT_DATA
));
490 DeviceExtension
->PortData
--;
491 DeviceExtension
->InputCount
--;
492 DeviceExtension
->ReadIsPending
= FALSE
;
494 /* Go to next packet and complete this request with STATUS_SUCCESS */
495 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
496 Irp
->IoStatus
.Information
= sizeof(MOUSE_INPUT_DATA
);
497 Stack
->Parameters
.Read
.Length
= sizeof(MOUSE_INPUT_DATA
);
498 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
500 IoStartNextPacket(DeviceObject
, FALSE
);
501 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, oldIrql
);
505 DeviceExtension
->ReadIsPending
= TRUE
;
510 SearchForLegacyDrivers(
511 IN PMOUCLASS_DRIVER_EXTENSION DriverExtension
)
513 PDEVICE_OBJECT PortDeviceObject
= NULL
;
514 PFILE_OBJECT FileObject
= NULL
;
515 UNICODE_STRING PortName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
518 /* FIXME: search for more than once legacy driver */
520 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
521 if(Status
!= STATUS_SUCCESS
)
523 DPRINT("Could not open old device object (Status 0x%08lx)\n", Status
);
527 if (DriverExtension
->ConnectMultiplePorts
)
528 Status
= ConnectMousePortDriver(PortDeviceObject
, DriverExtension
->MainMouclassDeviceObject
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT("ConnectMousePortDriver() failed with status 0x%08lx\n", Status
);
539 return STATUS_SUCCESS
;
543 * Standard DriverEntry method.
547 IN PDRIVER_OBJECT DriverObject
,
548 IN PUNICODE_STRING RegistryPath
)
550 PMOUCLASS_DRIVER_EXTENSION DriverExtension
;
554 Status
= IoAllocateDriverObjectExtension(
557 sizeof(MOUCLASS_DRIVER_EXTENSION
),
558 (PVOID
*)&DriverExtension
);
559 if (!NT_SUCCESS(Status
))
561 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
564 RtlZeroMemory(DriverExtension
, sizeof(MOUCLASS_DRIVER_EXTENSION
));
566 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
567 if (!NT_SUCCESS(Status
))
569 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
573 if (DriverExtension
->ConnectMultiplePorts
== 1)
575 Status
= CreatePointerClassDeviceObject(
577 &DriverExtension
->MainMouclassDeviceObject
);
578 if (!NT_SUCCESS(Status
))
580 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status
);
585 DriverObject
->DriverExtension
->AddDevice
= MouclassAddDevice
;
586 DriverObject
->DriverUnload
= DriverUnload
;
588 for (i
= 0; i
< IRP_MJ_MAXIMUM_FUNCTION
; i
++)
589 DriverObject
->MajorFunction
[i
] = IrpStub
;
591 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouclassCreate
;
592 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouclassClose
;
593 DriverObject
->MajorFunction
[IRP_MJ_READ
] = MouclassRead
;
594 DriverObject
->DriverStartIo
= MouclassStartIo
;
596 SearchForLegacyDrivers(DriverExtension
);
598 return STATUS_SUCCESS
;