2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Keyboard class driver
4 * FILE: drivers/kbdclass/kbdclass.c
5 * PURPOSE: Keyboard 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(KEYBOARD_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_KEYBOARD_QUERY_ATTRIBUTES
:
135 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
136 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
137 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
139 /* FIXME: We hope that all devices will return the same result.
140 * Ask only the first one */
141 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
142 if (Head
->Flink
!= Head
)
144 /* We have at least one device */
145 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Head
->Flink
, PORT_DEVICE_EXTENSION
, ListEntry
);
146 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
147 IoSkipCurrentIrpStackLocation(Irp
);
148 return IoCallDriver(DevExt
->DeviceObject
, Irp
);
152 case IOCTL_KEYBOARD_SET_INDICATORS
:
153 case IOCTL_KEYBOARD_SET_TYPEMATIC
: /* not in MSDN, would seem logical */
155 /* Send it to all associated Port devices */
156 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
157 PLIST_ENTRY Entry
= Head
->Flink
;
158 Status
= STATUS_SUCCESS
;
159 while (Entry
!= Head
)
161 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Entry
, PORT_DEVICE_EXTENSION
, ListEntry
);
162 NTSTATUS IntermediateStatus
;
164 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
165 IntermediateStatus
= ForwardIrpAndWait(DevExt
->DeviceObject
, Irp
);
166 if (!NT_SUCCESS(IntermediateStatus
))
167 Status
= IntermediateStatus
;
168 Entry
= Entry
->Flink
;
173 WARN_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
174 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
179 Irp
->IoStatus
.Status
= Status
;
180 Irp
->IoStatus
.Information
= 0;
181 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
186 static NTSTATUS NTAPI
188 IN PDEVICE_OBJECT DeviceObject
,
191 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
193 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
195 /* Forward some IRPs to lower device */
196 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
199 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
200 return ForwardIrpAndForget(DeviceObject
, Irp
);
203 ERR_(CLASS_NAME
, "Port DO stub for major function 0x%lx\n",
204 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
211 ERR_(CLASS_NAME
, "Class DO stub for major function 0x%lx\n",
212 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
216 Irp
->IoStatus
.Status
= Status
;
217 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
223 IN PUNICODE_STRING RegistryPath
,
224 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
226 UNICODE_STRING ParametersRegistryKey
;
227 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
230 /* HACK: We don't support multiple devices with this disabled */
231 ULONG DefaultConnectMultiplePorts
= 1;
232 ULONG DefaultDataQueueSize
= 0x64;
233 PCWSTR DefaultDeviceBaseName
= L
"KeyboardClass";
235 ParametersRegistryKey
.Length
= 0;
236 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
237 ParametersRegistryKey
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ParametersRegistryKey
.MaximumLength
, CLASS_TAG
);
238 if (!ParametersRegistryKey
.Buffer
)
240 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
241 return STATUS_NO_MEMORY
;
243 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
244 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
245 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
247 RtlZeroMemory(Parameters
, sizeof(Parameters
));
249 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
250 Parameters
[0].Name
= L
"ConnectMultiplePorts";
251 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
252 Parameters
[0].DefaultType
= REG_DWORD
;
253 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
254 Parameters
[0].DefaultLength
= sizeof(ULONG
);
256 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
257 Parameters
[1].Name
= L
"KeyboardDataQueueSize";
258 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
259 Parameters
[1].DefaultType
= REG_DWORD
;
260 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
261 Parameters
[1].DefaultLength
= sizeof(ULONG
);
263 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
264 Parameters
[2].Name
= L
"KeyboardDeviceBaseName";
265 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
266 Parameters
[2].DefaultType
= REG_SZ
;
267 Parameters
[2].DefaultData
= (PVOID
)DefaultDeviceBaseName
;
268 Parameters
[2].DefaultLength
= 0;
270 Status
= RtlQueryRegistryValues(
271 RTL_REGISTRY_ABSOLUTE
,
272 ParametersRegistryKey
.Buffer
,
277 if (NT_SUCCESS(Status
))
280 if (DriverExtension
->ConnectMultiplePorts
!= 0
281 && DriverExtension
->ConnectMultiplePorts
!= 1)
283 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
285 if (DriverExtension
->DataQueueSize
== 0)
287 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
290 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
292 /* Registry path doesn't exist. Set defaults */
293 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
294 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
295 if (RtlCreateUnicodeString(&DriverExtension
->DeviceBaseName
, DefaultDeviceBaseName
))
296 Status
= STATUS_SUCCESS
;
298 Status
= STATUS_NO_MEMORY
;
301 ExFreePoolWithTag(ParametersRegistryKey
.Buffer
, CLASS_TAG
);
306 CreateClassDeviceObject(
307 IN PDRIVER_OBJECT DriverObject
,
308 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
310 PCLASS_DRIVER_EXTENSION DriverExtension
;
313 UNICODE_STRING DeviceNameU
;
314 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
316 PCLASS_DEVICE_EXTENSION DeviceExtension
;
319 TRACE_(CLASS_NAME
, "CreateClassDeviceObject(0x%p)\n", DriverObject
);
321 /* Create new device object */
322 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
323 DeviceNameU
.Length
= 0;
324 DeviceNameU
.MaximumLength
=
325 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
326 + DriverExtension
->DeviceBaseName
.Length
/* "KeyboardClass" */
327 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
328 + sizeof(UNICODE_NULL
); /* Final NULL char */
329 DeviceNameU
.Buffer
= ExAllocatePoolWithTag(PagedPool
, DeviceNameU
.MaximumLength
, CLASS_TAG
);
330 if (!DeviceNameU
.Buffer
)
332 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
333 return STATUS_NO_MEMORY
;
335 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
336 if (!NT_SUCCESS(Status
))
338 WARN_(CLASS_NAME
, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
341 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
342 if (!NT_SUCCESS(Status
))
344 WARN_(CLASS_NAME
, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
347 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
348 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
349 while (DeviceId
< 9999)
351 DeviceNameU
.Length
= (USHORT
)(PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
));
352 Status
= IoCreateDevice(
354 sizeof(CLASS_DEVICE_EXTENSION
),
356 FILE_DEVICE_KEYBOARD
,
357 FILE_DEVICE_SECURE_OPEN
,
360 if (NT_SUCCESS(Status
))
362 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
364 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
369 WARN_(CLASS_NAME
, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
370 Status
= STATUS_TOO_MANY_NAMES
;
372 if (!NT_SUCCESS(Status
))
374 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
378 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
379 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
380 DeviceExtension
->Common
.IsClassDO
= TRUE
;
381 DeviceExtension
->DriverExtension
= DriverExtension
;
382 InitializeListHead(&DeviceExtension
->ListHead
);
383 KeInitializeSpinLock(&DeviceExtension
->ListSpinLock
);
384 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
385 DeviceExtension
->InputCount
= 0;
386 DeviceExtension
->PortData
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
), CLASS_TAG
);
387 if (!DeviceExtension
->PortData
)
389 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
390 return STATUS_NO_MEMORY
;
392 DeviceExtension
->DeviceName
= DeviceNameU
.Buffer
;
393 Fdo
->Flags
|= DO_POWER_PAGABLE
;
394 Fdo
->Flags
|= DO_BUFFERED_IO
; /* FIXME: Why is it needed for 1st stage setup? */
395 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
397 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
398 RtlWriteRegistryValue(
399 RTL_REGISTRY_DEVICEMAP
,
400 DriverExtension
->DeviceBaseName
.Buffer
,
401 DeviceExtension
->DeviceName
,
403 DriverExtension
->RegistryPath
.Buffer
,
404 DriverExtension
->RegistryPath
.MaximumLength
);
409 return STATUS_SUCCESS
;
414 IN PDEVICE_OBJECT ClassDeviceObject
,
416 IN PKEYBOARD_INPUT_DATA DataStart
,
417 IN SIZE_T NumberOfEntries
)
419 NTSTATUS Status
= STATUS_SUCCESS
;
421 if (ClassDeviceObject
->Flags
& DO_BUFFERED_IO
)
424 Irp
->AssociatedIrp
.SystemBuffer
,
426 NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
));
428 else if (ClassDeviceObject
->Flags
& DO_DIRECT_IO
)
430 PVOID DestAddress
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
436 NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
));
439 Status
= STATUS_UNSUCCESSFUL
;
448 NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
));
450 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
452 Status
= _SEH2_GetExceptionCode();
462 IN PDEVICE_OBJECT ClassDeviceObject
,
463 IN OUT PKEYBOARD_INPUT_DATA DataStart
,
464 IN PKEYBOARD_INPUT_DATA DataEnd
,
465 IN OUT PULONG ConsumedCount
)
467 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
469 SIZE_T InputCount
= DataEnd
- DataStart
;
472 TRACE_(CLASS_NAME
, "ClassCallback()\n");
474 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
476 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
479 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
482 * We're exceeding the buffer, and data will be thrown away...
483 * FIXME: What could we do, as we are at DISPATCH_LEVEL?
485 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
488 ReadSize
= InputCount
;
491 * Move the input data from the port data queue to our class data
495 &ClassDeviceExtension
->PortData
[ClassDeviceExtension
->InputCount
],
497 sizeof(KEYBOARD_INPUT_DATA
) * ReadSize
);
499 /* Move the counter up */
500 ClassDeviceExtension
->InputCount
+= ReadSize
;
502 (*ConsumedCount
) += (ULONG
)ReadSize
;
504 /* Complete pending IRP (if any) */
505 if (ClassDeviceExtension
->PendingIrp
)
506 HandleReadIrp(ClassDeviceObject
, ClassDeviceExtension
->PendingIrp
, FALSE
);
508 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
510 TRACE_(CLASS_NAME
, "Leaving ClassCallback()\n");
514 /* Send IOCTL_INTERNAL_*_CONNECT to port */
517 IN PDEVICE_OBJECT PortDO
,
518 IN PDEVICE_OBJECT ClassDO
)
522 IO_STATUS_BLOCK IoStatus
;
523 CONNECT_DATA ConnectData
;
526 TRACE_(CLASS_NAME
, "Connecting PortDO %p to ClassDO %p\n", PortDO
, ClassDO
);
528 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
530 ConnectData
.ClassDeviceObject
= ClassDO
;
531 ConnectData
.ClassService
= ClassCallback
;
533 Irp
= IoBuildDeviceIoControlRequest(
534 IOCTL_INTERNAL_KEYBOARD_CONNECT
,
536 &ConnectData
, sizeof(CONNECT_DATA
),
538 TRUE
, &Event
, &IoStatus
);
540 return STATUS_INSUFFICIENT_RESOURCES
;
542 Status
= IoCallDriver(PortDO
, Irp
);
544 if (Status
== STATUS_PENDING
)
545 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
547 IoStatus
.Status
= Status
;
549 if (NT_SUCCESS(IoStatus
.Status
))
551 ObReferenceObject(PortDO
);
552 ExInterlockedInsertTailList(
553 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListHead
,
554 &((PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
)->ListEntry
,
555 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListSpinLock
);
556 if (ClassDO
->StackSize
<= PortDO
->StackSize
)
558 /* Increase the stack size, in case we have to
559 * forward some IRPs to the port device object
561 ClassDO
->StackSize
= PortDO
->StackSize
+ 1;
565 return IoStatus
.Status
;
568 /* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
571 IN PDEVICE_OBJECT PortDO
)
573 PPORT_DEVICE_EXTENSION DeviceExtension
;
574 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
;
575 PCLASS_DRIVER_EXTENSION DriverExtension
;
578 IO_STATUS_BLOCK IoStatus
;
582 TRACE_(CLASS_NAME
, "Destroying PortDO %p\n", PortDO
);
584 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
;
585 ClassDeviceExtension
= DeviceExtension
->ClassDO
->DeviceExtension
;
586 DriverExtension
= IoGetDriverObjectExtension(PortDO
->DriverObject
, PortDO
->DriverObject
);
588 /* Send IOCTL_INTERNAL_*_DISCONNECT */
589 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
590 Irp
= IoBuildDeviceIoControlRequest(
591 IOCTL_INTERNAL_KEYBOARD_DISCONNECT
,
595 TRUE
, &Event
, &IoStatus
);
598 Status
= IoCallDriver(PortDO
, Irp
);
599 if (Status
== STATUS_PENDING
)
600 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
603 /* Remove from ClassDeviceExtension->ListHead list */
604 KeAcquireSpinLock(&ClassDeviceExtension
->ListSpinLock
, &OldIrql
);
605 RemoveHeadList(DeviceExtension
->ListEntry
.Blink
);
606 KeReleaseSpinLock(&ClassDeviceExtension
->ListSpinLock
, OldIrql
);
608 /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
609 RtlDeleteRegistryValue(
610 RTL_REGISTRY_DEVICEMAP
,
611 DriverExtension
->DeviceBaseName
.Buffer
,
612 ClassDeviceExtension
->DeviceName
);
614 if (DeviceExtension
->LowerDevice
)
615 IoDetachDevice(DeviceExtension
->LowerDevice
);
616 ObDereferenceObject(PortDO
);
618 if (!DriverExtension
->ConnectMultiplePorts
&& DeviceExtension
->ClassDO
)
620 ExFreePoolWithTag(ClassDeviceExtension
->PortData
, CLASS_TAG
);
621 ExFreePoolWithTag((PVOID
)ClassDeviceExtension
->DeviceName
, CLASS_TAG
);
622 IoDeleteDevice(DeviceExtension
->ClassDO
);
625 IoDeleteDevice(PortDO
);
628 static NTSTATUS NTAPI
630 IN PDRIVER_OBJECT DriverObject
,
631 IN PDEVICE_OBJECT Pdo
)
633 PCLASS_DRIVER_EXTENSION DriverExtension
;
634 PDEVICE_OBJECT Fdo
= NULL
;
635 PPORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
638 TRACE_(CLASS_NAME
, "ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
640 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
643 /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
644 return STATUS_SUCCESS
;
646 /* Create new device object */
647 Status
= IoCreateDevice(
649 sizeof(PORT_DEVICE_EXTENSION
),
652 Pdo
->Characteristics
& FILE_DEVICE_SECURE_OPEN
? FILE_DEVICE_SECURE_OPEN
: 0,
655 if (!NT_SUCCESS(Status
))
657 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
660 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
662 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
663 RtlZeroMemory(DeviceExtension
, sizeof(PORT_DEVICE_EXTENSION
));
664 DeviceExtension
->Common
.IsClassDO
= FALSE
;
665 DeviceExtension
->DeviceObject
= Fdo
;
666 DeviceExtension
->PnpState
= dsStopped
;
667 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
668 if (!NT_SUCCESS(Status
))
670 WARN_(CLASS_NAME
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
673 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
674 Fdo
->Flags
|= DO_POWER_PAGABLE
;
675 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
676 Fdo
->Flags
|= DO_BUFFERED_IO
;
677 if (DeviceExtension
->LowerDevice
->Flags
& DO_DIRECT_IO
)
678 Fdo
->Flags
|= DO_DIRECT_IO
;
680 if (DriverExtension
->ConnectMultiplePorts
)
681 DeviceExtension
->ClassDO
= DriverExtension
->MainClassDeviceObject
;
684 /* We need a new class device object for this Fdo */
685 Status
= CreateClassDeviceObject(
687 &DeviceExtension
->ClassDO
);
688 if (!NT_SUCCESS(Status
))
690 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
694 Status
= ConnectPortDriver(Fdo
, DeviceExtension
->ClassDO
);
695 if (!NT_SUCCESS(Status
))
697 WARN_(CLASS_NAME
, "ConnectPortDriver() failed with status 0x%08lx\n", Status
);
700 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
702 /* Register interface ; ignore the error (if any) as having
703 * a registred interface is not so important... */
704 Status
= IoRegisterDeviceInterface(
706 &GUID_DEVINTERFACE_KEYBOARD
,
708 &DeviceExtension
->InterfaceName
);
709 if (!NT_SUCCESS(Status
))
710 DeviceExtension
->InterfaceName
.Length
= 0;
712 return STATUS_SUCCESS
;
716 DestroyPortDriver(Fdo
);
722 IN PDEVICE_OBJECT DeviceObject
,
725 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= DeviceObject
->DeviceExtension
;
727 BOOLEAN wasQueued
= FALSE
;
729 TRACE_(CLASS_NAME
, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
731 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
733 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
735 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
737 if (ClassDeviceExtension
->PendingIrp
== Irp
)
739 ClassDeviceExtension
->PendingIrp
= NULL
;
742 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
746 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
747 Irp
->IoStatus
.Information
= 0;
748 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
752 /* Hm, this shouldn't happen */
759 IN PDEVICE_OBJECT DeviceObject
,
763 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
767 TRACE_(CLASS_NAME
, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
769 ASSERT(DeviceExtension
->Common
.IsClassDO
);
771 if (DeviceExtension
->InputCount
> 0)
773 SIZE_T NumberOfEntries
;
775 NumberOfEntries
= MIN(
776 DeviceExtension
->InputCount
,
777 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
/ sizeof(KEYBOARD_INPUT_DATA
));
779 Status
= FillEntries(
782 DeviceExtension
->PortData
,
785 if (NT_SUCCESS(Status
))
787 if (DeviceExtension
->InputCount
> NumberOfEntries
)
790 &DeviceExtension
->PortData
[0],
791 &DeviceExtension
->PortData
[NumberOfEntries
],
792 (DeviceExtension
->InputCount
- NumberOfEntries
) * sizeof(KEYBOARD_INPUT_DATA
));
795 DeviceExtension
->InputCount
-= NumberOfEntries
;
797 Irp
->IoStatus
.Information
= NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
);
800 /* Go to next packet and complete this request */
801 Irp
->IoStatus
.Status
= Status
;
803 (VOID
)IoSetCancelRoutine(Irp
, NULL
);
804 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
805 DeviceExtension
->PendingIrp
= NULL
;
809 IoAcquireCancelSpinLock(&OldIrql
);
812 DeviceExtension
->PendingIrp
= NULL
;
813 Status
= STATUS_CANCELLED
;
817 IoMarkIrpPending(Irp
);
818 DeviceExtension
->PendingIrp
= Irp
;
819 (VOID
)IoSetCancelRoutine(Irp
, ClassCancelRoutine
);
820 Status
= STATUS_PENDING
;
822 IoReleaseCancelSpinLock(OldIrql
);
829 IN PDEVICE_OBJECT DeviceObject
,
832 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
835 TRACE_(CLASS_NAME
, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
837 ASSERT(DeviceExtension
->Common
.IsClassDO
);
839 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
840 HandleReadIrp(DeviceObject
, Irp
, TRUE
);
841 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
845 SearchForLegacyDrivers(
846 IN PDRIVER_OBJECT DriverObject
,
847 IN PVOID Context
, /* PCLASS_DRIVER_EXTENSION */
850 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
851 PCLASS_DRIVER_EXTENSION DriverExtension
;
852 UNICODE_STRING PortBaseName
= { 0, 0, NULL
};
853 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
854 OBJECT_ATTRIBUTES ObjectAttributes
;
855 HANDLE hDeviceMapKey
= (HANDLE
)-1;
856 HANDLE hPortKey
= (HANDLE
)-1;
858 ULONG Size
, ResultLength
;
861 TRACE_(CLASS_NAME
, "SearchForLegacyDrivers(%p %p %lu)\n",
862 DriverObject
, Context
, Count
);
866 DriverExtension
= (PCLASS_DRIVER_EXTENSION
)Context
;
868 /* Create port base name, by replacing Class by Port at the end of the class base name */
869 Status
= DuplicateUnicodeString(
870 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
871 &DriverExtension
->DeviceBaseName
,
873 if (!NT_SUCCESS(Status
))
875 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
878 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
879 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
881 /* Allocate memory */
882 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
883 KeyValueInformation
= ExAllocatePoolWithTag(PagedPool
, Size
, CLASS_TAG
);
884 if (!KeyValueInformation
)
886 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
887 Status
= STATUS_NO_MEMORY
;
891 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
892 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
893 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
894 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
896 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
897 Status
= STATUS_SUCCESS
;
900 else if (!NT_SUCCESS(Status
))
902 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
907 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
908 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
909 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
911 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
912 Status
= STATUS_SUCCESS
;
915 else if (!NT_SUCCESS(Status
))
917 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
921 /* Read each value name */
922 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
924 UNICODE_STRING PortName
;
925 PDEVICE_OBJECT PortDeviceObject
= NULL
;
926 PFILE_OBJECT FileObject
= NULL
;
928 PortName
.Length
= PortName
.MaximumLength
= (USHORT
)KeyValueInformation
->NameLength
;
929 PortName
.Buffer
= KeyValueInformation
->Name
;
931 /* Open the device object pointer */
932 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
933 if (!NT_SUCCESS(Status
))
935 WARN_(CLASS_NAME
, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName
, Status
);
938 INFO_(CLASS_NAME
, "Legacy driver found\n");
940 Status
= ClassAddDevice(DriverObject
, PortDeviceObject
);
941 if (!NT_SUCCESS(Status
))
943 /* FIXME: Log the error */
944 WARN_(CLASS_NAME
, "ClassAddDevice() failed with status 0x%08lx\n", Status
);
947 /* A special hack for 1st stage setup: manually send start device to i8042prt */
948 if (IsFirstStageSetup())
949 Send8042StartDevice(DriverObject
, PortDeviceObject
);
953 if (KeyValueInformation
!= NULL
)
954 ExFreePoolWithTag(KeyValueInformation
, CLASS_TAG
);
955 if (hDeviceMapKey
!= (HANDLE
)-1)
956 ZwClose(hDeviceMapKey
);
957 if (hPortKey
!= (HANDLE
)-1)
962 * Standard DriverEntry method.
966 IN PDRIVER_OBJECT DriverObject
,
967 IN PUNICODE_STRING RegistryPath
)
969 PCLASS_DRIVER_EXTENSION DriverExtension
;
973 Status
= IoAllocateDriverObjectExtension(
976 sizeof(CLASS_DRIVER_EXTENSION
),
977 (PVOID
*)&DriverExtension
);
978 if (!NT_SUCCESS(Status
))
980 WARN_(CLASS_NAME
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
983 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
985 Status
= DuplicateUnicodeString(
986 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
988 &DriverExtension
->RegistryPath
);
989 if (!NT_SUCCESS(Status
))
991 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
995 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
996 if (!NT_SUCCESS(Status
))
998 WARN_(CLASS_NAME
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
1002 if (DriverExtension
->ConnectMultiplePorts
== 1)
1004 Status
= CreateClassDeviceObject(
1006 &DriverExtension
->MainClassDeviceObject
);
1007 if (!NT_SUCCESS(Status
))
1009 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
1014 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
1015 DriverObject
->DriverUnload
= DriverUnload
;
1017 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1018 DriverObject
->MajorFunction
[i
] = IrpStub
;
1020 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
1021 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
1022 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
1023 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
1024 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
1025 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ForwardIrpAndForget
;
1026 DriverObject
->DriverStartIo
= ClassStartIo
;
1028 /* We will detect the legacy devices later */
1029 IoRegisterDriverReinitialization(
1031 SearchForLegacyDrivers
,
1034 return STATUS_SUCCESS
;