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)
13 static DRIVER_UNLOAD DriverUnload
;
14 static DRIVER_DISPATCH ClassCreate
;
15 static DRIVER_DISPATCH ClassClose
;
16 static DRIVER_DISPATCH ClassCleanup
;
17 static DRIVER_DISPATCH ClassRead
;
18 static DRIVER_DISPATCH ClassDeviceControl
;
19 static DRIVER_DISPATCH IrpStub
;
20 static DRIVER_ADD_DEVICE ClassAddDevice
;
21 static DRIVER_STARTIO ClassStartIo
;
22 static DRIVER_CANCEL ClassCancelRoutine
;
25 IN PDEVICE_OBJECT DeviceObject
,
30 DriverUnload(IN PDRIVER_OBJECT DriverObject
)
32 // nothing to do here yet
37 IN PDEVICE_OBJECT DeviceObject
,
40 TRACE_(CLASS_NAME
, "IRP_MJ_CREATE\n");
42 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
43 return ForwardIrpAndForget(DeviceObject
, Irp
);
45 /* FIXME: open all associated Port devices */
46 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
47 Irp
->IoStatus
.Information
= 0;
48 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
49 return STATUS_SUCCESS
;
54 IN PDEVICE_OBJECT DeviceObject
,
57 TRACE_(CLASS_NAME
, "IRP_MJ_CLOSE\n");
59 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
60 return ForwardIrpAndForget(DeviceObject
, Irp
);
62 /* FIXME: close all associated Port devices */
63 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
64 Irp
->IoStatus
.Information
= 0;
65 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
66 return STATUS_SUCCESS
;
71 IN PDEVICE_OBJECT DeviceObject
,
74 TRACE_(CLASS_NAME
, "IRP_MJ_CLEANUP\n");
76 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
77 return ForwardIrpAndForget(DeviceObject
, Irp
);
79 /* FIXME: cleanup all associated Port devices */
80 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
81 Irp
->IoStatus
.Information
= 0;
82 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
83 return STATUS_SUCCESS
;
88 IN PDEVICE_OBJECT DeviceObject
,
91 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
95 TRACE_(CLASS_NAME
, "IRP_MJ_READ\n");
97 ASSERT(DeviceExtension
->Common
.IsClassDO
);
99 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
100 return ForwardIrpAndForget(DeviceObject
, Irp
);
102 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
< sizeof(MOUSE_INPUT_DATA
))
104 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
105 Irp
->IoStatus
.Information
= 0;
106 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
108 return STATUS_BUFFER_TOO_SMALL
;
111 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
112 Status
= HandleReadIrp(DeviceObject
, Irp
, FALSE
);
113 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
117 static NTSTATUS NTAPI
119 IN PDEVICE_OBJECT DeviceObject
,
122 //PCLASS_DEVICE_EXTENSION DeviceExtension;
123 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
125 TRACE_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL\n");
127 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
128 return ForwardIrpAndForget(DeviceObject
, Irp
);
130 //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
132 switch (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
)
134 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
136 /* FIXME: We hope that all devices will return the same result.
137 * Ask only the first one */
138 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
139 if (Head
->Flink
!= Head
)
141 /* We have at least one device */
142 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Head
->Flink
, PORT_DEVICE_EXTENSION
, ListEntry
);
143 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
144 IoSkipCurrentIrpStackLocation(Irp
);
145 return IoCallDriver(DevExt
->DeviceObject
, Irp
);
150 WARN_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
151 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
156 Irp
->IoStatus
.Status
= Status
;
157 Irp
->IoStatus
.Information
= 0;
158 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
163 static NTSTATUS NTAPI
165 IN PDEVICE_OBJECT DeviceObject
,
168 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
170 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
172 /* Forward some IRPs to lower device */
173 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
176 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
177 return ForwardIrpAndForget(DeviceObject
, Irp
);
180 ERR_(CLASS_NAME
, "Port DO stub for major function 0x%lx\n",
181 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
188 ERR_(CLASS_NAME
, "Class DO stub for major function 0x%lx\n",
189 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
193 Irp
->IoStatus
.Status
= Status
;
194 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
200 IN PUNICODE_STRING RegistryPath
,
201 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
203 UNICODE_STRING ParametersRegistryKey
;
204 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
207 ULONG DefaultConnectMultiplePorts
= 1;
208 ULONG DefaultDataQueueSize
= 0x64;
209 PCWSTR DefaultDeviceBaseName
= L
"PointerClass";
211 ParametersRegistryKey
.Length
= 0;
212 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
213 ParametersRegistryKey
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ParametersRegistryKey
.MaximumLength
, CLASS_TAG
);
214 if (!ParametersRegistryKey
.Buffer
)
216 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
217 return STATUS_NO_MEMORY
;
219 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
220 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
221 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
223 RtlZeroMemory(Parameters
, sizeof(Parameters
));
225 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
226 Parameters
[0].Name
= L
"ConnectMultiplePorts";
227 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
228 Parameters
[0].DefaultType
= REG_DWORD
;
229 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
230 Parameters
[0].DefaultLength
= sizeof(ULONG
);
232 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
233 Parameters
[1].Name
= L
"MouseDataQueueSize";
234 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
235 Parameters
[1].DefaultType
= REG_DWORD
;
236 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
237 Parameters
[1].DefaultLength
= sizeof(ULONG
);
239 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
240 Parameters
[2].Name
= L
"PointerDeviceBaseName";
241 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
242 Parameters
[2].DefaultType
= REG_SZ
;
243 Parameters
[2].DefaultData
= (PVOID
)DefaultDeviceBaseName
;
244 Parameters
[2].DefaultLength
= 0;
246 Status
= RtlQueryRegistryValues(
247 RTL_REGISTRY_ABSOLUTE
,
248 ParametersRegistryKey
.Buffer
,
253 if (NT_SUCCESS(Status
))
256 if (DriverExtension
->ConnectMultiplePorts
!= 0
257 && DriverExtension
->ConnectMultiplePorts
!= 1)
259 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
261 if (DriverExtension
->DataQueueSize
== 0)
263 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
266 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
268 /* Registry path doesn't exist. Set defaults */
269 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
270 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
271 if (RtlCreateUnicodeString(&DriverExtension
->DeviceBaseName
, DefaultDeviceBaseName
))
272 Status
= STATUS_SUCCESS
;
274 Status
= STATUS_NO_MEMORY
;
277 ExFreePoolWithTag(ParametersRegistryKey
.Buffer
, CLASS_TAG
);
282 CreateClassDeviceObject(
283 IN PDRIVER_OBJECT DriverObject
,
284 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
286 PCLASS_DRIVER_EXTENSION DriverExtension
;
289 UNICODE_STRING DeviceNameU
;
290 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
292 PCLASS_DEVICE_EXTENSION DeviceExtension
;
295 TRACE_(CLASS_NAME
, "CreateClassDeviceObject(0x%p)\n", DriverObject
);
297 /* Create new device object */
298 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
299 DeviceNameU
.Length
= 0;
300 DeviceNameU
.MaximumLength
=
301 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
302 + DriverExtension
->DeviceBaseName
.Length
/* "PointerClass" */
303 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
304 + sizeof(UNICODE_NULL
); /* Final NULL char */
305 DeviceNameU
.Buffer
= ExAllocatePoolWithTag(PagedPool
, DeviceNameU
.MaximumLength
, CLASS_TAG
);
306 if (!DeviceNameU
.Buffer
)
308 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
309 return STATUS_NO_MEMORY
;
311 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
312 if (!NT_SUCCESS(Status
))
314 WARN_(CLASS_NAME
, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
317 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
318 if (!NT_SUCCESS(Status
))
320 WARN_(CLASS_NAME
, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
323 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
324 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
325 while (DeviceId
< 9999)
327 DeviceNameU
.Length
= (USHORT
)(PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
));
328 Status
= IoCreateDevice(
330 sizeof(CLASS_DEVICE_EXTENSION
),
333 FILE_DEVICE_SECURE_OPEN
,
336 if (NT_SUCCESS(Status
))
338 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
340 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
345 WARN_(CLASS_NAME
, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
346 Status
= STATUS_TOO_MANY_NAMES
;
348 if (!NT_SUCCESS(Status
))
350 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
354 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
355 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
356 DeviceExtension
->Common
.IsClassDO
= TRUE
;
357 DeviceExtension
->DriverExtension
= DriverExtension
;
358 InitializeListHead(&DeviceExtension
->ListHead
);
359 KeInitializeSpinLock(&DeviceExtension
->ListSpinLock
);
360 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
361 DeviceExtension
->InputCount
= 0;
362 DeviceExtension
->PortData
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(MOUSE_INPUT_DATA
), CLASS_TAG
);
363 if (!DeviceExtension
->PortData
)
365 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
366 return STATUS_NO_MEMORY
;
368 DeviceExtension
->DeviceName
= DeviceNameU
.Buffer
;
369 Fdo
->Flags
|= DO_POWER_PAGABLE
;
370 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
371 Fdo
->Flags
|= DO_BUFFERED_IO
;
373 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
374 RtlWriteRegistryValue(
375 RTL_REGISTRY_DEVICEMAP
,
376 DriverExtension
->DeviceBaseName
.Buffer
,
377 DeviceExtension
->DeviceName
,
379 DriverExtension
->RegistryPath
.Buffer
,
380 DriverExtension
->RegistryPath
.MaximumLength
);
385 return STATUS_SUCCESS
;
390 IN PDEVICE_OBJECT ClassDeviceObject
,
392 IN PMOUSE_INPUT_DATA DataStart
,
393 IN SIZE_T NumberOfEntries
)
395 NTSTATUS Status
= STATUS_SUCCESS
;
397 if (ClassDeviceObject
->Flags
& DO_BUFFERED_IO
)
400 Irp
->AssociatedIrp
.SystemBuffer
,
402 NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
));
404 else if (ClassDeviceObject
->Flags
& DO_DIRECT_IO
)
406 PVOID DestAddress
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
412 NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
));
415 Status
= STATUS_UNSUCCESSFUL
;
424 NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
));
426 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
428 Status
= _SEH2_GetExceptionCode();
438 IN PDEVICE_OBJECT ClassDeviceObject
,
439 IN OUT PMOUSE_INPUT_DATA DataStart
,
440 IN PMOUSE_INPUT_DATA DataEnd
,
441 IN OUT PULONG ConsumedCount
)
443 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
445 SIZE_T InputCount
= DataEnd
- DataStart
;
448 TRACE_(CLASS_NAME
, "ClassCallback()\n");
450 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
452 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
455 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
458 * We're exceeding the buffer, and data will be thrown away...
459 * FIXME: What could we do, as we are at DISPATCH_LEVEL?
461 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
464 ReadSize
= InputCount
;
467 * Move the input data from the port data queue to our class data
471 &ClassDeviceExtension
->PortData
[ClassDeviceExtension
->InputCount
],
473 sizeof(MOUSE_INPUT_DATA
) * ReadSize
);
475 /* Move the counter up */
476 ClassDeviceExtension
->InputCount
+= ReadSize
;
478 (*ConsumedCount
) += (ULONG
)ReadSize
;
480 /* Complete pending IRP (if any) */
481 if (ClassDeviceExtension
->PendingIrp
)
482 HandleReadIrp(ClassDeviceObject
, ClassDeviceExtension
->PendingIrp
, FALSE
);
484 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
486 TRACE_(CLASS_NAME
, "Leaving ClassCallback()\n");
490 /* Send IOCTL_INTERNAL_*_CONNECT to port */
493 IN PDEVICE_OBJECT PortDO
,
494 IN PDEVICE_OBJECT ClassDO
)
498 IO_STATUS_BLOCK IoStatus
;
499 CONNECT_DATA ConnectData
;
502 TRACE_(CLASS_NAME
, "Connecting PortDO %p to ClassDO %p\n", PortDO
, ClassDO
);
504 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
506 ConnectData
.ClassDeviceObject
= ClassDO
;
507 ConnectData
.ClassService
= ClassCallback
;
509 Irp
= IoBuildDeviceIoControlRequest(
510 IOCTL_INTERNAL_MOUSE_CONNECT
,
512 &ConnectData
, sizeof(CONNECT_DATA
),
514 TRUE
, &Event
, &IoStatus
);
516 return STATUS_INSUFFICIENT_RESOURCES
;
518 Status
= IoCallDriver(PortDO
, Irp
);
520 if (Status
== STATUS_PENDING
)
521 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
523 IoStatus
.Status
= Status
;
525 if (NT_SUCCESS(IoStatus
.Status
))
527 ObReferenceObject(PortDO
);
528 ExInterlockedInsertTailList(
529 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListHead
,
530 &((PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
)->ListEntry
,
531 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListSpinLock
);
532 if (ClassDO
->StackSize
<= PortDO
->StackSize
)
534 /* Increase the stack size, in case we have to
535 * forward some IRPs to the port device object
537 ClassDO
->StackSize
= PortDO
->StackSize
+ 1;
541 return IoStatus
.Status
;
544 /* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
547 IN PDEVICE_OBJECT PortDO
)
549 PPORT_DEVICE_EXTENSION DeviceExtension
;
550 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
;
551 PCLASS_DRIVER_EXTENSION DriverExtension
;
554 IO_STATUS_BLOCK IoStatus
;
558 TRACE_(CLASS_NAME
, "Destroying PortDO %p\n", PortDO
);
560 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
;
561 ClassDeviceExtension
= DeviceExtension
->ClassDO
->DeviceExtension
;
562 DriverExtension
= IoGetDriverObjectExtension(PortDO
->DriverObject
, PortDO
->DriverObject
);
564 /* Send IOCTL_INTERNAL_*_DISCONNECT */
565 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
566 Irp
= IoBuildDeviceIoControlRequest(
567 IOCTL_INTERNAL_MOUSE_DISCONNECT
,
571 TRUE
, &Event
, &IoStatus
);
574 Status
= IoCallDriver(PortDO
, Irp
);
575 if (Status
== STATUS_PENDING
)
576 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
579 /* Remove from ClassDeviceExtension->ListHead list */
580 KeAcquireSpinLock(&ClassDeviceExtension
->ListSpinLock
, &OldIrql
);
581 RemoveHeadList(DeviceExtension
->ListEntry
.Blink
);
582 KeReleaseSpinLock(&ClassDeviceExtension
->ListSpinLock
, OldIrql
);
584 /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
585 RtlDeleteRegistryValue(
586 RTL_REGISTRY_DEVICEMAP
,
587 DriverExtension
->DeviceBaseName
.Buffer
,
588 ClassDeviceExtension
->DeviceName
);
590 if (DeviceExtension
->LowerDevice
)
591 IoDetachDevice(DeviceExtension
->LowerDevice
);
592 ObDereferenceObject(PortDO
);
594 if (!DriverExtension
->ConnectMultiplePorts
&& DeviceExtension
->ClassDO
)
596 ExFreePoolWithTag(ClassDeviceExtension
->PortData
, CLASS_TAG
);
597 ExFreePoolWithTag((PVOID
)ClassDeviceExtension
->DeviceName
, CLASS_TAG
);
598 IoDeleteDevice(DeviceExtension
->ClassDO
);
601 IoDeleteDevice(PortDO
);
604 static NTSTATUS NTAPI
606 IN PDRIVER_OBJECT DriverObject
,
607 IN PDEVICE_OBJECT Pdo
)
609 PCLASS_DRIVER_EXTENSION DriverExtension
;
610 PDEVICE_OBJECT Fdo
= NULL
;
611 PPORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
614 TRACE_(CLASS_NAME
, "ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
616 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
619 /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
620 return STATUS_SUCCESS
;
622 /* Create new device object */
623 Status
= IoCreateDevice(
625 sizeof(PORT_DEVICE_EXTENSION
),
628 Pdo
->Characteristics
& FILE_DEVICE_SECURE_OPEN
? FILE_DEVICE_SECURE_OPEN
: 0,
631 if (!NT_SUCCESS(Status
))
633 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
636 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
638 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
639 RtlZeroMemory(DeviceExtension
, sizeof(PORT_DEVICE_EXTENSION
));
640 DeviceExtension
->Common
.IsClassDO
= FALSE
;
641 DeviceExtension
->DeviceObject
= Fdo
;
642 DeviceExtension
->PnpState
= dsStopped
;
643 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
644 if (!NT_SUCCESS(Status
))
646 WARN_(CLASS_NAME
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
649 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
650 Fdo
->Flags
|= DO_POWER_PAGABLE
;
651 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
652 Fdo
->Flags
|= DO_BUFFERED_IO
;
653 if (DeviceExtension
->LowerDevice
->Flags
& DO_DIRECT_IO
)
654 Fdo
->Flags
|= DO_DIRECT_IO
;
656 if (DriverExtension
->ConnectMultiplePorts
)
657 DeviceExtension
->ClassDO
= DriverExtension
->MainClassDeviceObject
;
660 /* We need a new class device object for this Fdo */
661 Status
= CreateClassDeviceObject(
663 &DeviceExtension
->ClassDO
);
664 if (!NT_SUCCESS(Status
))
666 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
670 Status
= ConnectPortDriver(Fdo
, DeviceExtension
->ClassDO
);
671 if (!NT_SUCCESS(Status
))
673 WARN_(CLASS_NAME
, "ConnectPortDriver() failed with status 0x%08lx\n", Status
);
676 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
678 /* Register interface ; ignore the error (if any) as having
679 * a registred interface is not so important... */
680 Status
= IoRegisterDeviceInterface(
682 &GUID_DEVINTERFACE_MOUSE
,
684 &DeviceExtension
->InterfaceName
);
685 if (!NT_SUCCESS(Status
))
686 DeviceExtension
->InterfaceName
.Length
= 0;
688 return STATUS_SUCCESS
;
692 DestroyPortDriver(Fdo
);
698 IN PDEVICE_OBJECT DeviceObject
,
701 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= DeviceObject
->DeviceExtension
;
703 BOOLEAN wasQueued
= FALSE
;
705 TRACE_(CLASS_NAME
, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
707 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
709 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
711 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
713 if (ClassDeviceExtension
->PendingIrp
== Irp
)
715 ClassDeviceExtension
->PendingIrp
= NULL
;
718 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
722 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
723 Irp
->IoStatus
.Information
= 0;
724 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
728 DPRINT1("Cancelled IRP is not pending. Race condition?\n");
734 IN PDEVICE_OBJECT DeviceObject
,
738 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
742 TRACE_(CLASS_NAME
, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
744 ASSERT(DeviceExtension
->Common
.IsClassDO
);
746 if (DeviceExtension
->InputCount
> 0)
748 SIZE_T NumberOfEntries
;
750 NumberOfEntries
= MIN(
751 DeviceExtension
->InputCount
,
752 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
/ sizeof(MOUSE_INPUT_DATA
));
754 Status
= FillEntries(
757 DeviceExtension
->PortData
,
760 if (NT_SUCCESS(Status
))
762 if (DeviceExtension
->InputCount
> NumberOfEntries
)
765 &DeviceExtension
->PortData
[0],
766 &DeviceExtension
->PortData
[NumberOfEntries
],
767 (DeviceExtension
->InputCount
- NumberOfEntries
) * sizeof(MOUSE_INPUT_DATA
));
770 DeviceExtension
->InputCount
-= NumberOfEntries
;
772 Irp
->IoStatus
.Information
= NumberOfEntries
* sizeof(MOUSE_INPUT_DATA
);
775 /* Go to next packet and complete this request */
776 Irp
->IoStatus
.Status
= Status
;
778 (VOID
)IoSetCancelRoutine(Irp
, NULL
);
779 IoCompleteRequest(Irp
, IO_MOUSE_INCREMENT
);
780 DeviceExtension
->PendingIrp
= NULL
;
784 IoAcquireCancelSpinLock(&OldIrql
);
787 DeviceExtension
->PendingIrp
= NULL
;
788 Status
= STATUS_CANCELLED
;
792 IoMarkIrpPending(Irp
);
793 DeviceExtension
->PendingIrp
= Irp
;
794 (VOID
)IoSetCancelRoutine(Irp
, ClassCancelRoutine
);
795 Status
= STATUS_PENDING
;
797 IoReleaseCancelSpinLock(OldIrql
);
802 static NTSTATUS NTAPI
804 IN PDEVICE_OBJECT DeviceObject
,
807 PPORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
808 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
809 OBJECT_ATTRIBUTES ObjectAttributes
;
810 IO_STATUS_BLOCK Iosb
;
813 switch (IrpSp
->MinorFunction
)
815 case IRP_MN_START_DEVICE
:
816 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
817 if (NT_SUCCESS(Status
))
819 InitializeObjectAttributes(&ObjectAttributes
,
820 &DeviceExtension
->InterfaceName
,
821 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
825 Status
= ZwOpenFile(&DeviceExtension
->FileHandle
,
831 if (!NT_SUCCESS(Status
))
832 DeviceExtension
->FileHandle
= NULL
;
835 DeviceExtension
->FileHandle
= NULL
;
836 Irp
->IoStatus
.Status
= Status
;
837 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
840 case IRP_MN_REMOVE_DEVICE
:
841 case IRP_MN_STOP_DEVICE
:
842 if (DeviceExtension
->FileHandle
)
844 ZwClose(DeviceExtension
->FileHandle
);
845 DeviceExtension
->FileHandle
= NULL
;
847 Status
= STATUS_SUCCESS
;
851 Status
= Irp
->IoStatus
.Status
;
855 Irp
->IoStatus
.Status
= Status
;
856 if (NT_SUCCESS(Status
) || Status
== STATUS_NOT_SUPPORTED
)
858 IoSkipCurrentIrpStackLocation(Irp
);
859 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
863 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
870 IN PDEVICE_OBJECT DeviceObject
,
873 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
876 TRACE_(CLASS_NAME
, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
878 ASSERT(DeviceExtension
->Common
.IsClassDO
);
880 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
881 HandleReadIrp(DeviceObject
, Irp
, TRUE
);
882 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
886 SearchForLegacyDrivers(
887 IN PDRIVER_OBJECT DriverObject
,
888 IN PVOID Context
, /* PCLASS_DRIVER_EXTENSION */
891 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
892 PCLASS_DRIVER_EXTENSION DriverExtension
;
893 UNICODE_STRING PortBaseName
= { 0, 0, NULL
};
894 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
895 OBJECT_ATTRIBUTES ObjectAttributes
;
896 HANDLE hDeviceMapKey
= (HANDLE
)-1;
897 HANDLE hPortKey
= (HANDLE
)-1;
899 ULONG Size
, ResultLength
;
902 TRACE_(CLASS_NAME
, "SearchForLegacyDrivers(%p %p %lu)\n",
903 DriverObject
, Context
, Count
);
907 DriverExtension
= (PCLASS_DRIVER_EXTENSION
)Context
;
909 /* Create port base name, by replacing Class by Port at the end of the class base name */
910 Status
= DuplicateUnicodeString(
911 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
912 &DriverExtension
->DeviceBaseName
,
914 if (!NT_SUCCESS(Status
))
916 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
919 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
920 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
922 /* Allocate memory */
923 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
924 KeyValueInformation
= ExAllocatePoolWithTag(PagedPool
, Size
, CLASS_TAG
);
925 if (!KeyValueInformation
)
927 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
928 Status
= STATUS_NO_MEMORY
;
932 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
933 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
934 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
935 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
937 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
938 Status
= STATUS_SUCCESS
;
941 else if (!NT_SUCCESS(Status
))
943 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
948 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
949 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
950 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
952 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
953 Status
= STATUS_SUCCESS
;
956 else if (!NT_SUCCESS(Status
))
958 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
962 /* Read each value name */
963 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
965 UNICODE_STRING PortName
;
966 PDEVICE_OBJECT PortDeviceObject
= NULL
;
967 PFILE_OBJECT FileObject
= NULL
;
969 PortName
.Length
= PortName
.MaximumLength
= (USHORT
)KeyValueInformation
->NameLength
;
970 PortName
.Buffer
= KeyValueInformation
->Name
;
972 /* Open the device object pointer */
973 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
974 if (!NT_SUCCESS(Status
))
976 WARN_(CLASS_NAME
, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName
, Status
);
979 INFO_(CLASS_NAME
, "Legacy driver found\n");
981 Status
= ClassAddDevice(DriverObject
, PortDeviceObject
);
982 if (!NT_SUCCESS(Status
))
984 /* FIXME: Log the error */
985 WARN_(CLASS_NAME
, "ClassAddDevice() failed with status 0x%08lx\n", Status
);
988 ObDereferenceObject(FileObject
);
992 if (KeyValueInformation
!= NULL
)
993 ExFreePoolWithTag(KeyValueInformation
, CLASS_TAG
);
994 if (hDeviceMapKey
!= (HANDLE
)-1)
995 ZwClose(hDeviceMapKey
);
996 if (hPortKey
!= (HANDLE
)-1)
1001 * Standard DriverEntry method.
1005 IN PDRIVER_OBJECT DriverObject
,
1006 IN PUNICODE_STRING RegistryPath
)
1008 PCLASS_DRIVER_EXTENSION DriverExtension
;
1012 Status
= IoAllocateDriverObjectExtension(
1015 sizeof(CLASS_DRIVER_EXTENSION
),
1016 (PVOID
*)&DriverExtension
);
1017 if (!NT_SUCCESS(Status
))
1019 WARN_(CLASS_NAME
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
1022 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
1024 Status
= DuplicateUnicodeString(
1025 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1027 &DriverExtension
->RegistryPath
);
1028 if (!NT_SUCCESS(Status
))
1030 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
1034 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
1035 if (!NT_SUCCESS(Status
))
1037 WARN_(CLASS_NAME
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
1041 if (DriverExtension
->ConnectMultiplePorts
== 1)
1043 Status
= CreateClassDeviceObject(
1045 &DriverExtension
->MainClassDeviceObject
);
1046 if (!NT_SUCCESS(Status
))
1048 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
1053 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
1054 DriverObject
->DriverUnload
= DriverUnload
;
1056 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1057 DriverObject
->MajorFunction
[i
] = IrpStub
;
1059 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
1060 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
1061 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
1062 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
1063 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ClassPnp
;
1064 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
1065 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ForwardIrpAndForget
;
1066 DriverObject
->DriverStartIo
= ClassStartIo
;
1068 /* We will detect the legacy devices later */
1069 IoRegisterDriverReinitialization(
1071 SearchForLegacyDrivers
,
1074 return STATUS_SUCCESS
;