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)
14 #include <pseh/pseh2.h>
17 static DRIVER_UNLOAD DriverUnload
;
18 static DRIVER_DISPATCH ClassCreate
;
19 static DRIVER_DISPATCH ClassClose
;
20 static DRIVER_DISPATCH ClassCleanup
;
21 static DRIVER_DISPATCH ClassRead
;
22 static DRIVER_DISPATCH ClassDeviceControl
;
23 static DRIVER_DISPATCH IrpStub
;
24 static DRIVER_ADD_DEVICE ClassAddDevice
;
25 static DRIVER_STARTIO ClassStartIo
;
26 static DRIVER_CANCEL ClassCancelRoutine
;
29 IN PDEVICE_OBJECT DeviceObject
,
34 DriverUnload(IN PDRIVER_OBJECT DriverObject
)
36 // nothing to do here yet
41 IN PDEVICE_OBJECT DeviceObject
,
44 TRACE_(CLASS_NAME
, "IRP_MJ_CREATE\n");
46 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
47 return ForwardIrpAndForget(DeviceObject
, Irp
);
49 /* FIXME: open all associated Port devices */
50 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
51 Irp
->IoStatus
.Information
= 0;
52 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
53 return STATUS_SUCCESS
;
58 IN PDEVICE_OBJECT DeviceObject
,
61 TRACE_(CLASS_NAME
, "IRP_MJ_CLOSE\n");
63 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
64 return ForwardIrpAndForget(DeviceObject
, Irp
);
66 /* FIXME: close all associated Port devices */
67 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
68 Irp
->IoStatus
.Information
= 0;
69 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
70 return STATUS_SUCCESS
;
75 IN PDEVICE_OBJECT DeviceObject
,
78 TRACE_(CLASS_NAME
, "IRP_MJ_CLEANUP\n");
80 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
81 return ForwardIrpAndForget(DeviceObject
, Irp
);
83 /* FIXME: cleanup all associated Port devices */
84 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
85 Irp
->IoStatus
.Information
= 0;
86 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
87 return STATUS_SUCCESS
;
92 IN PDEVICE_OBJECT DeviceObject
,
95 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
99 TRACE_(CLASS_NAME
, "IRP_MJ_READ\n");
101 ASSERT(DeviceExtension
->Common
.IsClassDO
);
103 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
104 return ForwardIrpAndForget(DeviceObject
, Irp
);
106 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
< sizeof(MOUSE_INPUT_DATA
))
108 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
109 Irp
->IoStatus
.Information
= 0;
110 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
112 return STATUS_BUFFER_TOO_SMALL
;
115 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
116 Status
= HandleReadIrp(DeviceObject
, Irp
, FALSE
);
117 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
121 static NTSTATUS NTAPI
123 IN PDEVICE_OBJECT DeviceObject
,
126 //PCLASS_DEVICE_EXTENSION DeviceExtension;
127 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
129 TRACE_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL\n");
131 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
132 return ForwardIrpAndForget(DeviceObject
, Irp
);
134 //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
136 switch (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
)
138 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
140 /* FIXME: We hope that all devices will return the same result.
141 * Ask only the first one */
142 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
143 if (Head
->Flink
!= Head
)
145 /* We have at least one device */
146 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Head
->Flink
, PORT_DEVICE_EXTENSION
, ListEntry
);
147 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
148 IoSkipCurrentIrpStackLocation(Irp
);
149 return IoCallDriver(DevExt
->DeviceObject
, Irp
);
154 WARN_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
155 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
160 Irp
->IoStatus
.Status
= Status
;
161 Irp
->IoStatus
.Information
= 0;
162 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
167 static NTSTATUS NTAPI
169 IN PDEVICE_OBJECT DeviceObject
,
172 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
173 PPORT_DEVICE_EXTENSION DeviceExtension
;
175 DeviceExtension
= DeviceObject
->DeviceExtension
;
176 if (!DeviceExtension
->Common
.IsClassDO
)
178 /* Forward some IRPs to lower device */
179 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
182 PoStartNextPowerIrp(Irp
);
183 IoSkipCurrentIrpStackLocation(Irp
);
184 return PoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
187 ERR_(CLASS_NAME
, "Port DO stub for major function 0x%lx\n",
188 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
195 ERR_(CLASS_NAME
, "Class DO stub for major function 0x%lx\n",
196 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
200 Irp
->IoStatus
.Status
= Status
;
201 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
207 IN PUNICODE_STRING RegistryPath
,
208 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
210 UNICODE_STRING ParametersRegistryKey
;
211 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
214 ULONG DefaultConnectMultiplePorts
= 1;
215 ULONG DefaultDataQueueSize
= 0x64;
216 PCWSTR DefaultDeviceBaseName
= L
"PointerClass";
218 ParametersRegistryKey
.Length
= 0;
219 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
220 ParametersRegistryKey
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ParametersRegistryKey
.MaximumLength
, CLASS_TAG
);
221 if (!ParametersRegistryKey
.Buffer
)
223 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
224 return STATUS_NO_MEMORY
;
226 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
227 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
228 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
230 RtlZeroMemory(Parameters
, sizeof(Parameters
));
232 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
233 Parameters
[0].Name
= L
"ConnectMultiplePorts";
234 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
235 Parameters
[0].DefaultType
= REG_DWORD
;
236 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
237 Parameters
[0].DefaultLength
= sizeof(ULONG
);
239 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
240 Parameters
[1].Name
= L
"MouseDataQueueSize";
241 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
242 Parameters
[1].DefaultType
= REG_DWORD
;
243 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
244 Parameters
[1].DefaultLength
= sizeof(ULONG
);
246 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
247 Parameters
[2].Name
= L
"PointerDeviceBaseName";
248 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
249 Parameters
[2].DefaultType
= REG_SZ
;
250 Parameters
[2].DefaultData
= (PVOID
)DefaultDeviceBaseName
;
251 Parameters
[2].DefaultLength
= 0;
253 Status
= RtlQueryRegistryValues(
254 RTL_REGISTRY_ABSOLUTE
,
255 ParametersRegistryKey
.Buffer
,
260 if (NT_SUCCESS(Status
))
263 if (DriverExtension
->ConnectMultiplePorts
!= 0
264 && DriverExtension
->ConnectMultiplePorts
!= 1)
266 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
268 if (DriverExtension
->DataQueueSize
== 0)
270 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
273 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
275 /* Registry path doesn't exist. Set defaults */
276 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
277 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
278 if (RtlCreateUnicodeString(&DriverExtension
->DeviceBaseName
, DefaultDeviceBaseName
))
279 Status
= STATUS_SUCCESS
;
281 Status
= STATUS_NO_MEMORY
;
284 ExFreePoolWithTag(ParametersRegistryKey
.Buffer
, CLASS_TAG
);
289 CreateClassDeviceObject(
290 IN PDRIVER_OBJECT DriverObject
,
291 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
293 PCLASS_DRIVER_EXTENSION DriverExtension
;
296 UNICODE_STRING DeviceNameU
;
297 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
299 PCLASS_DEVICE_EXTENSION DeviceExtension
;
302 TRACE_(CLASS_NAME
, "CreateClassDeviceObject(0x%p)\n", DriverObject
);
304 /* Create new device object */
305 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
306 DeviceNameU
.Length
= 0;
307 DeviceNameU
.MaximumLength
=
308 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
309 + DriverExtension
->DeviceBaseName
.Length
/* "PointerClass" */
310 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
311 + sizeof(UNICODE_NULL
); /* Final NULL char */
312 DeviceNameU
.Buffer
= ExAllocatePoolWithTag(PagedPool
, DeviceNameU
.MaximumLength
, CLASS_TAG
);
313 if (!DeviceNameU
.Buffer
)
315 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
316 return STATUS_NO_MEMORY
;
318 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
319 if (!NT_SUCCESS(Status
))
321 WARN_(CLASS_NAME
, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
324 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
325 if (!NT_SUCCESS(Status
))
327 WARN_(CLASS_NAME
, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
330 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
331 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
332 while (DeviceId
< 9999)
334 DeviceNameU
.Length
= (USHORT
)(PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
));
335 Status
= IoCreateDevice(
337 sizeof(CLASS_DEVICE_EXTENSION
),
340 FILE_DEVICE_SECURE_OPEN
,
343 if (NT_SUCCESS(Status
))
345 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
347 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
352 WARN_(CLASS_NAME
, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
353 Status
= STATUS_TOO_MANY_NAMES
;
355 if (!NT_SUCCESS(Status
))
357 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
361 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
362 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
363 DeviceExtension
->Common
.IsClassDO
= TRUE
;
364 DeviceExtension
->DriverExtension
= DriverExtension
;
365 InitializeListHead(&DeviceExtension
->ListHead
);
366 KeInitializeSpinLock(&DeviceExtension
->ListSpinLock
);
367 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
368 DeviceExtension
->InputCount
= 0;
369 DeviceExtension
->PortData
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(MOUSE_INPUT_DATA
), CLASS_TAG
);
370 if (!DeviceExtension
->PortData
)
372 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
373 return STATUS_NO_MEMORY
;
375 DeviceExtension
->DeviceName
= DeviceNameU
.Buffer
;
376 Fdo
->Flags
|= DO_POWER_PAGABLE
;
377 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
378 Fdo
->Flags
|= DO_BUFFERED_IO
;
380 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
381 RtlWriteRegistryValue(
382 RTL_REGISTRY_DEVICEMAP
,
383 DriverExtension
->DeviceBaseName
.Buffer
,
384 DeviceExtension
->DeviceName
,
386 DriverExtension
->RegistryPath
.Buffer
,
387 DriverExtension
->RegistryPath
.MaximumLength
);
392 return STATUS_SUCCESS
;
397 IN PDEVICE_OBJECT ClassDeviceObject
,
399 IN PMOUSE_INPUT_DATA DataStart
,
400 IN SIZE_T NumberOfEntries
)
402 NTSTATUS Status
= STATUS_SUCCESS
;
404 if (ClassDeviceObject
->Flags
& DO_BUFFERED_IO
)
407 Irp
->AssociatedIrp
.SystemBuffer
,
409 NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
));
411 else if (ClassDeviceObject
->Flags
& DO_DIRECT_IO
)
413 PVOID DestAddress
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
419 NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
));
422 Status
= STATUS_UNSUCCESSFUL
;
431 NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
));
433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
435 Status
= _SEH2_GetExceptionCode();
445 IN PDEVICE_OBJECT ClassDeviceObject
,
446 IN OUT PMOUSE_INPUT_DATA DataStart
,
447 IN PMOUSE_INPUT_DATA DataEnd
,
448 IN OUT PULONG ConsumedCount
)
450 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
452 SIZE_T InputCount
= DataEnd
- DataStart
;
455 TRACE_(CLASS_NAME
, "ClassCallback()\n");
457 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
459 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
462 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
465 * We're exceeding the buffer, and data will be thrown away...
466 * FIXME: What could we do, as we are at DISPATCH_LEVEL?
468 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
471 ReadSize
= InputCount
;
474 * Move the input data from the port data queue to our class data
478 &ClassDeviceExtension
->PortData
[ClassDeviceExtension
->InputCount
],
480 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
482 /* Move the counter up */
483 ClassDeviceExtension
->InputCount
+= ReadSize
;
485 (*ConsumedCount
) += (ULONG
)ReadSize
;
487 /* Complete pending IRP (if any) */
488 if (ClassDeviceExtension
->PendingIrp
)
489 HandleReadIrp(ClassDeviceObject
, ClassDeviceExtension
->PendingIrp
, FALSE
);
491 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
493 TRACE_(CLASS_NAME
, "Leaving ClassCallback()\n");
497 /* Send IOCTL_INTERNAL_*_CONNECT to port */
500 IN PDEVICE_OBJECT PortDO
,
501 IN PDEVICE_OBJECT ClassDO
)
505 IO_STATUS_BLOCK IoStatus
;
506 CONNECT_DATA ConnectData
;
509 TRACE_(CLASS_NAME
, "Connecting PortDO %p to ClassDO %p\n", PortDO
, ClassDO
);
511 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
513 ConnectData
.ClassDeviceObject
= ClassDO
;
514 ConnectData
.ClassService
= ClassCallback
;
516 Irp
= IoBuildDeviceIoControlRequest(
517 IOCTL_INTERNAL_MOUSE_CONNECT
,
519 &ConnectData
, sizeof(CONNECT_DATA
),
521 TRUE
, &Event
, &IoStatus
);
523 return STATUS_INSUFFICIENT_RESOURCES
;
525 Status
= IoCallDriver(PortDO
, Irp
);
527 if (Status
== STATUS_PENDING
)
528 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
530 IoStatus
.Status
= Status
;
532 if (NT_SUCCESS(IoStatus
.Status
))
534 ObReferenceObject(PortDO
);
535 ExInterlockedInsertTailList(
536 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListHead
,
537 &((PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
)->ListEntry
,
538 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListSpinLock
);
539 if (ClassDO
->StackSize
<= PortDO
->StackSize
)
541 /* Increase the stack size, in case we have to
542 * forward some IRPs to the port device object
544 ClassDO
->StackSize
= PortDO
->StackSize
+ 1;
548 return IoStatus
.Status
;
551 /* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
554 IN PDEVICE_OBJECT PortDO
)
556 PPORT_DEVICE_EXTENSION DeviceExtension
;
557 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
;
558 PCLASS_DRIVER_EXTENSION DriverExtension
;
561 IO_STATUS_BLOCK IoStatus
;
565 TRACE_(CLASS_NAME
, "Destroying PortDO %p\n", PortDO
);
567 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
;
568 ClassDeviceExtension
= DeviceExtension
->ClassDO
->DeviceExtension
;
569 DriverExtension
= IoGetDriverObjectExtension(PortDO
->DriverObject
, PortDO
->DriverObject
);
571 /* Send IOCTL_INTERNAL_*_DISCONNECT */
572 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
573 Irp
= IoBuildDeviceIoControlRequest(
574 IOCTL_INTERNAL_MOUSE_DISCONNECT
,
578 TRUE
, &Event
, &IoStatus
);
581 Status
= IoCallDriver(PortDO
, Irp
);
582 if (Status
== STATUS_PENDING
)
583 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
586 /* Remove from ClassDeviceExtension->ListHead list */
587 KeAcquireSpinLock(&ClassDeviceExtension
->ListSpinLock
, &OldIrql
);
588 RemoveEntryList(&DeviceExtension
->ListEntry
);
589 KeReleaseSpinLock(&ClassDeviceExtension
->ListSpinLock
, OldIrql
);
591 /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
592 RtlDeleteRegistryValue(
593 RTL_REGISTRY_DEVICEMAP
,
594 DriverExtension
->DeviceBaseName
.Buffer
,
595 ClassDeviceExtension
->DeviceName
);
597 if (DeviceExtension
->LowerDevice
)
598 IoDetachDevice(DeviceExtension
->LowerDevice
);
599 ObDereferenceObject(PortDO
);
601 if (!DriverExtension
->ConnectMultiplePorts
&& DeviceExtension
->ClassDO
)
603 ExFreePoolWithTag(ClassDeviceExtension
->PortData
, CLASS_TAG
);
604 ExFreePoolWithTag((PVOID
)ClassDeviceExtension
->DeviceName
, CLASS_TAG
);
605 IoDeleteDevice(DeviceExtension
->ClassDO
);
608 IoDeleteDevice(PortDO
);
611 static NTSTATUS NTAPI
613 IN PDRIVER_OBJECT DriverObject
,
614 IN PDEVICE_OBJECT Pdo
)
616 PCLASS_DRIVER_EXTENSION DriverExtension
;
617 PDEVICE_OBJECT Fdo
= NULL
;
618 PPORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
621 TRACE_(CLASS_NAME
, "ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
623 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
626 /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
627 return STATUS_SUCCESS
;
629 /* Create new device object */
630 Status
= IoCreateDevice(
632 sizeof(PORT_DEVICE_EXTENSION
),
635 Pdo
->Characteristics
& FILE_DEVICE_SECURE_OPEN
? FILE_DEVICE_SECURE_OPEN
: 0,
638 if (!NT_SUCCESS(Status
))
640 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
643 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
645 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
646 RtlZeroMemory(DeviceExtension
, sizeof(PORT_DEVICE_EXTENSION
));
647 DeviceExtension
->Common
.IsClassDO
= FALSE
;
648 DeviceExtension
->DeviceObject
= Fdo
;
649 DeviceExtension
->PnpState
= dsStopped
;
650 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
651 if (!NT_SUCCESS(Status
))
653 WARN_(CLASS_NAME
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
656 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
657 Fdo
->Flags
|= DO_POWER_PAGABLE
;
658 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
659 Fdo
->Flags
|= DO_BUFFERED_IO
;
660 if (DeviceExtension
->LowerDevice
->Flags
& DO_DIRECT_IO
)
661 Fdo
->Flags
|= DO_DIRECT_IO
;
663 if (DriverExtension
->ConnectMultiplePorts
)
664 DeviceExtension
->ClassDO
= DriverExtension
->MainClassDeviceObject
;
667 /* We need a new class device object for this Fdo */
668 Status
= CreateClassDeviceObject(
670 &DeviceExtension
->ClassDO
);
671 if (!NT_SUCCESS(Status
))
673 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
677 Status
= ConnectPortDriver(Fdo
, DeviceExtension
->ClassDO
);
678 if (!NT_SUCCESS(Status
))
680 WARN_(CLASS_NAME
, "ConnectPortDriver() failed with status 0x%08lx\n", Status
);
683 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
685 /* Register interface ; ignore the error (if any) as having
686 * a registered interface is not so important... */
687 Status
= IoRegisterDeviceInterface(
689 &GUID_DEVINTERFACE_MOUSE
,
691 &DeviceExtension
->InterfaceName
);
692 if (!NT_SUCCESS(Status
))
693 DeviceExtension
->InterfaceName
.Length
= 0;
695 return STATUS_SUCCESS
;
699 DestroyPortDriver(Fdo
);
705 IN PDEVICE_OBJECT DeviceObject
,
708 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= DeviceObject
->DeviceExtension
;
710 BOOLEAN wasQueued
= FALSE
;
712 TRACE_(CLASS_NAME
, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
714 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
716 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
718 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
720 if (ClassDeviceExtension
->PendingIrp
== Irp
)
722 ClassDeviceExtension
->PendingIrp
= NULL
;
725 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
729 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
730 Irp
->IoStatus
.Information
= 0;
731 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
735 DPRINT1("Cancelled IRP is not pending. Race condition?\n");
741 IN PDEVICE_OBJECT DeviceObject
,
745 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
749 TRACE_(CLASS_NAME
, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
751 ASSERT(DeviceExtension
->Common
.IsClassDO
);
753 if (DeviceExtension
->InputCount
> 0)
755 SIZE_T NumberOfEntries
;
757 NumberOfEntries
= MIN(
758 DeviceExtension
->InputCount
,
759 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
/ sizeof(MOUSE_INPUT_DATA
));
761 Status
= FillEntries(
764 DeviceExtension
->PortData
,
767 if (NT_SUCCESS(Status
))
769 if (DeviceExtension
->InputCount
> NumberOfEntries
)
772 &DeviceExtension
->PortData
[0],
773 &DeviceExtension
->PortData
[NumberOfEntries
],
774 (DeviceExtension
->InputCount
- NumberOfEntries
) * sizeof(MOUSE_INPUT_DATA
));
777 DeviceExtension
->InputCount
-= NumberOfEntries
;
779 Irp
->IoStatus
.Information
= NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
);
782 /* Go to next packet and complete this request */
783 Irp
->IoStatus
.Status
= Status
;
785 (VOID
)IoSetCancelRoutine(Irp
, NULL
);
786 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
787 DeviceExtension
->PendingIrp
= NULL
;
791 IoAcquireCancelSpinLock(&OldIrql
);
794 DeviceExtension
->PendingIrp
= NULL
;
795 Status
= STATUS_CANCELLED
;
799 IoMarkIrpPending(Irp
);
800 DeviceExtension
->PendingIrp
= Irp
;
801 (VOID
)IoSetCancelRoutine(Irp
, ClassCancelRoutine
);
802 Status
= STATUS_PENDING
;
804 IoReleaseCancelSpinLock(OldIrql
);
809 static NTSTATUS NTAPI
811 IN PDEVICE_OBJECT DeviceObject
,
814 PPORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
815 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
816 OBJECT_ATTRIBUTES ObjectAttributes
;
817 IO_STATUS_BLOCK Iosb
;
820 switch (IrpSp
->MinorFunction
)
822 case IRP_MN_START_DEVICE
:
823 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
824 if (NT_SUCCESS(Status
))
826 InitializeObjectAttributes(&ObjectAttributes
,
827 &DeviceExtension
->InterfaceName
,
828 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
832 Status
= ZwOpenFile(&DeviceExtension
->FileHandle
,
838 if (!NT_SUCCESS(Status
))
839 DeviceExtension
->FileHandle
= NULL
;
842 DeviceExtension
->FileHandle
= NULL
;
843 Irp
->IoStatus
.Status
= Status
;
844 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
847 case IRP_MN_STOP_DEVICE
:
848 if (DeviceExtension
->FileHandle
)
850 ZwClose(DeviceExtension
->FileHandle
);
851 DeviceExtension
->FileHandle
= NULL
;
853 Status
= STATUS_SUCCESS
;
856 case IRP_MN_REMOVE_DEVICE
:
857 if (DeviceExtension
->FileHandle
)
859 ZwClose(DeviceExtension
->FileHandle
);
860 DeviceExtension
->FileHandle
= NULL
;
862 IoSkipCurrentIrpStackLocation(Irp
);
863 Status
= IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
864 DestroyPortDriver(DeviceObject
);
868 Status
= Irp
->IoStatus
.Status
;
872 Irp
->IoStatus
.Status
= Status
;
873 if (NT_SUCCESS(Status
) || Status
== STATUS_NOT_SUPPORTED
)
875 IoSkipCurrentIrpStackLocation(Irp
);
876 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
880 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
887 IN PDEVICE_OBJECT DeviceObject
,
890 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
893 TRACE_(CLASS_NAME
, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
895 ASSERT(DeviceExtension
->Common
.IsClassDO
);
897 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
898 HandleReadIrp(DeviceObject
, Irp
, TRUE
);
899 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
903 SearchForLegacyDrivers(
904 IN PDRIVER_OBJECT DriverObject
,
905 IN PVOID Context
, /* PCLASS_DRIVER_EXTENSION */
908 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
909 PCLASS_DRIVER_EXTENSION DriverExtension
;
910 UNICODE_STRING PortBaseName
= { 0, 0, NULL
};
911 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
912 OBJECT_ATTRIBUTES ObjectAttributes
;
913 HANDLE hDeviceMapKey
= (HANDLE
)-1;
914 HANDLE hPortKey
= (HANDLE
)-1;
916 ULONG Size
, ResultLength
;
919 TRACE_(CLASS_NAME
, "SearchForLegacyDrivers(%p %p %lu)\n",
920 DriverObject
, Context
, Count
);
924 DriverExtension
= (PCLASS_DRIVER_EXTENSION
)Context
;
926 /* Create port base name, by replacing Class by Port at the end of the class base name */
927 Status
= DuplicateUnicodeString(
928 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
929 &DriverExtension
->DeviceBaseName
,
931 if (!NT_SUCCESS(Status
))
933 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
936 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
937 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
939 /* Allocate memory */
940 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
941 KeyValueInformation
= ExAllocatePoolWithTag(PagedPool
, Size
, CLASS_TAG
);
942 if (!KeyValueInformation
)
944 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
945 Status
= STATUS_NO_MEMORY
;
949 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
950 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
951 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
952 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
954 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
955 Status
= STATUS_SUCCESS
;
958 else if (!NT_SUCCESS(Status
))
960 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
965 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
966 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
967 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
969 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
970 Status
= STATUS_SUCCESS
;
973 else if (!NT_SUCCESS(Status
))
975 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
979 /* Read each value name */
980 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
982 UNICODE_STRING PortName
;
983 PDEVICE_OBJECT PortDeviceObject
= NULL
;
984 PFILE_OBJECT FileObject
= NULL
;
986 PortName
.Length
= PortName
.MaximumLength
= (USHORT
)KeyValueInformation
->NameLength
;
987 PortName
.Buffer
= KeyValueInformation
->Name
;
989 /* Open the device object pointer */
990 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
991 if (!NT_SUCCESS(Status
))
993 WARN_(CLASS_NAME
, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName
, Status
);
996 INFO_(CLASS_NAME
, "Legacy driver found\n");
998 Status
= ClassAddDevice(DriverObject
, PortDeviceObject
);
999 if (!NT_SUCCESS(Status
))
1001 /* FIXME: Log the error */
1002 WARN_(CLASS_NAME
, "ClassAddDevice() failed with status 0x%08lx\n", Status
);
1005 ObDereferenceObject(FileObject
);
1009 if (KeyValueInformation
!= NULL
)
1010 ExFreePoolWithTag(KeyValueInformation
, CLASS_TAG
);
1011 if (hDeviceMapKey
!= (HANDLE
)-1)
1012 ZwClose(hDeviceMapKey
);
1013 if (hPortKey
!= (HANDLE
)-1)
1018 * Standard DriverEntry method.
1022 IN PDRIVER_OBJECT DriverObject
,
1023 IN PUNICODE_STRING RegistryPath
)
1025 PCLASS_DRIVER_EXTENSION DriverExtension
;
1029 Status
= IoAllocateDriverObjectExtension(
1032 sizeof(CLASS_DRIVER_EXTENSION
),
1033 (PVOID
*)&DriverExtension
);
1034 if (!NT_SUCCESS(Status
))
1036 WARN_(CLASS_NAME
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
1039 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
1041 Status
= DuplicateUnicodeString(
1042 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1044 &DriverExtension
->RegistryPath
);
1045 if (!NT_SUCCESS(Status
))
1047 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
1051 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
1052 if (!NT_SUCCESS(Status
))
1054 WARN_(CLASS_NAME
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
1058 if (DriverExtension
->ConnectMultiplePorts
== 1)
1060 Status
= CreateClassDeviceObject(
1062 &DriverExtension
->MainClassDeviceObject
);
1063 if (!NT_SUCCESS(Status
))
1065 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
1070 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
1071 DriverObject
->DriverUnload
= DriverUnload
;
1073 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1074 DriverObject
->MajorFunction
[i
] = IrpStub
;
1076 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
1077 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
1078 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
1079 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
1080 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ClassPnp
;
1081 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
1082 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ForwardIrpAndForget
;
1083 DriverObject
->DriverStartIo
= ClassStartIo
;
1085 /* We will detect the legacy devices later */
1086 IoRegisterDriverReinitialization(
1088 SearchForLegacyDrivers
,
1091 return STATUS_SUCCESS
;