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 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
39 Irp
->IoStatus
.Information
= 0;
40 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
41 return STATUS_SUCCESS
;
46 IN PDEVICE_OBJECT DeviceObject
,
49 DPRINT("IRP_MJ_CLOSE\n");
51 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
52 return ForwardIrpAndForget(DeviceObject
, Irp
);
54 /* FIXME: close all associated Port devices */
55 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
56 Irp
->IoStatus
.Information
= 0;
57 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
58 return STATUS_SUCCESS
;
63 IN PDEVICE_OBJECT DeviceObject
,
66 DPRINT("IRP_MJ_CLEANUP\n");
68 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
69 return ForwardIrpAndForget(DeviceObject
, Irp
);
71 /* FIXME: cleanup all associated Port devices */
72 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
73 Irp
->IoStatus
.Information
= 0;
74 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
75 return STATUS_SUCCESS
;
80 IN PDEVICE_OBJECT DeviceObject
,
83 DPRINT("IRP_MJ_READ\n");
85 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
86 return ForwardIrpAndForget(DeviceObject
, Irp
);
88 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
< sizeof(KEYBOARD_INPUT_DATA
))
90 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
91 Irp
->IoStatus
.Information
= 0;
92 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
94 return STATUS_BUFFER_TOO_SMALL
;
97 IoMarkIrpPending(Irp
);
98 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
99 return STATUS_PENDING
;
102 static NTSTATUS NTAPI
104 IN PDEVICE_OBJECT DeviceObject
,
107 PCLASS_DEVICE_EXTENSION DeviceExtension
;
108 NTSTATUS Status
= Irp
->IoStatus
.Status
;
110 DPRINT("IRP_MJ_DEVICE_CONTROL\n");
112 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
113 return ForwardIrpAndForget(DeviceObject
, Irp
);
115 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
117 switch (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
)
119 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
120 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
121 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
122 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
124 /* FIXME: We hope that all devices will return the same result.
125 * Ask only the first one */
126 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
127 if (Head
->Flink
!= Head
)
129 /* We have at least one keyboard */
130 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Head
->Flink
, PORT_DEVICE_EXTENSION
, ListEntry
);
131 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
132 IoSkipCurrentIrpStackLocation(Irp
);
133 return IoCallDriver(DevExt
->DeviceObject
, Irp
);
137 case IOCTL_KEYBOARD_SET_INDICATORS
:
138 case IOCTL_KEYBOARD_SET_TYPEMATIC
: /* not in MSDN, would seem logical */
140 /* Send it to all associated Port devices */
141 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
142 PLIST_ENTRY Entry
= Head
->Flink
;
143 Status
= STATUS_SUCCESS
;
144 while (Entry
!= Head
)
146 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Entry
, PORT_DEVICE_EXTENSION
, ListEntry
);
147 NTSTATUS IntermediateStatus
;
149 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
150 IntermediateStatus
= ForwardIrpAndWait(DevExt
->DeviceObject
, Irp
);
151 if (!NT_SUCCESS(IntermediateStatus
))
152 Status
= IntermediateStatus
;
153 Entry
= Entry
->Flink
;
158 DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
159 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
164 Irp
->IoStatus
.Status
= Status
;
165 Irp
->IoStatus
.Information
= 0;
166 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
171 static NTSTATUS NTAPI
173 IN PDEVICE_OBJECT DeviceObject
,
176 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
178 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
180 /* Forward some IRPs to lower device */
181 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
184 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
185 return ForwardIrpAndForget(DeviceObject
, Irp
);
188 DPRINT1("Port DO stub for major function 0x%lx\n",
189 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
191 Status
= Irp
->IoStatus
.Status
;
197 DPRINT1("Class DO stub for major function 0x%lx\n",
198 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
200 Status
= Irp
->IoStatus
.Status
;
203 Irp
->IoStatus
.Status
= Status
;
204 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
210 IN PUNICODE_STRING RegistryPath
,
211 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
213 UNICODE_STRING ParametersRegistryKey
;
214 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
217 ULONG DefaultConnectMultiplePorts
= 0;
218 ULONG DefaultDataQueueSize
= 0x64;
219 UNICODE_STRING DefaultDeviceBaseName
= RTL_CONSTANT_STRING(L
"KeyboardClass");
221 ParametersRegistryKey
.Length
= 0;
222 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
223 ParametersRegistryKey
.Buffer
= ExAllocatePool(PagedPool
, ParametersRegistryKey
.MaximumLength
);
224 if (!ParametersRegistryKey
.Buffer
)
226 DPRINT("ExAllocatePool() failed\n");
227 return STATUS_INSUFFICIENT_RESOURCES
;
229 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
230 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
231 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
233 RtlZeroMemory(Parameters
, sizeof(Parameters
));
235 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
236 Parameters
[0].Name
= L
"ConnectMultiplePorts";
237 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
238 Parameters
[0].DefaultType
= REG_DWORD
;
239 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
240 Parameters
[0].DefaultLength
= sizeof(ULONG
);
242 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
243 Parameters
[1].Name
= L
"KeyboardDataQueueSize";
244 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
245 Parameters
[1].DefaultType
= REG_DWORD
;
246 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
247 Parameters
[1].DefaultLength
= sizeof(ULONG
);
249 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
250 Parameters
[2].Name
= L
"KeyboardDeviceBaseName";
251 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
252 Parameters
[2].DefaultType
= REG_SZ
;
253 Parameters
[2].DefaultData
= &DefaultDeviceBaseName
;
254 Parameters
[2].DefaultLength
= 0;
256 Status
= RtlQueryRegistryValues(
257 RTL_REGISTRY_ABSOLUTE
,
258 ParametersRegistryKey
.Buffer
,
263 if (NT_SUCCESS(Status
))
266 if (DriverExtension
->ConnectMultiplePorts
!= 0
267 && DriverExtension
->ConnectMultiplePorts
!= 1)
269 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
271 if (DriverExtension
->DataQueueSize
== 0)
273 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
276 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
278 /* Registry path doesn't exist. Set defaults */
279 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
280 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
281 Status
= RtlDuplicateUnicodeString(
282 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
283 &DefaultDeviceBaseName
,
284 &DriverExtension
->DeviceBaseName
);
291 CreateClassDeviceObject(
292 IN PDRIVER_OBJECT DriverObject
,
293 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
295 PCLASS_DRIVER_EXTENSION DriverExtension
;
298 UNICODE_STRING DeviceNameU
;
299 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
301 PCLASS_DEVICE_EXTENSION DeviceExtension
;
304 DPRINT("CreateClassDeviceObject(0x%p)\n", DriverObject
);
306 /* Create new device object */
307 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
308 DeviceNameU
.Length
= 0;
309 DeviceNameU
.MaximumLength
=
310 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
311 + DriverExtension
->DeviceBaseName
.Length
/* "KeyboardClass" */
312 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
313 + sizeof(UNICODE_NULL
); /* Final NULL char */
314 DeviceNameU
.Buffer
= ExAllocatePool(PagedPool
, DeviceNameU
.MaximumLength
);
315 if (!DeviceNameU
.Buffer
)
317 DPRINT("ExAllocatePool() failed\n");
318 return STATUS_INSUFFICIENT_RESOURCES
;
320 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
321 if (!NT_SUCCESS(Status
))
323 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
326 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
327 if (!NT_SUCCESS(Status
))
329 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
332 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
333 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
334 while (DeviceId
< 9999)
336 DeviceNameU
.Length
= PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
);
337 Status
= IoCreateDevice(
339 sizeof(CLASS_DEVICE_EXTENSION
),
341 FILE_DEVICE_KEYBOARD
,
342 FILE_DEVICE_SECURE_OPEN
,
345 if (NT_SUCCESS(Status
))
347 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
349 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
354 DPRINT("Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
355 Status
= STATUS_TOO_MANY_NAMES
;
357 if (!NT_SUCCESS(Status
))
359 ExFreePool(DeviceNameU
.Buffer
);
363 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
364 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
365 DeviceExtension
->Common
.IsClassDO
= TRUE
;
366 DeviceExtension
->DriverExtension
= DriverExtension
;
367 InitializeListHead(&DeviceExtension
->ListHead
);
368 KeInitializeSpinLock(&DeviceExtension
->ListSpinLock
);
369 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
370 DeviceExtension
->ReadIsPending
= FALSE
;
371 DeviceExtension
->InputCount
= 0;
372 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
));
373 Fdo
->Flags
|= DO_POWER_PAGABLE
;
374 Fdo
->Flags
|= DO_BUFFERED_IO
; /* FIXME: Why is it needed for 1st stage setup? */
375 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
377 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
378 RtlWriteRegistryValue(
379 RTL_REGISTRY_DEVICEMAP
,
380 DriverExtension
->DeviceBaseName
.Buffer
,
383 DriverExtension
->RegistryPath
.Buffer
,
384 DriverExtension
->RegistryPath
.MaximumLength
);
386 ExFreePool(DeviceNameU
.Buffer
);
391 return STATUS_SUCCESS
;
396 IN PDEVICE_OBJECT ClassDeviceObject
,
398 IN PKEYBOARD_INPUT_DATA DataStart
)
400 NTSTATUS Status
= STATUS_SUCCESS
;
402 if (ClassDeviceObject
->Flags
& DO_BUFFERED_IO
)
405 Irp
->AssociatedIrp
.SystemBuffer
,
407 sizeof(KEYBOARD_INPUT_DATA
));
409 else if (ClassDeviceObject
->Flags
& DO_DIRECT_IO
)
411 PVOID DestAddress
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
417 sizeof(KEYBOARD_INPUT_DATA
));
420 Status
= STATUS_UNSUCCESSFUL
;
429 sizeof(KEYBOARD_INPUT_DATA
));
433 Status
= _SEH_GetExceptionCode();
443 IN PDEVICE_OBJECT ClassDeviceObject
,
444 IN OUT PKEYBOARD_INPUT_DATA DataStart
,
445 IN PKEYBOARD_INPUT_DATA DataEnd
,
446 IN OUT PULONG ConsumedCount
)
448 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
451 PIO_STACK_LOCATION Stack
;
452 ULONG InputCount
= DataEnd
- DataStart
;
455 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
457 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
459 DPRINT("ClassCallback()\n");
460 /* A filter driver might have consumed all the data already; I'm
461 * not sure if they are supposed to move the packets when they
462 * consume them though.
464 if (ClassDeviceExtension
->ReadIsPending
== TRUE
&& InputCount
)
468 Irp
= ClassDeviceObject
->CurrentIrp
;
469 ClassDeviceObject
->CurrentIrp
= NULL
;
470 Stack
= IoGetCurrentIrpStackLocation(Irp
);
472 /* A read request is waiting for input, so go straight to it */
473 Status
= FillOneEntry(
478 if (NT_SUCCESS(Status
))
480 /* Go to next packet and complete this request with STATUS_SUCCESS */
481 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
482 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INPUT_DATA
);
483 Stack
->Parameters
.Read
.Length
= sizeof(KEYBOARD_INPUT_DATA
);
485 ClassDeviceExtension
->ReadIsPending
= FALSE
;
487 /* Skip the packet we just sent away */
494 /* If we have data from the port driver and a higher service to send the data to */
497 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
498 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
500 ReadSize
= InputCount
;
503 * If we exceed the buffer, data gets thrown away...
504 * Try at least to display a dialog
507 IoRaiseHardError(Irp
, NULL
, ClassDeviceObject
);
510 * Move the input data from the port data queue to our class data
514 ClassDeviceExtension
->PortData
,
516 sizeof(KEYBOARD_INPUT_DATA
) * ReadSize
);
518 /* Move the pointer and counter up */
519 ClassDeviceExtension
->PortData
+= ReadSize
;
520 ClassDeviceExtension
->InputCount
+= ReadSize
;
522 (*ConsumedCount
) += ReadSize
;
526 DPRINT("ClassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount
);
529 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
533 IoStartNextPacket(ClassDeviceObject
, FALSE
);
534 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
537 DPRINT("Leaving ClassCallback()\n");
541 /* Send IOCTL_INTERNAL_*_CONNECT to port */
544 IN PDEVICE_OBJECT PortDO
,
545 IN PDEVICE_OBJECT ClassDO
)
549 IO_STATUS_BLOCK IoStatus
;
550 CONNECT_DATA ConnectData
;
553 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
555 ConnectData
.ClassDeviceObject
= ClassDO
;
556 ConnectData
.ClassService
= ClassCallback
;
558 Irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_KEYBOARD_CONNECT
,
560 &ConnectData
, sizeof(CONNECT_DATA
),
562 TRUE
, &Event
, &IoStatus
);
564 Status
= IoCallDriver(PortDO
, Irp
);
566 if (Status
== STATUS_PENDING
)
567 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
569 IoStatus
.Status
= Status
;
571 if (NT_SUCCESS(IoStatus
.Status
))
573 ObReferenceObject(PortDO
);
574 ExInterlockedInsertTailList(
575 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListHead
,
576 &((PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
)->ListEntry
,
577 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListSpinLock
);
578 if (ClassDO
->StackSize
<= PortDO
->StackSize
)
580 /* Increase the stack size, in case we have to
581 * forward some IRPs to the port device object
583 ClassDO
->StackSize
= PortDO
->StackSize
+ 1;
587 return IoStatus
.Status
;
590 static NTSTATUS NTAPI
592 IN PDRIVER_OBJECT DriverObject
,
593 IN PDEVICE_OBJECT Pdo
)
595 PCLASS_DRIVER_EXTENSION DriverExtension
;
596 PDEVICE_OBJECT Fdo
= NULL
;
597 PPORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
600 DPRINT("ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
602 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
605 /* We're getting a NULL Pdo at the first call as we're a legacy driver.
606 * Use it to search for legacy port drivers. */
607 return SearchForLegacyDrivers(DriverObject
, DriverExtension
);
609 /* Create new device object */
610 Status
= IoCreateDevice(
612 sizeof(PORT_DEVICE_EXTENSION
),
615 Pdo
->Characteristics
& FILE_DEVICE_SECURE_OPEN
? FILE_DEVICE_SECURE_OPEN
: 0,
618 if (!NT_SUCCESS(Status
))
620 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
624 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
625 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
626 DeviceExtension
->Common
.IsClassDO
= FALSE
;
627 DeviceExtension
->DeviceObject
= Fdo
;
628 DeviceExtension
->PnpState
= dsStopped
;
629 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
630 if (!NT_SUCCESS(Status
))
632 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
635 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
636 Fdo
->Flags
|= DO_POWER_PAGABLE
;
637 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
638 Fdo
->Flags
|= DO_BUFFERED_IO
;
639 if (DeviceExtension
->LowerDevice
->Flags
& DO_DIRECT_IO
)
640 Fdo
->Flags
|= DO_DIRECT_IO
;
642 if (DriverExtension
->ConnectMultiplePorts
)
643 DeviceExtension
->ClassDO
= DriverExtension
->MainClassDeviceObject
;
646 /* We need a new class device object for this Fdo */
647 Status
= CreateClassDeviceObject(
649 &DeviceExtension
->ClassDO
);
650 if (!NT_SUCCESS(Status
))
652 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
656 Status
= ConnectPortDriver(Fdo
, DeviceExtension
->ClassDO
);
657 if (!NT_SUCCESS(Status
))
659 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status
);
662 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
664 /* Register interface */
665 Status
= IoRegisterDeviceInterface(
667 &GUID_DEVINTERFACE_KEYBOARD
,
669 &DeviceExtension
->InterfaceName
);
670 if (Status
== STATUS_INVALID_PARAMETER_1
)
672 /* The Pdo was a strange one ; maybe it is a legacy device.
673 * Ignore the error. */
674 return STATUS_SUCCESS
;
676 else if (!NT_SUCCESS(Status
))
678 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status
);
682 return STATUS_SUCCESS
;
687 if (DeviceExtension
->LowerDevice
)
688 IoDetachDevice(DeviceExtension
->LowerDevice
);
689 if (DriverExtension
->ConnectMultiplePorts
&& DeviceExtension
->ClassDO
)
691 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
;
692 ClassDeviceExtension
= (PCLASS_DEVICE_EXTENSION
)DeviceExtension
->ClassDO
->DeviceExtension
;
693 ExFreePool(ClassDeviceExtension
->PortData
);
703 IN PDEVICE_OBJECT DeviceObject
,
706 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
707 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
709 ASSERT(DeviceExtension
->Common
.IsClassDO
);
711 if (DeviceExtension
->InputCount
> 0)
716 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &oldIrql
);
718 Status
= FillOneEntry(
721 DeviceExtension
->PortData
- DeviceExtension
->InputCount
);
723 if (NT_SUCCESS(Status
))
725 if (DeviceExtension
->InputCount
> 1)
728 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
729 DeviceExtension
->PortData
- DeviceExtension
->InputCount
+ 1,
730 (DeviceExtension
->InputCount
- 1) * sizeof(KEYBOARD_INPUT_DATA
));
733 DeviceExtension
->PortData
--;
734 DeviceExtension
->InputCount
--;
735 DeviceExtension
->ReadIsPending
= FALSE
;
737 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INPUT_DATA
);
738 Stack
->Parameters
.Read
.Length
= sizeof(KEYBOARD_INPUT_DATA
);
741 /* Go to next packet and complete this request */
742 Irp
->IoStatus
.Status
= Status
;
743 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
745 IoStartNextPacket(DeviceObject
, FALSE
);
746 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, oldIrql
);
750 DeviceExtension
->ReadIsPending
= TRUE
;
755 SearchForLegacyDrivers(
756 IN PDRIVER_OBJECT DriverObject
,
757 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
759 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
760 UNICODE_STRING PortBaseName
= {0, };
761 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
762 OBJECT_ATTRIBUTES ObjectAttributes
;
763 HANDLE hDeviceMapKey
= (HANDLE
)-1;
764 HANDLE hPortKey
= (HANDLE
)-1;
766 ULONG Size
, ResultLength
;
769 /* Create port base name, by replacing Class by Port at the end of the class base name */
770 Status
= RtlDuplicateUnicodeString(
771 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
772 &DriverExtension
->DeviceBaseName
,
774 if (!NT_SUCCESS(Status
))
776 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
779 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
780 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
782 /* Allocate memory */
783 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
784 KeyValueInformation
= ExAllocatePool(PagedPool
, Size
);
785 if (!KeyValueInformation
)
787 DPRINT("ExAllocatePool() failed\n");
788 Status
= STATUS_INSUFFICIENT_RESOURCES
;
792 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
793 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
794 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
795 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
797 DPRINT("HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
798 Status
= STATUS_SUCCESS
;
801 else if (!NT_SUCCESS(Status
))
803 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
808 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
809 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
810 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
812 DPRINT("HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
813 Status
= STATUS_SUCCESS
;
816 else if (!NT_SUCCESS(Status
))
818 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
822 /* Read each value name */
823 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
825 UNICODE_STRING PortName
;
826 PDEVICE_OBJECT PortDeviceObject
= NULL
;
827 PFILE_OBJECT FileObject
= NULL
;
829 PortName
.Length
= PortName
.MaximumLength
= KeyValueInformation
->NameLength
;
830 PortName
.Buffer
= KeyValueInformation
->Name
;
832 /* Open the device object pointer */
833 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
834 if (!NT_SUCCESS(Status
))
836 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status
);
839 DPRINT("Legacy driver found: %wZ\n", &PortDeviceObject
->DriverObject
->DriverName
);
841 Status
= ClassAddDevice(DriverObject
, PortDeviceObject
);
842 if (!NT_SUCCESS(Status
))
844 /* FIXME: Log the error */
845 DPRINT("ClassAddDevice() failed with status 0x%08lx\n", Status
);
848 if (Status
== STATUS_NO_MORE_ENTRIES
)
849 Status
= STATUS_SUCCESS
;
852 if (KeyValueInformation
!= NULL
)
853 ExFreePool(KeyValueInformation
);
854 if (hDeviceMapKey
!= (HANDLE
)-1)
855 ZwClose(hDeviceMapKey
);
856 if (hPortKey
!= (HANDLE
)-1)
862 * Standard DriverEntry method.
866 IN PDRIVER_OBJECT DriverObject
,
867 IN PUNICODE_STRING RegistryPath
)
869 PCLASS_DRIVER_EXTENSION DriverExtension
;
873 Status
= IoAllocateDriverObjectExtension(
876 sizeof(CLASS_DRIVER_EXTENSION
),
877 (PVOID
*)&DriverExtension
);
878 if (!NT_SUCCESS(Status
))
880 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
883 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
885 Status
= RtlDuplicateUnicodeString(
886 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
888 &DriverExtension
->RegistryPath
);
889 if (!NT_SUCCESS(Status
))
891 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
895 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
896 if (!NT_SUCCESS(Status
))
898 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
902 if (DriverExtension
->ConnectMultiplePorts
== 1)
904 Status
= CreateClassDeviceObject(
906 &DriverExtension
->MainClassDeviceObject
);
907 if (!NT_SUCCESS(Status
))
909 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
914 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
915 DriverObject
->DriverUnload
= DriverUnload
;
917 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
918 DriverObject
->MajorFunction
[i
] = IrpStub
;
920 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
921 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
922 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
923 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
924 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
925 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ForwardIrpAndForget
;
926 DriverObject
->DriverStartIo
= ClassStartIo
;
928 return STATUS_SUCCESS
;