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
;
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
:
114 case IOCTL_KEYBOARD_SET_INDICATORS
:
115 case IOCTL_KEYBOARD_SET_TYPEMATIC
: /* not in MSDN, would seem logical */
116 /* FIXME: send it to all associated Port devices */
117 Status
= STATUS_NOT_SUPPORTED
;
120 DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
121 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
122 Status
= STATUS_NOT_SUPPORTED
;
125 Irp
->IoStatus
.Status
= Status
;
126 Irp
->IoStatus
.Information
= 0;
127 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
132 static NTSTATUS NTAPI
134 IN PDEVICE_OBJECT DeviceObject
,
137 NTSTATUS Status
= STATUS_NOT_SUPPORTED
;
139 if (!((PCOMMON_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->IsClassDO
)
141 /* Forward some IRPs to lower device */
142 switch (IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)
144 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
145 return ForwardIrpAndForget(DeviceObject
, Irp
);
148 DPRINT1("Port DO stub for major function 0x%lx\n",
149 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
151 Status
= Irp
->IoStatus
.Status
;
157 DPRINT1("Class DO stub for major function 0x%lx\n",
158 IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
);
160 Status
= Irp
->IoStatus
.Status
;
163 Irp
->IoStatus
.Status
= Status
;
164 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
170 IN PUNICODE_STRING RegistryPath
,
171 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
173 UNICODE_STRING ParametersRegistryKey
;
174 RTL_QUERY_REGISTRY_TABLE Parameters
[4];
177 ULONG DefaultConnectMultiplePorts
= 0;
178 ULONG DefaultDataQueueSize
= 0x64;
179 UNICODE_STRING DefaultDeviceBaseName
= RTL_CONSTANT_STRING(L
"KeyboardClass");
181 ParametersRegistryKey
.Length
= 0;
182 ParametersRegistryKey
.MaximumLength
= RegistryPath
->Length
+ sizeof(L
"\\Parameters") + sizeof(UNICODE_NULL
);
183 ParametersRegistryKey
.Buffer
= ExAllocatePool(PagedPool
, ParametersRegistryKey
.MaximumLength
);
184 if (!ParametersRegistryKey
.Buffer
)
186 DPRINT("ExAllocatePool() failed\n");
187 return STATUS_INSUFFICIENT_RESOURCES
;
189 RtlCopyUnicodeString(&ParametersRegistryKey
, RegistryPath
);
190 RtlAppendUnicodeToString(&ParametersRegistryKey
, L
"\\Parameters");
191 ParametersRegistryKey
.Buffer
[ParametersRegistryKey
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
193 RtlZeroMemory(Parameters
, sizeof(Parameters
));
195 Parameters
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
196 Parameters
[0].Name
= L
"ConnectMultiplePorts";
197 Parameters
[0].EntryContext
= &DriverExtension
->ConnectMultiplePorts
;
198 Parameters
[0].DefaultType
= REG_DWORD
;
199 Parameters
[0].DefaultData
= &DefaultConnectMultiplePorts
;
200 Parameters
[0].DefaultLength
= sizeof(ULONG
);
202 Parameters
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
203 Parameters
[1].Name
= L
"KeyboardDataQueueSize";
204 Parameters
[1].EntryContext
= &DriverExtension
->DataQueueSize
;
205 Parameters
[1].DefaultType
= REG_DWORD
;
206 Parameters
[1].DefaultData
= &DefaultDataQueueSize
;
207 Parameters
[1].DefaultLength
= sizeof(ULONG
);
209 Parameters
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_REGISTRY_OPTIONAL
;
210 Parameters
[2].Name
= L
"KeyboardDeviceBaseName";
211 Parameters
[2].EntryContext
= &DriverExtension
->DeviceBaseName
;
212 Parameters
[2].DefaultType
= REG_SZ
;
213 Parameters
[2].DefaultData
= &DefaultDeviceBaseName
;
214 Parameters
[2].DefaultLength
= 0;
216 Status
= RtlQueryRegistryValues(
217 RTL_REGISTRY_ABSOLUTE
,
218 ParametersRegistryKey
.Buffer
,
223 if (NT_SUCCESS(Status
))
226 if (DriverExtension
->ConnectMultiplePorts
!= 0
227 && DriverExtension
->ConnectMultiplePorts
!= 1)
229 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
231 if (DriverExtension
->DataQueueSize
== 0)
233 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
236 else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
238 /* Registry path doesn't exist. Set defaults */
239 DriverExtension
->ConnectMultiplePorts
= DefaultConnectMultiplePorts
;
240 DriverExtension
->DataQueueSize
= DefaultDataQueueSize
;
241 Status
= RtlDuplicateUnicodeString(
242 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
243 &DefaultDeviceBaseName
,
244 &DriverExtension
->DeviceBaseName
);
251 CreateClassDeviceObject(
252 IN PDRIVER_OBJECT DriverObject
,
253 OUT PDEVICE_OBJECT
*ClassDO OPTIONAL
)
255 PCLASS_DRIVER_EXTENSION DriverExtension
;
256 UNICODE_STRING SymbolicLinkName
= RTL_CONSTANT_STRING(L
"\\??\\Keyboard");
259 UNICODE_STRING DeviceNameU
;
260 PWSTR DeviceIdW
= NULL
; /* Pointer into DeviceNameU.Buffer */
262 PCLASS_DEVICE_EXTENSION DeviceExtension
;
265 DPRINT("CreateClassDeviceObject(0x%p)\n", DriverObject
);
267 /* Create new device object */
268 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
269 DeviceNameU
.Length
= 0;
270 DeviceNameU
.MaximumLength
=
271 wcslen(L
"\\Device\\") * sizeof(WCHAR
) /* "\Device\" */
272 + DriverExtension
->DeviceBaseName
.Length
/* "KeyboardClass" */
273 + 4 * sizeof(WCHAR
) /* Id between 0 and 9999 */
274 + sizeof(UNICODE_NULL
); /* Final NULL char */
275 DeviceNameU
.Buffer
= ExAllocatePool(PagedPool
, DeviceNameU
.MaximumLength
);
276 if (!DeviceNameU
.Buffer
)
278 DPRINT("ExAllocatePool() failed\n");
279 return STATUS_INSUFFICIENT_RESOURCES
;
281 Status
= RtlAppendUnicodeToString(&DeviceNameU
, L
"\\Device\\");
282 if (!NT_SUCCESS(Status
))
284 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status
);
287 Status
= RtlAppendUnicodeStringToString(&DeviceNameU
, &DriverExtension
->DeviceBaseName
);
288 if (!NT_SUCCESS(Status
))
290 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status
);
293 PrefixLength
= DeviceNameU
.MaximumLength
- 4 * sizeof(WCHAR
) - sizeof(UNICODE_NULL
);
294 DeviceIdW
= &DeviceNameU
.Buffer
[PrefixLength
/ sizeof(WCHAR
)];
295 while (DeviceId
< 9999)
297 DeviceNameU
.Length
= PrefixLength
+ swprintf(DeviceIdW
, L
"%lu", DeviceId
) * sizeof(WCHAR
);
298 Status
= IoCreateDevice(
300 sizeof(CLASS_DEVICE_EXTENSION
),
302 FILE_DEVICE_KEYBOARD
,
303 FILE_DEVICE_SECURE_OPEN
,
306 if (NT_SUCCESS(Status
))
308 else if (Status
!= STATUS_OBJECT_NAME_COLLISION
)
310 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
315 DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension
->DeviceBaseName
);
316 Status
= STATUS_UNSUCCESSFUL
;
318 if (!NT_SUCCESS(Status
))
320 ExFreePool(DeviceNameU
.Buffer
);
324 DeviceExtension
= (PCLASS_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
325 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
326 DeviceExtension
->Common
.IsClassDO
= TRUE
;
327 DeviceExtension
->DriverExtension
= DriverExtension
;
328 KeInitializeSpinLock(&(DeviceExtension
->SpinLock
));
329 DeviceExtension
->ReadIsPending
= FALSE
;
330 DeviceExtension
->InputCount
= 0;
331 DeviceExtension
->PortData
= ExAllocatePool(NonPagedPool
, DeviceExtension
->DriverExtension
->DataQueueSize
* sizeof(KEYBOARD_INPUT_DATA
));
332 Fdo
->Flags
|= DO_POWER_PAGABLE
;
333 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
335 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
336 RtlWriteRegistryValue(
337 RTL_REGISTRY_DEVICEMAP
,
338 DriverExtension
->DeviceBaseName
.Buffer
,
341 DriverExtension
->RegistryPath
.Buffer
,
342 DriverExtension
->RegistryPath
.MaximumLength
);
344 /* HACK: 1st stage setup needs a keyboard to open it in user-mode
345 * Create a link to user space... */
346 IoCreateSymbolicLink(&SymbolicLinkName
, &DeviceNameU
);
348 ExFreePool(DeviceNameU
.Buffer
);
353 return STATUS_SUCCESS
;
358 IN PDEVICE_OBJECT ClassDeviceObject
,
359 IN OUT PKEYBOARD_INPUT_DATA DataStart
,
360 IN PKEYBOARD_INPUT_DATA DataEnd
,
361 IN OUT PULONG ConsumedCount
)
363 PCLASS_DEVICE_EXTENSION ClassDeviceExtension
= ClassDeviceObject
->DeviceExtension
;
366 PIO_STACK_LOCATION Stack
;
367 ULONG InputCount
= DataEnd
- DataStart
;
370 ASSERT(ClassDeviceExtension
->Common
.IsClassDO
);
372 KeAcquireSpinLock(&ClassDeviceExtension
->SpinLock
, &OldIrql
);
374 DPRINT("ClassCallback()\n");
375 /* A filter driver might have consumed all the data already; I'm
376 * not sure if they are supposed to move the packets when they
377 * consume them though.
379 if (ClassDeviceExtension
->ReadIsPending
== TRUE
&& InputCount
)
381 Irp
= ClassDeviceObject
->CurrentIrp
;
382 ClassDeviceObject
->CurrentIrp
= NULL
;
383 Stack
= IoGetCurrentIrpStackLocation(Irp
);
385 /* A read request is waiting for input, so go straight to it */
388 Irp
->MdlAddress
? MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
) : Irp
->UserBuffer
,
390 sizeof(KEYBOARD_INPUT_DATA
));
392 /* Go to next packet and complete this request with STATUS_SUCCESS */
393 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
394 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INPUT_DATA
);
395 Stack
->Parameters
.Read
.Length
= sizeof(KEYBOARD_INPUT_DATA
);
397 ClassDeviceExtension
->ReadIsPending
= FALSE
;
399 /* Skip the packet we just sent away */
405 /* If we have data from the port driver and a higher service to send the data to */
408 if (ClassDeviceExtension
->InputCount
+ InputCount
> ClassDeviceExtension
->DriverExtension
->DataQueueSize
)
409 ReadSize
= ClassDeviceExtension
->DriverExtension
->DataQueueSize
- ClassDeviceExtension
->InputCount
;
411 ReadSize
= InputCount
;
414 * FIXME: If we exceed the buffer, data gets thrown away.. better
419 * Move the input data from the port data queue to our class data
423 ClassDeviceExtension
->PortData
,
425 sizeof(KEYBOARD_INPUT_DATA
) * ReadSize
);
427 /* Move the pointer and counter up */
428 ClassDeviceExtension
->PortData
+= ReadSize
;
429 ClassDeviceExtension
->InputCount
+= ReadSize
;
431 (*ConsumedCount
) += ReadSize
;
435 DPRINT("ClassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount
);
438 KeReleaseSpinLock(&ClassDeviceExtension
->SpinLock
, OldIrql
);
442 IoStartNextPacket(ClassDeviceObject
, FALSE
);
443 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
446 DPRINT("Leaving ClassCallback()\n");
450 /* Send IOCTL_INTERNAL_*_CONNECT to port */
453 IN PDEVICE_OBJECT PortDO
,
454 IN PDEVICE_OBJECT ClassDO
)
458 IO_STATUS_BLOCK IoStatus
;
459 CONNECT_DATA ConnectData
;
462 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
464 ConnectData
.ClassDeviceObject
= ClassDO
;
465 ConnectData
.ClassService
= ClassCallback
;
467 Irp
= IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_KEYBOARD_CONNECT
,
469 &ConnectData
, sizeof(CONNECT_DATA
),
471 TRUE
, &Event
, &IoStatus
);
473 Status
= IoCallDriver(PortDO
, Irp
);
475 if (Status
== STATUS_PENDING
)
476 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
478 IoStatus
.Status
= Status
;
480 if (NT_SUCCESS(IoStatus
.Status
))
481 ObReferenceObject(PortDO
);
483 return IoStatus
.Status
;
486 static NTSTATUS NTAPI
488 IN PDRIVER_OBJECT DriverObject
,
489 IN PDEVICE_OBJECT Pdo
)
491 PCLASS_DRIVER_EXTENSION DriverExtension
;
493 PPORT_DEVICE_EXTENSION DeviceExtension
;
496 DPRINT("ClassAddDevice called. Pdo = 0x%p\n", Pdo
);
498 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
501 /* We're getting a NULL Pdo at the first call as we're a legacy driver.
502 * Use it to search for legacy port drivers. */
503 return SearchForLegacyDrivers(DriverObject
, DriverExtension
);
505 /* Create new device object */
506 Status
= IoCreateDevice(
508 sizeof(PORT_DEVICE_EXTENSION
),
511 FILE_DEVICE_SECURE_OPEN
,
514 if (!NT_SUCCESS(Status
))
516 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status
);
520 DeviceExtension
= (PPORT_DEVICE_EXTENSION
)Fdo
->DeviceExtension
;
521 RtlZeroMemory(DeviceExtension
, sizeof(CLASS_DEVICE_EXTENSION
));
522 DeviceExtension
->Common
.IsClassDO
= FALSE
;
523 DeviceExtension
->PnpState
= dsStopped
;
524 Status
= IoAttachDeviceToDeviceStackSafe(Fdo
, Pdo
, &DeviceExtension
->LowerDevice
);
525 if (!NT_SUCCESS(Status
))
527 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status
);
531 if (DeviceExtension
->LowerDevice
->Flags
& DO_POWER_PAGABLE
)
532 Fdo
->Flags
|= DO_POWER_PAGABLE
;
533 if (DeviceExtension
->LowerDevice
->Flags
& DO_BUFFERED_IO
)
534 Fdo
->Flags
|= DO_BUFFERED_IO
;
536 if (DriverExtension
->ConnectMultiplePorts
)
537 Status
= ConnectPortDriver(Fdo
, DriverExtension
->MainClassDeviceObject
);
539 Status
= ConnectPortDriver(Fdo
, Fdo
);
540 if (!NT_SUCCESS(Status
))
542 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status
);
543 IoDetachDevice(DeviceExtension
->LowerDevice
);
544 /* FIXME: why can't I cleanup without error? */
545 //IoDeleteDevice(Fdo);
548 Fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
550 /* Register interface */
551 Status
= IoRegisterDeviceInterface(
553 &GUID_DEVINTERFACE_KEYBOARD
,
555 &DeviceExtension
->InterfaceName
);
556 if (!NT_SUCCESS(Status
))
558 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status
);
562 return STATUS_SUCCESS
;
567 IN PDEVICE_OBJECT DeviceObject
,
570 PCLASS_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
571 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
573 ASSERT(DeviceExtension
->Common
.IsClassDO
);
575 if (DeviceExtension
->InputCount
> 0)
579 KeAcquireSpinLock(&DeviceExtension
->SpinLock
, &oldIrql
);
581 DPRINT("Mdl: %p, UserBuffer: %p, InputCount: %lu\n",
584 DeviceExtension
->InputCount
);
588 Irp
->MdlAddress
? MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
) : Irp
->UserBuffer
,
589 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
590 sizeof(KEYBOARD_INPUT_DATA
));
592 if (DeviceExtension
->InputCount
> 1)
595 DeviceExtension
->PortData
- DeviceExtension
->InputCount
,
596 DeviceExtension
->PortData
- DeviceExtension
->InputCount
+ 1,
597 (DeviceExtension
->InputCount
- 1) * sizeof(KEYBOARD_INPUT_DATA
));
599 DeviceExtension
->PortData
--;
600 DeviceExtension
->InputCount
--;
601 DeviceExtension
->ReadIsPending
= FALSE
;
603 /* Go to next packet and complete this request with STATUS_SUCCESS */
604 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
605 Irp
->IoStatus
.Information
= sizeof(KEYBOARD_INPUT_DATA
);
606 Stack
->Parameters
.Read
.Length
= sizeof(KEYBOARD_INPUT_DATA
);
607 IoCompleteRequest(Irp
, IO_KEYBOARD_INCREMENT
);
609 IoStartNextPacket(DeviceObject
, FALSE
);
610 KeReleaseSpinLock(&DeviceExtension
->SpinLock
, oldIrql
);
614 DeviceExtension
->ReadIsPending
= TRUE
;
619 SearchForLegacyDrivers(
620 IN PDRIVER_OBJECT DriverObject
,
621 IN PCLASS_DRIVER_EXTENSION DriverExtension
)
623 UNICODE_STRING DeviceMapKeyU
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
624 UNICODE_STRING PortBaseName
= {0, };
625 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation
= NULL
;
626 OBJECT_ATTRIBUTES ObjectAttributes
;
627 HANDLE hDeviceMapKey
= (HANDLE
)-1;
628 HANDLE hPortKey
= (HANDLE
)-1;
630 ULONG Size
, ResultLength
;
633 /* Create port base name, by replacing Class by Port at the end of the class base name */
634 Status
= RtlDuplicateUnicodeString(
635 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
636 &DriverExtension
->DeviceBaseName
,
638 if (!NT_SUCCESS(Status
))
640 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
643 PortBaseName
.Length
-= (sizeof(L
"Class") - sizeof(UNICODE_NULL
));
644 RtlAppendUnicodeToString(&PortBaseName
, L
"Port");
646 /* Allocate memory */
647 Size
= sizeof(KEY_VALUE_BASIC_INFORMATION
) + MAX_PATH
;
648 KeyValueInformation
= ExAllocatePool(PagedPool
, Size
);
649 if (!KeyValueInformation
)
651 DPRINT("ExAllocatePool() failed\n");
652 Status
= STATUS_INSUFFICIENT_RESOURCES
;
656 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
657 InitializeObjectAttributes(&ObjectAttributes
, &DeviceMapKeyU
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
658 Status
= ZwOpenKey(&hDeviceMapKey
, 0, &ObjectAttributes
);
659 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
661 DPRINT("HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
662 Status
= STATUS_SUCCESS
;
665 else if (!NT_SUCCESS(Status
))
667 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
672 InitializeObjectAttributes(&ObjectAttributes
, &PortBaseName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, hDeviceMapKey
, NULL
);
673 Status
= ZwOpenKey(&hPortKey
, KEY_QUERY_VALUE
, &ObjectAttributes
);
674 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
676 DPRINT("HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName
);
677 Status
= STATUS_SUCCESS
;
680 else if (!NT_SUCCESS(Status
))
682 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status
);
686 /* Read each value name */
687 while (ZwEnumerateValueKey(hPortKey
, Index
++, KeyValueBasicInformation
, KeyValueInformation
, Size
, &ResultLength
) == STATUS_SUCCESS
)
689 UNICODE_STRING PortName
;
690 PDEVICE_OBJECT PortDeviceObject
= NULL
;
691 PFILE_OBJECT FileObject
= NULL
;
693 PortName
.Length
= PortName
.MaximumLength
= KeyValueInformation
->NameLength
;
694 PortName
.Buffer
= KeyValueInformation
->Name
;
696 /* Open the device object pointer */
697 Status
= IoGetDeviceObjectPointer(&PortName
, FILE_READ_ATTRIBUTES
, &FileObject
, &PortDeviceObject
);
698 if (!NT_SUCCESS(Status
))
700 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status
);
703 /* Connect the port device object */
704 if (DriverExtension
->ConnectMultiplePorts
)
706 Status
= ConnectPortDriver(PortDeviceObject
, DriverExtension
->MainClassDeviceObject
);
707 if (!NT_SUCCESS(Status
))
709 /* FIXME: Log the error */
710 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status
);
715 PDEVICE_OBJECT ClassDO
;
716 Status
= CreateClassDeviceObject(DriverObject
, &ClassDO
);
717 if (!NT_SUCCESS(Status
))
719 /* FIXME: Log the error */
720 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status
);
723 Status
= ConnectPortDriver(PortDeviceObject
, ClassDO
);
724 if (!NT_SUCCESS(Status
))
726 /* FIXME: Log the error */
727 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status
);
728 IoDeleteDevice(ClassDO
);
732 if (Status
== STATUS_NO_MORE_ENTRIES
)
733 Status
= STATUS_SUCCESS
;
736 if (KeyValueInformation
!= NULL
)
737 ExFreePool(KeyValueInformation
);
738 if (hDeviceMapKey
!= (HANDLE
)-1)
739 ZwClose(hDeviceMapKey
);
740 if (hPortKey
!= (HANDLE
)-1)
746 * Standard DriverEntry method.
750 IN PDRIVER_OBJECT DriverObject
,
751 IN PUNICODE_STRING RegistryPath
)
753 PCLASS_DRIVER_EXTENSION DriverExtension
;
757 Status
= IoAllocateDriverObjectExtension(
760 sizeof(CLASS_DRIVER_EXTENSION
),
761 (PVOID
*)&DriverExtension
);
762 if (!NT_SUCCESS(Status
))
764 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status
);
767 RtlZeroMemory(DriverExtension
, sizeof(CLASS_DRIVER_EXTENSION
));
769 Status
= RtlDuplicateUnicodeString(
770 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
772 &DriverExtension
->RegistryPath
);
773 if (!NT_SUCCESS(Status
))
775 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status
);
779 Status
= ReadRegistryEntries(RegistryPath
, DriverExtension
);
780 if (!NT_SUCCESS(Status
))
782 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status
);
786 if (DriverExtension
->ConnectMultiplePorts
== 1)
788 Status
= CreateClassDeviceObject(
790 &DriverExtension
->MainClassDeviceObject
);
791 if (!NT_SUCCESS(Status
))
793 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status
);
798 DriverObject
->DriverExtension
->AddDevice
= ClassAddDevice
;
799 DriverObject
->DriverUnload
= DriverUnload
;
801 for (i
= 0; i
< IRP_MJ_MAXIMUM_FUNCTION
; i
++)
802 DriverObject
->MajorFunction
[i
] = IrpStub
;
804 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ClassCreate
;
805 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ClassClose
;
806 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = ClassCleanup
;
807 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ClassRead
;
808 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ClassDeviceControl
;
809 DriverObject
->DriverStartIo
= ClassStartIo
;
811 return STATUS_SUCCESS
;