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)
17 SearchForLegacyDrivers(
18 IN PDRIVER_OBJECT DriverObject
,
19 IN PCLASS_DRIVER_EXTENSION DriverExtension
);
22 DriverUnload(IN PDRIVER_OBJECT DriverObject
)
24 // nothing to do here yet
29 IN PDEVICE_OBJECT DeviceObject
,
32 DPRINT("IRP_MJ_CREATE\n");
34 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
35 return ForwardIrpAndForget(DeviceObject
, Irp
);
37 /* FIXME: open all associated Port devices */
38 return STATUS_SUCCESS
;
43 IN PDEVICE_OBJECT DeviceObject
,
46 DPRINT("IRP_MJ_CLOSE\n");
48 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
49 return ForwardIrpAndForget(DeviceObject
, Irp
);
51 /* FIXME: close all associated Port devices */
52 return STATUS_SUCCESS
;
57 IN PDEVICE_OBJECT DeviceObject
,
60 DPRINT("IRP_MJ_CLEANUP\n");
62 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
63 return ForwardIrpAndForget(DeviceObject
, Irp
);
65 /* FIXME: cleanup all associated Port devices */
66 return STATUS_SUCCESS
;
71 IN PDEVICE_OBJECT DeviceObject
,
74 DPRINT("IRP_MJ_READ\n");
76 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
77 return ForwardIrpAndForget(DeviceObject
, Irp
);
79 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
< sizeof(KEYBOARD_INPUT_DATA
))
81 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
82 Irp
->IoStatus
.Information
= 0;
83 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
85 return STATUS_BUFFER_TOO_SMALL
;
88 IoMarkIrpPending(Irp
);
89 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
90 return STATUS_PENDING
;
95 IN PDEVICE_OBJECT DeviceObject
,
98 PCLASS_DEVICE_EXTENSION DeviceExtension
;
99 NTSTATUS Status
= Irp
->IoStatus
.Status
;
101 DPRINT("IRP_MJ_DEVICE_CONTROL\n");
103 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
104 return ForwardIrpAndForget(DeviceObject
, Irp
);
106 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
108 switch (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
)
110 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
111 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
112 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
113 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
115 /* FIXME: We hope that all devices will return the same result.
116 * Ask only the first one */
117 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
118 if (Head
->Flink
!= Head
)
120 /* We have at least one keyboard */
121 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Head
->Flink
, PORT_DEVICE_EXTENSION
, ListEntry
);
122 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
123 IoSkipCurrentIrpStackLocation(Irp
);
124 return IoCallDriver(DevExt
->DeviceObject
, Irp
);
128 case IOCTL_KEYBOARD_SET_INDICATORS
:
129 case IOCTL_KEYBOARD_SET_TYPEMATIC
: /* not in MSDN, would seem logical */
131 /* Send it to all associated Port devices */
132 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
133 PLIST_ENTRY Entry
= Head
->Flink
;
134 Status
= STATUS_SUCCESS
;
135 while (Entry
!= Head
)
137 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Entry
, PORT_DEVICE_EXTENSION
, ListEntry
);
138 NTSTATUS IntermediateStatus
;
140 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
141 IntermediateStatus
= ForwardIrpAndWait(DevExt
->DeviceObject
, Irp
);
142 if (!NT_SUCCESS(IntermediateStatus
))
143 Status
= IntermediateStatus
;
144 Entry
= Entry
->Flink
;
149 DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
150 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
155 Irp
->IoStatus
.Status
= Status
;
156 Irp
->IoStatus
.Information
= 0;
157 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
162 static NTSTATUS NTAPI
164 IN PDEVICE_OBJECT DeviceObject
,
167 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
169 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
171 /* Forward some IRPs to lower device */
172 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
175 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
176 return ForwardIrpAndForget(DeviceObject
, Irp
);
179 DPRINT1("Port DO stub for major function 0x%lx\n",
180 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
182 Status
= Irp
->IoStatus
.Status
;
188 DPRINT1("Class DO stub for major function 0x%lx\n",
189 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
191 Status
= Irp
->IoStatus
.Status
;
194 Irp
->IoStatus
.Status
= Status
;
195 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
201 IN PUNICODE_STRING RegistryPath
,
202 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
204 UNICODE_STRING ParametersRegistryKey
;
205 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
208 ULONG DefaultConnectMultiplePorts
= 0;
209 ULONG DefaultDataQueueSize
= 0x64;
210 UNICODE_STRING DefaultDeviceBaseName
= RTL_CONSTANT_STRING(L
"KeyboardClass");
212 ParametersRegistryKey
.Length
= 0;
213 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
214 ParametersRegistryKey
.Buffer
= ExAllocatePool(PagedPool
, ParametersRegistryKey
.MaximumLength
);
215 if (!ParametersRegistryKey
.Buffer
)
217 DPRINT("ExAllocatePool() failed\n");
218 return STATUS_INSUFFICIENT_RESOURCES
;
220 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
221 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
222 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
224 RtlZeroMemory(Parameters
, sizeof(Parameters
));
226 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
227 Parameters
[0].Name
= L
"ConnectMultiplePorts";
228 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
229 Parameters
[0].DefaultType
= REG_DWORD
;
230 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
231 Parameters
[0].DefaultLength
= sizeof(ULONG
);
233 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
234 Parameters
[1].Name
= L
"KeyboardDataQueueSize";
235 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
236 Parameters
[1].DefaultType
= REG_DWORD
;
237 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
238 Parameters
[1].DefaultLength
= sizeof(ULONG
);
240 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
241 Parameters
[2].Name
= L
"KeyboardDeviceBaseName";
242 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
243 Parameters
[2].DefaultType
= REG_SZ
;
244 Parameters
[2].DefaultData
= &DefaultDeviceBaseName
;
245 Parameters
[2].DefaultLength
= 0;
247 Status
= RtlQueryRegistryValues(
248 RTL_REGISTRY_ABSOLUTE
,
249 ParametersRegistryKey
.Buffer
,
254 if (NT_SUCCESS(Status
))
257 if (DriverExtension
->ConnectMultiplePorts
!= 0
258 && DriverExtension
->ConnectMultiplePorts
!= 1)
260 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
262 if (DriverExtension
->DataQueueSize
== 0)
264 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
267 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
269 /* Registry path doesn't exist. Set defaults */
270 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
271 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
272 Status
= RtlDuplicateUnicodeString(
273 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
274 &DefaultDeviceBaseName
,
275 &DriverExtension
->DeviceBaseName
);
282 CreateClassDeviceObject(
283 IN PDRIVER_OBJECT DriverObject
,
284 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
286 PCLASS_DRIVER_EXTENSION DriverExtension
;
287 UNICODE_STRING SymbolicLinkName
= RTL_CONSTANT_STRING(L
"\\??\\Keyboard");
290 UNICODE_STRING DeviceNameU
;
291 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
293 PCLASS_DEVICE_EXTENSION DeviceExtension
;
296 DPRINT("CreateClassDeviceObject(0x%p)\n", DriverObject
);
298 /* Create new device object */
299 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
300 DeviceNameU
.Length
= 0;
301 DeviceNameU
.MaximumLength
=
302 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
303 + DriverExtension
->DeviceBaseName
.Length
/* "KeyboardClass" */
304 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
305 + sizeof(UNICODE_NULL
); /* Final NULL char */
306 DeviceNameU
.Buffer
= ExAllocatePool(PagedPool
, DeviceNameU
.MaximumLength
);
307 if (!DeviceNameU
.Buffer
)
309 DPRINT("ExAllocatePool() failed\n");
310 return STATUS_INSUFFICIENT_RESOURCES
;
312 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
313 if (!NT_SUCCESS(Status
))
315 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
318 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
319 if (!NT_SUCCESS(Status
))
321 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
324 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
325 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
326 while (DeviceId
< 9999)
328 DeviceNameU
.Length
= PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
);
329 Status
= IoCreateDevice(
331 sizeof(CLASS_DEVICE_EXTENSION
),
333 FILE_DEVICE_KEYBOARD
,
334 FILE_DEVICE_SECURE_OPEN
,
337 if (NT_SUCCESS(Status
))
339 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
341 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
346 DPRINT("Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
347 Status
= STATUS_TOO_MANY_NAMES
;
349 if (!NT_SUCCESS(Status
))
351 ExFreePool(DeviceNameU
.Buffer
);
355 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
356 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
357 DeviceExtension
->Common
.IsClassDO
= TRUE
;
358 DeviceExtension
->DriverExtension
= DriverExtension
;
359 InitializeListHead(&DeviceExtension
->ListHead
);
360 KeInitializeSpinLock(&DeviceExtension
->ListSpinLock
);
361 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
362 DeviceExtension
->ReadIsPending
= FALSE
;
363 DeviceExtension
->InputCount
= 0;
364 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
));
365 Fdo
->Flags
|= DO_POWER_PAGABLE
| DO_BUFFERED_IO
;
366 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
368 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
369 RtlWriteRegistryValue(
370 RTL_REGISTRY_DEVICEMAP
,
371 DriverExtension
->DeviceBaseName
.Buffer
,
374 DriverExtension
->RegistryPath
.Buffer
,
375 DriverExtension
->RegistryPath
.MaximumLength
);
377 /* HACK: 1st stage setup needs a keyboard to open it in user-mode
378 * Create a link to user space... */
379 IoCreateSymbolicLink(&SymbolicLinkName
, &DeviceNameU
);
381 ExFreePool(DeviceNameU
.Buffer
);
386 return STATUS_SUCCESS
;
391 IN PDEVICE_OBJECT ClassDeviceObject
,
392 IN OUT PKEYBOARD_INPUT_DATA DataStart
,
393 IN PKEYBOARD_INPUT_DATA DataEnd
,
394 IN OUT PULONG ConsumedCount
)
396 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
399 PIO_STACK_LOCATION Stack
;
400 ULONG InputCount
= DataEnd
- DataStart
;
403 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
405 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
407 DPRINT("ClassCallback()\n");
408 /* A filter driver might have consumed all the data already; I'm
409 * not sure if they are supposed to move the packets when they
410 * consume them though.
412 if (ClassDeviceExtension
->ReadIsPending
== TRUE
&& InputCount
)
414 Irp
= ClassDeviceObject
->CurrentIrp
;
415 ClassDeviceObject
->CurrentIrp
= NULL
;
416 Stack
= IoGetCurrentIrpStackLocation(Irp
);
418 /* A read request is waiting for input, so go straight to it */
421 Irp
->MdlAddress
? MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
) : Irp
->AssociatedIrp
.SystemBuffer
,
423 sizeof(KEYBOARD_INPUT_DATA
));
425 /* Go to next packet and complete this request with STATUS_SUCCESS */
426 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
427 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INPUT_DATA
);
428 Stack
->Parameters
.Read
.Length
= sizeof(KEYBOARD_INPUT_DATA
);
430 ClassDeviceExtension
->ReadIsPending
= FALSE
;
432 /* Skip the packet we just sent away */
438 /* If we have data from the port driver and a higher service to send the data to */
441 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
442 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
444 ReadSize
= InputCount
;
447 * FIXME: If we exceed the buffer, data gets thrown away.. better
452 * Move the input data from the port data queue to our class data
456 ClassDeviceExtension
->PortData
,
458 sizeof(KEYBOARD_INPUT_DATA
) * ReadSize
);
460 /* Move the pointer and counter up */
461 ClassDeviceExtension
->PortData
+= ReadSize
;
462 ClassDeviceExtension
->InputCount
+= ReadSize
;
464 (*ConsumedCount
) += ReadSize
;
468 DPRINT("ClassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount
);
471 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
475 IoStartNextPacket(ClassDeviceObject
, FALSE
);
476 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
479 DPRINT("Leaving ClassCallback()\n");
483 /* Send IOCTL_INTERNAL_*_CONNECT to port */
486 IN PDEVICE_OBJECT PortDO
,
487 IN PDEVICE_OBJECT ClassDO
)
491 IO_STATUS_BLOCK IoStatus
;
492 CONNECT_DATA ConnectData
;
495 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
497 ConnectData
.ClassDeviceObject
= ClassDO
;
498 ConnectData
.ClassService
= ClassCallback
;
500 Irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_KEYBOARD_CONNECT
,
502 &ConnectData
, sizeof(CONNECT_DATA
),
504 TRUE
, &Event
, &IoStatus
);
506 Status
= IoCallDriver(PortDO
, Irp
);
508 if (Status
== STATUS_PENDING
)
509 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
511 IoStatus
.Status
= Status
;
513 if (NT_SUCCESS(IoStatus
.Status
))
515 ObReferenceObject(PortDO
);
516 ExInterlockedInsertTailList(
517 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListHead
,
518 &((PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
)->ListEntry
,
519 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListSpinLock
);
520 if (ClassDO
->StackSize
<= PortDO
->StackSize
)
522 /* Increase the stack size, in case we have to
523 * forward some IRPs to the port device object
525 ClassDO
->StackSize
= PortDO
->StackSize
+ 1;
529 return IoStatus
.Status
;
532 static NTSTATUS NTAPI
534 IN PDRIVER_OBJECT DriverObject
,
535 IN PDEVICE_OBJECT Pdo
)
537 PCLASS_DRIVER_EXTENSION DriverExtension
;
538 PDEVICE_OBJECT Fdo
= NULL
;
539 PPORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
542 DPRINT("ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
544 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
547 /* We're getting a NULL Pdo at the first call as we're a legacy driver.
548 * Use it to search for legacy port drivers. */
549 return SearchForLegacyDrivers(DriverObject
, DriverExtension
);
551 /* Create new device object */
552 Status
= IoCreateDevice(
554 sizeof(PORT_DEVICE_EXTENSION
),
557 FILE_DEVICE_SECURE_OPEN
,
560 if (!NT_SUCCESS(Status
))
562 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
566 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
567 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
568 DeviceExtension
->Common
.IsClassDO
= FALSE
;
569 DeviceExtension
->DeviceObject
= Fdo
;
570 DeviceExtension
->PnpState
= dsStopped
;
571 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
572 if (!NT_SUCCESS(Status
))
574 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
577 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
578 Fdo
->Flags
|= DO_POWER_PAGABLE
;
579 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
580 Fdo
->Flags
|= DO_BUFFERED_IO
;
582 if (DriverExtension
->ConnectMultiplePorts
)
583 DeviceExtension
->ClassDO
= DriverExtension
->MainClassDeviceObject
;
586 /* We need a new class device object for this Fdo */
587 Status
= CreateClassDeviceObject(
589 &DeviceExtension
->ClassDO
);
590 if (!NT_SUCCESS(Status
))
592 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
596 Status
= ConnectPortDriver(Fdo
, DeviceExtension
->ClassDO
);
597 if (!NT_SUCCESS(Status
))
599 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status
);
600 ObDereferenceObject(Fdo
);
603 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
605 /* Register interface */
606 Status
= IoRegisterDeviceInterface(
608 &GUID_DEVINTERFACE_KEYBOARD
,
610 &DeviceExtension
->InterfaceName
);
611 if (Status
== STATUS_INVALID_PARAMETER_1
)
613 /* The Pdo was a strange one ; maybe it is a legacy device.
614 * Ignore the error. */
615 return STATUS_SUCCESS
;
617 else if (!NT_SUCCESS(Status
))
619 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status
);
623 return STATUS_SUCCESS
;
628 if (DeviceExtension
->LowerDevice
)
629 IoDetachDevice(DeviceExtension
->LowerDevice
);
630 if (DriverExtension
->ConnectMultiplePorts
&& DeviceExtension
->ClassDO
)
632 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
;
633 ClassDeviceExtension
= (PCLASS_DEVICE_EXTENSION
)DeviceExtension
->ClassDO
->DeviceExtension
;
634 ExFreePool(ClassDeviceExtension
->PortData
);
644 IN PDEVICE_OBJECT DeviceObject
,
647 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
648 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
650 ASSERT(DeviceExtension
->Common
.IsClassDO
);
652 if (DeviceExtension
->InputCount
> 0)
656 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &oldIrql
);
658 DPRINT("Mdl: %p, UserBuffer: %p, InputCount: %lu\n",
661 DeviceExtension
->InputCount
);
665 Irp
->AssociatedIrp
.SystemBuffer
,
666 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
667 sizeof(KEYBOARD_INPUT_DATA
));
669 if (DeviceExtension
->InputCount
> 1)
672 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
673 DeviceExtension
->PortData
- DeviceExtension
->InputCount
+ 1,
674 (DeviceExtension
->InputCount
- 1) * sizeof(KEYBOARD_INPUT_DATA
));
676 DeviceExtension
->PortData
--;
677 DeviceExtension
->InputCount
--;
678 DeviceExtension
->ReadIsPending
= FALSE
;
680 /* Go to next packet and complete this request with STATUS_SUCCESS */
681 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
682 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INPUT_DATA
);
683 Stack
->Parameters
.Read
.Length
= sizeof(KEYBOARD_INPUT_DATA
);
684 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
686 IoStartNextPacket(DeviceObject
, FALSE
);
687 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, oldIrql
);
691 DeviceExtension
->ReadIsPending
= TRUE
;
696 SearchForLegacyDrivers(
697 IN PDRIVER_OBJECT DriverObject
,
698 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
700 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
701 UNICODE_STRING PortBaseName
= {0, };
702 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
703 OBJECT_ATTRIBUTES ObjectAttributes
;
704 HANDLE hDeviceMapKey
= (HANDLE
)-1;
705 HANDLE hPortKey
= (HANDLE
)-1;
707 ULONG Size
, ResultLength
;
710 /* Create port base name, by replacing Class by Port at the end of the class base name */
711 Status
= RtlDuplicateUnicodeString(
712 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
713 &DriverExtension
->DeviceBaseName
,
715 if (!NT_SUCCESS(Status
))
717 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
720 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
721 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
723 /* Allocate memory */
724 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
725 KeyValueInformation
= ExAllocatePool(PagedPool
, Size
);
726 if (!KeyValueInformation
)
728 DPRINT("ExAllocatePool() failed\n");
729 Status
= STATUS_INSUFFICIENT_RESOURCES
;
733 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
734 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
735 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
736 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
738 DPRINT("HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
739 Status
= STATUS_SUCCESS
;
742 else if (!NT_SUCCESS(Status
))
744 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
749 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
750 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
751 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
753 DPRINT("HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
754 Status
= STATUS_SUCCESS
;
757 else if (!NT_SUCCESS(Status
))
759 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
763 /* Read each value name */
764 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
766 UNICODE_STRING PortName
;
767 PDEVICE_OBJECT PortDeviceObject
= NULL
;
768 PFILE_OBJECT FileObject
= NULL
;
770 PortName
.Length
= PortName
.MaximumLength
= KeyValueInformation
->NameLength
;
771 PortName
.Buffer
= KeyValueInformation
->Name
;
773 /* Open the device object pointer */
774 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
775 if (!NT_SUCCESS(Status
))
777 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status
);
780 DPRINT("Legacy driver found: %wZ\n", &PortDeviceObject
->DriverObject
->DriverName
);
782 Status
= ClassAddDevice(DriverObject
, PortDeviceObject
);
783 if (!NT_SUCCESS(Status
))
785 /* FIXME: Log the error */
786 DPRINT("ClassAddDevice() failed with status 0x%08lx\n", Status
);
789 if (Status
== STATUS_NO_MORE_ENTRIES
)
790 Status
= STATUS_SUCCESS
;
793 if (KeyValueInformation
!= NULL
)
794 ExFreePool(KeyValueInformation
);
795 if (hDeviceMapKey
!= (HANDLE
)-1)
796 ZwClose(hDeviceMapKey
);
797 if (hPortKey
!= (HANDLE
)-1)
803 * Standard DriverEntry method.
807 IN PDRIVER_OBJECT DriverObject
,
808 IN PUNICODE_STRING RegistryPath
)
810 PCLASS_DRIVER_EXTENSION DriverExtension
;
814 Status
= IoAllocateDriverObjectExtension(
817 sizeof(CLASS_DRIVER_EXTENSION
),
818 (PVOID
*)&DriverExtension
);
819 if (!NT_SUCCESS(Status
))
821 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
824 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
826 Status
= RtlDuplicateUnicodeString(
827 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
829 &DriverExtension
->RegistryPath
);
830 if (!NT_SUCCESS(Status
))
832 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
836 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
837 if (!NT_SUCCESS(Status
))
839 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
843 if (DriverExtension
->ConnectMultiplePorts
== 1)
845 Status
= CreateClassDeviceObject(
847 &DriverExtension
->MainClassDeviceObject
);
848 if (!NT_SUCCESS(Status
))
850 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
855 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
856 DriverObject
->DriverUnload
= DriverUnload
;
858 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
859 DriverObject
->MajorFunction
[i
] = IrpStub
;
861 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
862 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
863 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
864 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
865 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
866 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ForwardIrpAndForget
;
867 DriverObject
->DriverStartIo
= ClassStartIo
;
869 return STATUS_SUCCESS
;