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 #include <pseh/pseh2.h>
17 static DRIVER_UNLOAD DriverUnload
;
18 static DRIVER_DISPATCH ClassCreate
;
19 static DRIVER_DISPATCH ClassClose
;
20 static DRIVER_DISPATCH ClassCleanup
;
21 static DRIVER_DISPATCH ClassRead
;
22 static DRIVER_DISPATCH ClassDeviceControl
;
23 static DRIVER_DISPATCH IrpStub
;
24 static DRIVER_ADD_DEVICE ClassAddDevice
;
25 static DRIVER_STARTIO ClassStartIo
;
26 static DRIVER_CANCEL ClassCancelRoutine
;
29 IN PDEVICE_OBJECT DeviceObject
,
34 DriverUnload(IN PDRIVER_OBJECT DriverObject
)
36 // nothing to do here yet
41 IN PDEVICE_OBJECT DeviceObject
,
44 TRACE_(CLASS_NAME
, "IRP_MJ_CREATE\n");
46 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
47 return ForwardIrpAndForget(DeviceObject
, Irp
);
49 /* FIXME: open all associated Port devices */
50 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
51 Irp
->IoStatus
.Information
= 0;
52 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
53 return STATUS_SUCCESS
;
58 IN PDEVICE_OBJECT DeviceObject
,
61 TRACE_(CLASS_NAME
, "IRP_MJ_CLOSE\n");
63 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
64 return ForwardIrpAndForget(DeviceObject
, Irp
);
66 /* FIXME: close all associated Port devices */
67 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
68 Irp
->IoStatus
.Information
= 0;
69 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
70 return STATUS_SUCCESS
;
75 IN PDEVICE_OBJECT DeviceObject
,
78 TRACE_(CLASS_NAME
, "IRP_MJ_CLEANUP\n");
80 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
81 return ForwardIrpAndForget(DeviceObject
, Irp
);
83 /* FIXME: cleanup all associated Port devices */
84 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
85 Irp
->IoStatus
.Information
= 0;
86 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
87 return STATUS_SUCCESS
;
92 IN PDEVICE_OBJECT DeviceObject
,
95 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
99 TRACE_(CLASS_NAME
, "IRP_MJ_READ\n");
101 ASSERT(DeviceExtension
->Common
.IsClassDO
);
103 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
104 return ForwardIrpAndForget(DeviceObject
, Irp
);
106 if (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
< sizeof(KEYBOARD_INPUT_DATA
))
108 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
109 Irp
->IoStatus
.Information
= 0;
110 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
112 return STATUS_BUFFER_TOO_SMALL
;
115 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
116 Status
= HandleReadIrp(DeviceObject
, Irp
, FALSE
);
117 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
121 static NTSTATUS NTAPI
123 IN PDEVICE_OBJECT DeviceObject
,
126 //PCLASS_DEVICE_EXTENSION DeviceExtension;
127 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
129 TRACE_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL\n");
131 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
132 return ForwardIrpAndForget(DeviceObject
, Irp
);
134 //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
136 switch (IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
)
138 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
139 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
140 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
141 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
143 /* FIXME: We hope that all devices will return the same result.
144 * Ask only the first one */
145 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
146 if (Head
->Flink
!= Head
)
148 /* We have at least one device */
149 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Head
->Flink
, PORT_DEVICE_EXTENSION
, ListEntry
);
150 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
151 IoSkipCurrentIrpStackLocation(Irp
);
152 return IoCallDriver(DevExt
->DeviceObject
, Irp
);
156 case IOCTL_KEYBOARD_SET_INDICATORS
:
157 case IOCTL_KEYBOARD_SET_TYPEMATIC
: /* not in MSDN, would seem logical */
159 /* Send it to all associated Port devices */
160 PLIST_ENTRY Head
= &((PCLASS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->ListHead
;
161 PLIST_ENTRY Entry
= Head
->Flink
;
162 Status
= STATUS_SUCCESS
;
163 while (Entry
!= Head
)
165 PPORT_DEVICE_EXTENSION DevExt
= CONTAINING_RECORD(Entry
, PORT_DEVICE_EXTENSION
, ListEntry
);
166 NTSTATUS IntermediateStatus
;
168 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
169 IntermediateStatus
= ForwardIrpAndWait(DevExt
->DeviceObject
, Irp
);
170 if (!NT_SUCCESS(IntermediateStatus
))
171 Status
= IntermediateStatus
;
172 Entry
= Entry
->Flink
;
177 WARN_(CLASS_NAME
, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
178 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
183 Irp
->IoStatus
.Status
= Status
;
184 Irp
->IoStatus
.Information
= 0;
185 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
190 static NTSTATUS NTAPI
192 IN PDEVICE_OBJECT DeviceObject
,
195 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
197 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
199 /* Forward some IRPs to lower device */
200 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
203 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
204 return ForwardIrpAndForget(DeviceObject
, Irp
);
207 ERR_(CLASS_NAME
, "Port DO stub for major function 0x%lx\n",
208 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
215 ERR_(CLASS_NAME
, "Class DO stub for major function 0x%lx\n",
216 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
220 Irp
->IoStatus
.Status
= Status
;
221 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
227 IN PUNICODE_STRING RegistryPath
,
228 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
230 UNICODE_STRING ParametersRegistryKey
;
231 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
234 /* HACK: We don't support multiple devices with this disabled */
235 ULONG DefaultConnectMultiplePorts
= 1;
236 ULONG DefaultDataQueueSize
= 0x64;
237 PCWSTR DefaultDeviceBaseName
= L
"KeyboardClass";
239 ParametersRegistryKey
.Length
= 0;
240 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
241 ParametersRegistryKey
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ParametersRegistryKey
.MaximumLength
, CLASS_TAG
);
242 if (!ParametersRegistryKey
.Buffer
)
244 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
245 return STATUS_NO_MEMORY
;
247 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
248 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
249 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
251 RtlZeroMemory(Parameters
, sizeof(Parameters
));
253 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
254 Parameters
[0].Name
= L
"ConnectMultiplePorts";
255 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
256 Parameters
[0].DefaultType
= REG_DWORD
;
257 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
258 Parameters
[0].DefaultLength
= sizeof(ULONG
);
260 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
261 Parameters
[1].Name
= L
"KeyboardDataQueueSize";
262 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
263 Parameters
[1].DefaultType
= REG_DWORD
;
264 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
265 Parameters
[1].DefaultLength
= sizeof(ULONG
);
267 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
268 Parameters
[2].Name
= L
"KeyboardDeviceBaseName";
269 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
270 Parameters
[2].DefaultType
= REG_SZ
;
271 Parameters
[2].DefaultData
= (PVOID
)DefaultDeviceBaseName
;
272 Parameters
[2].DefaultLength
= 0;
274 Status
= RtlQueryRegistryValues(
275 RTL_REGISTRY_ABSOLUTE
,
276 ParametersRegistryKey
.Buffer
,
281 if (NT_SUCCESS(Status
))
284 if (DriverExtension
->ConnectMultiplePorts
!= 0
285 && DriverExtension
->ConnectMultiplePorts
!= 1)
287 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
289 if (DriverExtension
->DataQueueSize
== 0)
291 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
294 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
296 /* Registry path doesn't exist. Set defaults */
297 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
298 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
299 if (RtlCreateUnicodeString(&DriverExtension
->DeviceBaseName
, DefaultDeviceBaseName
))
300 Status
= STATUS_SUCCESS
;
302 Status
= STATUS_NO_MEMORY
;
305 ExFreePoolWithTag(ParametersRegistryKey
.Buffer
, CLASS_TAG
);
310 CreateClassDeviceObject(
311 IN PDRIVER_OBJECT DriverObject
,
312 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
314 PCLASS_DRIVER_EXTENSION DriverExtension
;
317 UNICODE_STRING DeviceNameU
;
318 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
320 PCLASS_DEVICE_EXTENSION DeviceExtension
;
323 TRACE_(CLASS_NAME
, "CreateClassDeviceObject(0x%p)\n", DriverObject
);
325 /* Create new device object */
326 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
327 DeviceNameU
.Length
= 0;
328 DeviceNameU
.MaximumLength
=
329 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
330 + DriverExtension
->DeviceBaseName
.Length
/* "KeyboardClass" */
331 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
332 + sizeof(UNICODE_NULL
); /* Final NULL char */
333 DeviceNameU
.Buffer
= ExAllocatePoolWithTag(PagedPool
, DeviceNameU
.MaximumLength
, CLASS_TAG
);
334 if (!DeviceNameU
.Buffer
)
336 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
337 return STATUS_NO_MEMORY
;
339 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
340 if (!NT_SUCCESS(Status
))
342 WARN_(CLASS_NAME
, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
345 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
346 if (!NT_SUCCESS(Status
))
348 WARN_(CLASS_NAME
, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
351 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
352 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
353 while (DeviceId
< 9999)
355 DeviceNameU
.Length
= (USHORT
)(PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
));
356 Status
= IoCreateDevice(
358 sizeof(CLASS_DEVICE_EXTENSION
),
360 FILE_DEVICE_KEYBOARD
,
361 FILE_DEVICE_SECURE_OPEN
,
364 if (NT_SUCCESS(Status
))
366 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
368 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
373 WARN_(CLASS_NAME
, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
374 Status
= STATUS_TOO_MANY_NAMES
;
376 if (!NT_SUCCESS(Status
))
378 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
382 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
383 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
384 DeviceExtension
->Common
.IsClassDO
= TRUE
;
385 DeviceExtension
->DriverExtension
= DriverExtension
;
386 InitializeListHead(&DeviceExtension
->ListHead
);
387 KeInitializeSpinLock(&DeviceExtension
->ListSpinLock
);
388 KeInitializeSpinLock(&DeviceExtension
->SpinLock
);
389 DeviceExtension
->InputCount
= 0;
390 DeviceExtension
->PortData
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
), CLASS_TAG
);
391 if (!DeviceExtension
->PortData
)
393 ExFreePoolWithTag(DeviceNameU
.Buffer
, CLASS_TAG
);
394 return STATUS_NO_MEMORY
;
396 DeviceExtension
->DeviceName
= DeviceNameU
.Buffer
;
397 Fdo
->Flags
|= DO_POWER_PAGABLE
;
398 Fdo
->Flags
|= DO_BUFFERED_IO
; /* FIXME: Why is it needed for 1st stage setup? */
399 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
401 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
402 RtlWriteRegistryValue(
403 RTL_REGISTRY_DEVICEMAP
,
404 DriverExtension
->DeviceBaseName
.Buffer
,
405 DeviceExtension
->DeviceName
,
407 DriverExtension
->RegistryPath
.Buffer
,
408 DriverExtension
->RegistryPath
.MaximumLength
);
413 return STATUS_SUCCESS
;
418 IN PDEVICE_OBJECT ClassDeviceObject
,
420 IN PKEYBOARD_INPUT_DATA DataStart
,
421 IN SIZE_T NumberOfEntries
)
423 NTSTATUS Status
= STATUS_SUCCESS
;
425 if (ClassDeviceObject
->Flags
& DO_BUFFERED_IO
)
428 Irp
->AssociatedIrp
.SystemBuffer
,
430 NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
));
432 else if (ClassDeviceObject
->Flags
& DO_DIRECT_IO
)
434 PVOID DestAddress
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
440 NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
));
443 Status
= STATUS_UNSUCCESSFUL
;
452 NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
));
454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
456 Status
= _SEH2_GetExceptionCode();
466 IN PDEVICE_OBJECT ClassDeviceObject
,
467 IN OUT PKEYBOARD_INPUT_DATA DataStart
,
468 IN PKEYBOARD_INPUT_DATA DataEnd
,
469 IN OUT PULONG ConsumedCount
)
471 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
473 SIZE_T InputCount
= DataEnd
- DataStart
;
476 TRACE_(CLASS_NAME
, "ClassCallback()\n");
478 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
480 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
483 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
486 * We're exceeding the buffer, and data will be thrown away...
487 * FIXME: What could we do, as we are at DISPATCH_LEVEL?
489 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
492 ReadSize
= InputCount
;
495 * Move the input data from the port data queue to our class data
499 &ClassDeviceExtension
->PortData
[ClassDeviceExtension
->InputCount
],
501 sizeof(KEYBOARD_INPUT_DATA
) * ReadSize
);
503 /* Move the counter up */
504 ClassDeviceExtension
->InputCount
+= ReadSize
;
506 (*ConsumedCount
) += (ULONG
)ReadSize
;
508 /* Complete pending IRP (if any) */
509 if (ClassDeviceExtension
->PendingIrp
)
510 HandleReadIrp(ClassDeviceObject
, ClassDeviceExtension
->PendingIrp
, FALSE
);
512 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
514 TRACE_(CLASS_NAME
, "Leaving ClassCallback()\n");
518 /* Send IOCTL_INTERNAL_*_CONNECT to port */
521 IN PDEVICE_OBJECT PortDO
,
522 IN PDEVICE_OBJECT ClassDO
)
526 IO_STATUS_BLOCK IoStatus
;
527 CONNECT_DATA ConnectData
;
530 TRACE_(CLASS_NAME
, "Connecting PortDO %p to ClassDO %p\n", PortDO
, ClassDO
);
532 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
534 ConnectData
.ClassDeviceObject
= ClassDO
;
535 ConnectData
.ClassService
= ClassCallback
;
537 Irp
= IoBuildDeviceIoControlRequest(
538 IOCTL_INTERNAL_KEYBOARD_CONNECT
,
540 &ConnectData
, sizeof(CONNECT_DATA
),
542 TRUE
, &Event
, &IoStatus
);
544 return STATUS_INSUFFICIENT_RESOURCES
;
546 Status
= IoCallDriver(PortDO
, Irp
);
548 if (Status
== STATUS_PENDING
)
549 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
551 IoStatus
.Status
= Status
;
553 if (NT_SUCCESS(IoStatus
.Status
))
555 ObReferenceObject(PortDO
);
556 ExInterlockedInsertTailList(
557 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListHead
,
558 &((PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
)->ListEntry
,
559 &((PCLASS_DEVICE_EXTENSION
)ClassDO
->DeviceExtension
)->ListSpinLock
);
560 if (ClassDO
->StackSize
<= PortDO
->StackSize
)
562 /* Increase the stack size, in case we have to
563 * forward some IRPs to the port device object
565 ClassDO
->StackSize
= PortDO
->StackSize
+ 1;
569 return IoStatus
.Status
;
572 /* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
575 IN PDEVICE_OBJECT PortDO
)
577 PPORT_DEVICE_EXTENSION DeviceExtension
;
578 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
;
579 PCLASS_DRIVER_EXTENSION DriverExtension
;
582 IO_STATUS_BLOCK IoStatus
;
586 TRACE_(CLASS_NAME
, "Destroying PortDO %p\n", PortDO
);
588 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)PortDO
->DeviceExtension
;
589 ClassDeviceExtension
= DeviceExtension
->ClassDO
->DeviceExtension
;
590 DriverExtension
= IoGetDriverObjectExtension(PortDO
->DriverObject
, PortDO
->DriverObject
);
592 /* Send IOCTL_INTERNAL_*_DISCONNECT */
593 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
594 Irp
= IoBuildDeviceIoControlRequest(
595 IOCTL_INTERNAL_KEYBOARD_DISCONNECT
,
599 TRUE
, &Event
, &IoStatus
);
602 Status
= IoCallDriver(PortDO
, Irp
);
603 if (Status
== STATUS_PENDING
)
604 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
607 /* Remove from ClassDeviceExtension->ListHead list */
608 KeAcquireSpinLock(&ClassDeviceExtension
->ListSpinLock
, &OldIrql
);
609 RemoveHeadList(DeviceExtension
->ListEntry
.Blink
);
610 KeReleaseSpinLock(&ClassDeviceExtension
->ListSpinLock
, OldIrql
);
612 /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
613 RtlDeleteRegistryValue(
614 RTL_REGISTRY_DEVICEMAP
,
615 DriverExtension
->DeviceBaseName
.Buffer
,
616 ClassDeviceExtension
->DeviceName
);
618 if (DeviceExtension
->LowerDevice
)
619 IoDetachDevice(DeviceExtension
->LowerDevice
);
620 ObDereferenceObject(PortDO
);
622 if (!DriverExtension
->ConnectMultiplePorts
&& DeviceExtension
->ClassDO
)
624 ExFreePoolWithTag(ClassDeviceExtension
->PortData
, CLASS_TAG
);
625 ExFreePoolWithTag((PVOID
)ClassDeviceExtension
->DeviceName
, CLASS_TAG
);
626 IoDeleteDevice(DeviceExtension
->ClassDO
);
629 IoDeleteDevice(PortDO
);
632 static NTSTATUS NTAPI
634 IN PDRIVER_OBJECT DriverObject
,
635 IN PDEVICE_OBJECT Pdo
)
637 PCLASS_DRIVER_EXTENSION DriverExtension
;
638 PDEVICE_OBJECT Fdo
= NULL
;
639 PPORT_DEVICE_EXTENSION DeviceExtension
= NULL
;
642 TRACE_(CLASS_NAME
, "ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
644 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
647 /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
648 return STATUS_SUCCESS
;
650 /* Create new device object */
651 Status
= IoCreateDevice(
653 sizeof(PORT_DEVICE_EXTENSION
),
656 Pdo
->Characteristics
& FILE_DEVICE_SECURE_OPEN
? FILE_DEVICE_SECURE_OPEN
: 0,
659 if (!NT_SUCCESS(Status
))
661 WARN_(CLASS_NAME
, "IoCreateDevice() failed with status 0x%08lx\n", Status
);
664 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
666 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
667 RtlZeroMemory(DeviceExtension
, sizeof(PORT_DEVICE_EXTENSION
));
668 DeviceExtension
->Common
.IsClassDO
= FALSE
;
669 DeviceExtension
->DeviceObject
= Fdo
;
670 DeviceExtension
->PnpState
= dsStopped
;
671 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
672 if (!NT_SUCCESS(Status
))
674 WARN_(CLASS_NAME
, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
677 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
678 Fdo
->Flags
|= DO_POWER_PAGABLE
;
679 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
680 Fdo
->Flags
|= DO_BUFFERED_IO
;
681 if (DeviceExtension
->LowerDevice
->Flags
& DO_DIRECT_IO
)
682 Fdo
->Flags
|= DO_DIRECT_IO
;
684 if (DriverExtension
->ConnectMultiplePorts
)
685 DeviceExtension
->ClassDO
= DriverExtension
->MainClassDeviceObject
;
688 /* We need a new class device object for this Fdo */
689 Status
= CreateClassDeviceObject(
691 &DeviceExtension
->ClassDO
);
692 if (!NT_SUCCESS(Status
))
694 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
698 Status
= ConnectPortDriver(Fdo
, DeviceExtension
->ClassDO
);
699 if (!NT_SUCCESS(Status
))
701 WARN_(CLASS_NAME
, "ConnectPortDriver() failed with status 0x%08lx\n", Status
);
704 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
706 /* Register interface ; ignore the error (if any) as having
707 * a registred interface is not so important... */
708 Status
= IoRegisterDeviceInterface(
710 &GUID_DEVINTERFACE_KEYBOARD
,
712 &DeviceExtension
->InterfaceName
);
713 if (!NT_SUCCESS(Status
))
714 DeviceExtension
->InterfaceName
.Length
= 0;
716 return STATUS_SUCCESS
;
720 DestroyPortDriver(Fdo
);
726 IN PDEVICE_OBJECT DeviceObject
,
729 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= DeviceObject
->DeviceExtension
;
731 BOOLEAN wasQueued
= FALSE
;
733 TRACE_(CLASS_NAME
, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
735 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
737 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
739 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
741 if (ClassDeviceExtension
->PendingIrp
== Irp
)
743 ClassDeviceExtension
->PendingIrp
= NULL
;
746 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
750 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
751 Irp
->IoStatus
.Information
= 0;
752 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
756 DPRINT1("Cancelled IRP is not pending. Race condition?\n");
762 IN PDEVICE_OBJECT DeviceObject
,
766 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
770 TRACE_(CLASS_NAME
, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
772 ASSERT(DeviceExtension
->Common
.IsClassDO
);
774 if (DeviceExtension
->InputCount
> 0)
776 SIZE_T NumberOfEntries
;
778 NumberOfEntries
= MIN(
779 DeviceExtension
->InputCount
,
780 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
/ sizeof(KEYBOARD_INPUT_DATA
));
782 Status
= FillEntries(
785 DeviceExtension
->PortData
,
788 if (NT_SUCCESS(Status
))
790 if (DeviceExtension
->InputCount
> NumberOfEntries
)
793 &DeviceExtension
->PortData
[0],
794 &DeviceExtension
->PortData
[NumberOfEntries
],
795 (DeviceExtension
->InputCount
- NumberOfEntries
) * sizeof(KEYBOARD_INPUT_DATA
));
798 DeviceExtension
->InputCount
-= NumberOfEntries
;
800 Irp
->IoStatus
.Information
= NumberOfEntries
* sizeof(KEYBOARD_INPUT_DATA
);
803 /* Go to next packet and complete this request */
804 Irp
->IoStatus
.Status
= Status
;
806 (VOID
)IoSetCancelRoutine(Irp
, NULL
);
807 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
808 DeviceExtension
->PendingIrp
= NULL
;
812 IoAcquireCancelSpinLock(&OldIrql
);
815 DeviceExtension
->PendingIrp
= NULL
;
816 Status
= STATUS_CANCELLED
;
820 IoMarkIrpPending(Irp
);
821 DeviceExtension
->PendingIrp
= Irp
;
822 (VOID
)IoSetCancelRoutine(Irp
, ClassCancelRoutine
);
823 Status
= STATUS_PENDING
;
825 IoReleaseCancelSpinLock(OldIrql
);
830 static NTSTATUS NTAPI
832 IN PDEVICE_OBJECT DeviceObject
,
835 PPORT_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
836 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
837 OBJECT_ATTRIBUTES ObjectAttributes
;
838 IO_STATUS_BLOCK Iosb
;
841 switch (IrpSp
->MinorFunction
)
843 case IRP_MN_START_DEVICE
:
844 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
845 if (NT_SUCCESS(Status
))
847 InitializeObjectAttributes(&ObjectAttributes
,
848 &DeviceExtension
->InterfaceName
,
849 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
853 Status
= ZwOpenFile(&DeviceExtension
->FileHandle
,
859 if (!NT_SUCCESS(Status
))
860 DeviceExtension
->FileHandle
= NULL
;
863 DeviceExtension
->FileHandle
= NULL
;
864 Irp
->IoStatus
.Status
= Status
;
865 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
868 case IRP_MN_REMOVE_DEVICE
:
869 case IRP_MN_STOP_DEVICE
:
870 if (DeviceExtension
->FileHandle
)
872 ZwClose(DeviceExtension
->FileHandle
);
873 DeviceExtension
->FileHandle
= NULL
;
875 Status
= STATUS_SUCCESS
;
879 Status
= Irp
->IoStatus
.Status
;
883 Irp
->IoStatus
.Status
= Status
;
884 if (NT_SUCCESS(Status
) || Status
== STATUS_NOT_SUPPORTED
)
886 IoSkipCurrentIrpStackLocation(Irp
);
887 return IoCallDriver(DeviceExtension
->LowerDevice
, Irp
);
891 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
898 IN PDEVICE_OBJECT DeviceObject
,
901 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
904 TRACE_(CLASS_NAME
, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
906 ASSERT(DeviceExtension
->Common
.IsClassDO
);
908 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &OldIrql
);
909 HandleReadIrp(DeviceObject
, Irp
, TRUE
);
910 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, OldIrql
);
914 SearchForLegacyDrivers(
915 IN PDRIVER_OBJECT DriverObject
,
916 IN PVOID Context
, /* PCLASS_DRIVER_EXTENSION */
919 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
920 PCLASS_DRIVER_EXTENSION DriverExtension
;
921 UNICODE_STRING PortBaseName
= { 0, 0, NULL
};
922 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
923 OBJECT_ATTRIBUTES ObjectAttributes
;
924 HANDLE hDeviceMapKey
= (HANDLE
)-1;
925 HANDLE hPortKey
= (HANDLE
)-1;
927 ULONG Size
, ResultLength
;
930 TRACE_(CLASS_NAME
, "SearchForLegacyDrivers(%p %p %lu)\n",
931 DriverObject
, Context
, Count
);
935 DriverExtension
= (PCLASS_DRIVER_EXTENSION
)Context
;
937 /* Create port base name, by replacing Class by Port at the end of the class base name */
938 Status
= DuplicateUnicodeString(
939 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
940 &DriverExtension
->DeviceBaseName
,
942 if (!NT_SUCCESS(Status
))
944 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
947 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
948 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
950 /* Allocate memory */
951 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
952 KeyValueInformation
= ExAllocatePoolWithTag(PagedPool
, Size
, CLASS_TAG
);
953 if (!KeyValueInformation
)
955 WARN_(CLASS_NAME
, "ExAllocatePoolWithTag() failed\n");
956 Status
= STATUS_NO_MEMORY
;
960 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
961 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
962 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
963 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
965 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
966 Status
= STATUS_SUCCESS
;
969 else if (!NT_SUCCESS(Status
))
971 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
976 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
977 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
978 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
980 INFO_(CLASS_NAME
, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
981 Status
= STATUS_SUCCESS
;
984 else if (!NT_SUCCESS(Status
))
986 WARN_(CLASS_NAME
, "ZwOpenKey() failed with status 0x%08lx\n", Status
);
990 /* Read each value name */
991 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
993 UNICODE_STRING PortName
;
994 PDEVICE_OBJECT PortDeviceObject
= NULL
;
995 PFILE_OBJECT FileObject
= NULL
;
997 PortName
.Length
= PortName
.MaximumLength
= (USHORT
)KeyValueInformation
->NameLength
;
998 PortName
.Buffer
= KeyValueInformation
->Name
;
1000 /* Open the device object pointer */
1001 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
1002 if (!NT_SUCCESS(Status
))
1004 WARN_(CLASS_NAME
, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName
, Status
);
1007 INFO_(CLASS_NAME
, "Legacy driver found\n");
1009 Status
= ClassAddDevice(DriverObject
, PortDeviceObject
);
1010 if (!NT_SUCCESS(Status
))
1012 /* FIXME: Log the error */
1013 WARN_(CLASS_NAME
, "ClassAddDevice() failed with status 0x%08lx\n", Status
);
1016 ObDereferenceObject(FileObject
);
1020 if (KeyValueInformation
!= NULL
)
1021 ExFreePoolWithTag(KeyValueInformation
, CLASS_TAG
);
1022 if (hDeviceMapKey
!= (HANDLE
)-1)
1023 ZwClose(hDeviceMapKey
);
1024 if (hPortKey
!= (HANDLE
)-1)
1029 * Standard DriverEntry method.
1033 IN PDRIVER_OBJECT DriverObject
,
1034 IN PUNICODE_STRING RegistryPath
)
1036 PCLASS_DRIVER_EXTENSION DriverExtension
;
1040 Status
= IoAllocateDriverObjectExtension(
1043 sizeof(CLASS_DRIVER_EXTENSION
),
1044 (PVOID
*)&DriverExtension
);
1045 if (!NT_SUCCESS(Status
))
1047 WARN_(CLASS_NAME
, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
1050 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
1052 Status
= DuplicateUnicodeString(
1053 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1055 &DriverExtension
->RegistryPath
);
1056 if (!NT_SUCCESS(Status
))
1058 WARN_(CLASS_NAME
, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
1062 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
1063 if (!NT_SUCCESS(Status
))
1065 WARN_(CLASS_NAME
, "ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
1069 if (DriverExtension
->ConnectMultiplePorts
== 1)
1071 Status
= CreateClassDeviceObject(
1073 &DriverExtension
->MainClassDeviceObject
);
1074 if (!NT_SUCCESS(Status
))
1076 WARN_(CLASS_NAME
, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
1081 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
1082 DriverObject
->DriverUnload
= DriverUnload
;
1084 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1085 DriverObject
->MajorFunction
[i
] = IrpStub
;
1087 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
1088 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
1089 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
1090 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
1091 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = ClassPnp
;
1092 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
1093 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = ForwardIrpAndForget
;
1094 DriverObject
->DriverStartIo
= ClassStartIo
;
1096 /* We will detect the legacy devices later */
1097 IoRegisterDriverReinitialization(
1099 SearchForLegacyDrivers
,
1102 return STATUS_SUCCESS
;