Big move of driver input stack to a Plug-and-Play model:
[reactos.git] / reactos / drivers / input / kbdclass / kbdclass.c
1 /*
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
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 #define NDEBUG
11 #include <debug.h>
12
13 #define INITGUID
14 #include "kbdclass.h"
15
16 static VOID NTAPI
17 DriverUnload(IN PDRIVER_OBJECT DriverObject)
18 {
19 // nothing to do here yet
20 }
21
22 static NTSTATUS NTAPI
23 KbdclassCreate(
24 IN PDEVICE_OBJECT DeviceObject,
25 IN PIRP Irp)
26 {
27 DPRINT("IRP_MJ_CREATE\n");
28
29 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
30 return ForwardIrpAndForget(DeviceObject, Irp);
31
32 /* FIXME: open all associated Port devices */
33 return STATUS_SUCCESS;
34 }
35
36 static NTSTATUS NTAPI
37 KbdclassClose(
38 IN PDEVICE_OBJECT DeviceObject,
39 IN PIRP Irp)
40 {
41 DPRINT("IRP_MJ_CLOSE\n");
42
43 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
44 return ForwardIrpAndForget(DeviceObject, Irp);
45
46 /* FIXME: close all associated Port devices */
47 return STATUS_SUCCESS;
48 }
49
50 static NTSTATUS NTAPI
51 KbdclassRead(
52 IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp)
54 {
55 DPRINT("IRP_MJ_READ\n");
56
57 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
58 return ForwardIrpAndForget(DeviceObject, Irp);
59
60 if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA))
61 {
62 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
63 Irp->IoStatus.Information = 0;
64 IoCompleteRequest(Irp, IO_NO_INCREMENT);
65
66 return STATUS_BUFFER_TOO_SMALL;
67 }
68
69 IoMarkIrpPending(Irp);
70 IoStartPacket(DeviceObject, Irp, NULL, NULL);
71 return STATUS_PENDING;
72 }
73
74 static NTSTATUS NTAPI
75 KbdclassDeviceControl(
76 IN PDEVICE_OBJECT DeviceObject,
77 IN PIRP Irp)
78 {
79 NTSTATUS Status;
80
81 DPRINT("IRP_MJ_DEVICE_CONTROL\n");
82
83 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
84 return ForwardIrpAndForget(DeviceObject, Irp);
85
86 switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
87 {
88 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
89 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
90 case IOCTL_KEYBOARD_QUERY_INDICATORS:
91 case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
92 case IOCTL_KEYBOARD_SET_INDICATORS:
93 case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
94 /* FIXME: send it to all associated Port devices */
95 Status = STATUS_NOT_SUPPORTED;
96 break;
97 default:
98 DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
99 IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
100 Status = STATUS_NOT_SUPPORTED;
101 }
102
103 Irp->IoStatus.Status = Status;
104 Irp->IoStatus.Information = 0;
105 IoCompleteRequest(Irp, IO_NO_INCREMENT);
106
107 return Status;
108 }
109
110 static NTSTATUS NTAPI
111 IrpStub(
112 IN PDEVICE_OBJECT DeviceObject,
113 IN PIRP Irp)
114 {
115 NTSTATUS Status = STATUS_NOT_SUPPORTED;
116
117 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
118 {
119 /* Forward some IRPs to lower device */
120 switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
121 {
122 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
123 return ForwardIrpAndForget(DeviceObject, Irp);
124 default:
125 {
126 DPRINT1("Port DO stub for major function 0x%lx\n",
127 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
128 ASSERT(FALSE);
129 Status = Irp->IoStatus.Status;
130 }
131 }
132 }
133 else
134 {
135 DPRINT1("Class DO stub for major function 0x%lx\n",
136 IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
137 ASSERT(FALSE);
138 Status = Irp->IoStatus.Status;
139 }
140
141 Irp->IoStatus.Status = Status;
142 IoCompleteRequest(Irp, IO_NO_INCREMENT);
143 return Status;
144 }
145
146 static NTSTATUS
147 ReadRegistryEntries(
148 IN PUNICODE_STRING RegistryPath,
149 IN PKBDCLASS_DRIVER_EXTENSION DriverExtension)
150 {
151 RTL_QUERY_REGISTRY_TABLE Parameters[4];
152 NTSTATUS Status;
153
154 ULONG DefaultConnectMultiplePorts = 1;
155 ULONG DefaultKeyboardDataQueueSize = 0x64;
156 UNICODE_STRING DefaultKeyboardDeviceBaseName = RTL_CONSTANT_STRING(L"KeyboardClass");
157
158 RtlZeroMemory(Parameters, sizeof(Parameters));
159
160 Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
161 Parameters[0].Name = L"ConnectMultiplePorts";
162 Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
163 Parameters[0].DefaultType = REG_DWORD;
164 Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
165 Parameters[0].DefaultLength = sizeof(ULONG);
166
167 Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
168 Parameters[1].Name = L"KeyboardDataQueueSize";
169 Parameters[1].EntryContext = &DriverExtension->KeyboardDataQueueSize;
170 Parameters[1].DefaultType = REG_DWORD;
171 Parameters[1].DefaultData = &DefaultKeyboardDataQueueSize;
172 Parameters[1].DefaultLength = sizeof(ULONG);
173
174 Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
175 Parameters[2].Name = L"KeyboardDeviceBaseName";
176 Parameters[2].EntryContext = &DriverExtension->KeyboardDeviceBaseName;
177 Parameters[2].DefaultType = REG_SZ;
178 Parameters[2].DefaultData = &DefaultKeyboardDeviceBaseName;
179 Parameters[2].DefaultLength = sizeof(ULONG);
180
181 Status = RtlQueryRegistryValues(
182 RTL_REGISTRY_ABSOLUTE,
183 RegistryPath->Buffer,
184 Parameters,
185 NULL,
186 NULL);
187
188 if (NT_SUCCESS(Status))
189 {
190 /* Check values */
191 if (DriverExtension->ConnectMultiplePorts != 0
192 && DriverExtension->ConnectMultiplePorts != 1)
193 {
194 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
195 }
196 if (DriverExtension->KeyboardDataQueueSize == 0)
197 {
198 DriverExtension->KeyboardDataQueueSize = DefaultKeyboardDataQueueSize;
199 }
200 }
201
202 return Status;
203 }
204
205 static NTSTATUS
206 CreateKeyboardClassDeviceObject(
207 IN PDRIVER_OBJECT DriverObject,
208 OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
209 {
210 PKBDCLASS_DRIVER_EXTENSION DriverExtension;
211 ULONG DeviceId = 0;
212 ULONG PrefixLength;
213 UNICODE_STRING DeviceNameU;
214 PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
215 PDEVICE_OBJECT Fdo;
216 PKBDCLASS_DEVICE_EXTENSION DeviceExtension;
217 NTSTATUS Status;
218
219 DPRINT("CreateKeyboardClassDeviceObject(0x%p)\n", DriverObject);
220
221 /* Create new device object */
222 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
223 DeviceNameU.Length = 0;
224 DeviceNameU.MaximumLength =
225 wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */
226 + DriverExtension->KeyboardDeviceBaseName.Length/* "KeyboardClass" */
227 + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */
228 + sizeof(UNICODE_NULL); /* Final NULL char */
229 DeviceNameU.Buffer = ExAllocatePool(PagedPool, DeviceNameU.MaximumLength);
230 if (!DeviceNameU.Buffer)
231 {
232 DPRINT("ExAllocatePool() failed\n");
233 return STATUS_INSUFFICIENT_RESOURCES;
234 }
235 Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
236 if (!NT_SUCCESS(Status))
237 {
238 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
239 goto cleanup;
240 }
241 Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->KeyboardDeviceBaseName);
242 if (!NT_SUCCESS(Status))
243 {
244 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
245 goto cleanup;
246 }
247 PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
248 DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
249 while (DeviceId < 9999)
250 {
251 DeviceNameU.Length = PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR);
252 Status = IoCreateDevice(
253 DriverObject,
254 sizeof(KBDCLASS_DEVICE_EXTENSION),
255 &DeviceNameU,
256 FILE_DEVICE_KEYBOARD,
257 FILE_DEVICE_SECURE_OPEN,
258 FALSE,
259 &Fdo);
260 if (NT_SUCCESS(Status))
261 goto cleanup;
262 else if (Status != STATUS_OBJECT_NAME_COLLISION)
263 {
264 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
265 goto cleanup;
266 }
267 DeviceId++;
268 }
269 DPRINT("Too much devices starting with '\\Device\\%wZ'\n", &DriverExtension->KeyboardDeviceBaseName);
270 Status = STATUS_UNSUCCESSFUL;
271 cleanup:
272 ExFreePool(DeviceNameU.Buffer);
273 if (!NT_SUCCESS(Status))
274 return Status;
275
276 DeviceExtension = (PKBDCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
277 RtlZeroMemory(DeviceExtension, sizeof(KBDCLASS_DEVICE_EXTENSION));
278 DeviceExtension->Common.IsClassDO = TRUE;
279 DeviceExtension->DriverExtension = DriverExtension;
280 DeviceExtension->PnpState = dsStopped;
281 KeInitializeSpinLock(&(DeviceExtension->SpinLock));
282 DeviceExtension->ReadIsPending = FALSE;
283 DeviceExtension->InputCount = 0;
284 DeviceExtension->PortData = ExAllocatePool(NonPagedPool, DeviceExtension->DriverExtension->KeyboardDataQueueSize * sizeof(KEYBOARD_INPUT_DATA));
285 Fdo->Flags |= DO_POWER_PAGABLE;
286 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
287
288 /* FIXME: create registry entry in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
289
290 if (ClassDO)
291 *ClassDO = Fdo;
292
293 return STATUS_SUCCESS;
294 }
295
296 static BOOLEAN
297 KbdclassCallback(
298 IN PDEVICE_OBJECT ClassDeviceObject,
299 IN OUT PKEYBOARD_INPUT_DATA KeyboardDataStart,
300 IN PKEYBOARD_INPUT_DATA KeyboardDataEnd,
301 IN OUT PULONG ConsumedCount)
302 {
303 PKBDCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
304 PIRP Irp = NULL;
305 KIRQL OldIrql;
306 PIO_STACK_LOCATION Stack;
307 ULONG InputCount = KeyboardDataEnd - KeyboardDataStart;
308 ULONG ReadSize;
309
310 ASSERT(ClassDeviceExtension->Common.IsClassDO);
311
312 DPRINT("KbdclassCallback()\n");
313 /* A filter driver might have consumed all the data already; I'm
314 * not sure if they are supposed to move the packets when they
315 * consume them though.
316 */
317 if (ClassDeviceExtension->ReadIsPending == TRUE && InputCount)
318 {
319 Irp = ClassDeviceObject->CurrentIrp;
320 ClassDeviceObject->CurrentIrp = NULL;
321 Stack = IoGetCurrentIrpStackLocation(Irp);
322
323 /* A read request is waiting for input, so go straight to it */
324 /* FIXME: use SEH */
325 RtlCopyMemory(
326 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
327 KeyboardDataStart,
328 sizeof(KEYBOARD_INPUT_DATA));
329
330 /* Go to next packet and complete this request with STATUS_SUCCESS */
331 Irp->IoStatus.Status = STATUS_SUCCESS;
332 Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
333 Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
334
335 ClassDeviceExtension->ReadIsPending = FALSE;
336
337 /* Skip the packet we just sent away */
338 KeyboardDataStart++;
339 (*ConsumedCount)++;
340 InputCount--;
341 }
342
343 /* If we have data from the port driver and a higher service to send the data to */
344 if (InputCount != 0)
345 {
346 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
347
348 if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->KeyboardDataQueueSize)
349 ReadSize = ClassDeviceExtension->DriverExtension->KeyboardDataQueueSize - ClassDeviceExtension->InputCount;
350 else
351 ReadSize = InputCount;
352
353 /*
354 * FIXME: If we exceed the buffer, keyboard data gets thrown away.. better
355 * solution?
356 */
357
358 /*
359 * Move the keyboard input data from the port data queue to our class data
360 * queue.
361 */
362 RtlMoveMemory(
363 ClassDeviceExtension->PortData,
364 (PCHAR)KeyboardDataStart,
365 sizeof(KEYBOARD_INPUT_DATA) * ReadSize);
366
367 /* Move the pointer and counter up */
368 ClassDeviceExtension->PortData += ReadSize;
369 ClassDeviceExtension->InputCount += ReadSize;
370
371 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
372 (*ConsumedCount) += ReadSize;
373 }
374 else
375 {
376 DPRINT("KbdclassCallBack() entered, InputCount = %lu - DOING NOTHING\n", InputCount);
377 }
378
379 if (Irp != NULL)
380 {
381 IoStartNextPacket(ClassDeviceObject, FALSE);
382 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
383 }
384
385 DPRINT("Leaving KbdclassCallback()\n");
386 return TRUE;
387 }
388
389 /* Send IOCTL_INTERNAL_KEYBOARD_CONNECT to keyboard port */
390 static NTSTATUS
391 ConnectKeyboardPortDriver(
392 IN PDEVICE_OBJECT KeyboardPortDO,
393 IN PDEVICE_OBJECT KeyboardClassDO)
394 {
395 KEVENT Event;
396 PIRP Irp;
397 IO_STATUS_BLOCK IoStatus;
398 CONNECT_DATA ConnectData;
399 NTSTATUS Status;
400
401 KeInitializeEvent(&Event, NotificationEvent, FALSE);
402
403 ConnectData.ClassDeviceObject = KeyboardClassDO;
404 ConnectData.ClassService = KbdclassCallback;
405
406 Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_KEYBOARD_CONNECT,
407 KeyboardPortDO,
408 &ConnectData, sizeof(CONNECT_DATA),
409 NULL, 0,
410 TRUE, &Event, &IoStatus);
411
412 Status = IoCallDriver(KeyboardPortDO, Irp);
413
414 if (Status == STATUS_PENDING)
415 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
416 else
417 IoStatus.Status = Status;
418
419 return IoStatus.Status;
420 }
421
422 static NTSTATUS NTAPI
423 KbdclassAddDevice(
424 IN PDRIVER_OBJECT DriverObject,
425 IN PDEVICE_OBJECT Pdo)
426 {
427 PKBDCLASS_DRIVER_EXTENSION DriverExtension;
428 PDEVICE_OBJECT Fdo;
429 PKBDCLASS_DEVICE_EXTENSION DeviceExtension;
430 NTSTATUS Status;
431
432 DPRINT("KbdclassAddDevice called. Pdo = 0x%p\n", Pdo);
433
434 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
435
436 /* Create new device object */
437 Status = IoCreateDevice(
438 DriverObject,
439 sizeof(KBDCLASS_DEVICE_EXTENSION),
440 NULL,
441 Pdo->DeviceType,
442 FILE_DEVICE_SECURE_OPEN,
443 FALSE,
444 &Fdo);
445 if (!NT_SUCCESS(Status))
446 {
447 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
448 return Status;
449 }
450
451 DeviceExtension = (PKBDCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
452 RtlZeroMemory(DeviceExtension, sizeof(KBDCLASS_DEVICE_EXTENSION));
453 DeviceExtension->Common.IsClassDO = FALSE;
454 DeviceExtension->PnpState = dsStopped;
455 Fdo->Flags |= DO_POWER_PAGABLE;
456 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
457 if (!NT_SUCCESS(Status))
458 {
459 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
460 IoDeleteDevice(Fdo);
461 return Status;
462 }
463 Fdo->Flags |= DO_BUFFERED_IO;
464 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
465
466 if (DriverExtension->ConnectMultiplePorts)
467 Status = ConnectKeyboardPortDriver(Fdo, DriverExtension->MainKbdclassDeviceObject);
468 else
469 Status = ConnectKeyboardPortDriver(Fdo, Fdo);
470 if (!NT_SUCCESS(Status))
471 {
472 DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
473 /* FIXME: why can't I cleanup without error? */
474 //IoDetachDevice(Fdo);
475 //IoDeleteDevice(Fdo);
476 return Status;
477 }
478
479 /* Register GUID_DEVINTERFACE_KEYBOARD interface */
480 Status = IoRegisterDeviceInterface(
481 Pdo,
482 &GUID_DEVINTERFACE_KEYBOARD,
483 NULL,
484 &DeviceExtension->KeyboardInterfaceName);
485 if (!NT_SUCCESS(Status))
486 {
487 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
488 return Status;
489 }
490
491 return STATUS_SUCCESS;
492 }
493
494 static VOID NTAPI
495 KbdclassStartIo(
496 IN PDEVICE_OBJECT DeviceObject,
497 IN PIRP Irp)
498 {
499 PKBDCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
500 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
501
502 ASSERT(DeviceExtension->Common.IsClassDO);
503
504 if (DeviceExtension->InputCount > 0)
505 {
506 KIRQL oldIrql;
507
508 KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
509
510 /* FIXME: use SEH */
511 RtlCopyMemory(
512 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
513 DeviceExtension->PortData - DeviceExtension->InputCount,
514 sizeof(KEYBOARD_INPUT_DATA));
515
516 if (DeviceExtension->InputCount > 1)
517 {
518 RtlMoveMemory(
519 DeviceExtension->PortData - DeviceExtension->InputCount,
520 DeviceExtension->PortData - DeviceExtension->InputCount + 1,
521 (DeviceExtension->InputCount - 1) * sizeof(KEYBOARD_INPUT_DATA));
522 }
523 DeviceExtension->PortData--;
524 DeviceExtension->InputCount--;
525 DeviceExtension->ReadIsPending = FALSE;
526
527 /* Go to next packet and complete this request with STATUS_SUCCESS */
528 Irp->IoStatus.Status = STATUS_SUCCESS;
529 Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
530 Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
531 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
532
533 IoStartNextPacket(DeviceObject, FALSE);
534 KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
535 }
536 else
537 {
538 DeviceExtension->ReadIsPending = TRUE;
539 }
540 }
541
542 static NTSTATUS
543 SearchForLegacyDrivers(
544 IN PDRIVER_OBJECT DriverObject,
545 IN PKBDCLASS_DRIVER_EXTENSION DriverExtension)
546 {
547 UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
548 UNICODE_STRING PortBaseName = {0, };
549 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
550 OBJECT_ATTRIBUTES ObjectAttributes;
551 HANDLE hDeviceMapKey = (HANDLE)-1;
552 HANDLE hPortKey = (HANDLE)-1;
553 ULONG Index = 0;
554 ULONG Size, ResultLength;
555 NTSTATUS Status;
556
557 /* Create port base name, by replacing Class by Port at the end of the class base name */
558 Status = RtlDuplicateUnicodeString(
559 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
560 &DriverExtension->KeyboardDeviceBaseName,
561 &PortBaseName);
562 if (!NT_SUCCESS(Status))
563 {
564 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
565 goto cleanup;
566 }
567 PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
568 RtlAppendUnicodeToString(&PortBaseName, L"Port");
569
570 /* Allocate memory */
571 Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
572 KeyValueInformation = ExAllocatePool(PagedPool, Size);
573 if (!KeyValueInformation)
574 {
575 DPRINT("ExAllocatePool() failed\n");
576 Status = STATUS_INSUFFICIENT_RESOURCES;
577 goto cleanup;
578 }
579
580 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
581 InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
582 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
583 if (!NT_SUCCESS(Status))
584 {
585 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
586 goto cleanup;
587 }
588
589 /* Open sub key */
590 InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
591 Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
592 if (!NT_SUCCESS(Status))
593 {
594 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
595 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
596 goto cleanup;
597 }
598
599 /* Read each value name */
600 while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
601 {
602 UNICODE_STRING PortName;
603 PDEVICE_OBJECT PortDeviceObject = NULL;
604 PFILE_OBJECT FileObject = NULL;
605
606 PortName.Length = PortName.MaximumLength = KeyValueInformation->NameLength;
607 PortName.Buffer = KeyValueInformation->Name;
608
609 /* Open the device object pointer */
610 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
611 if (!NT_SUCCESS(Status))
612 {
613 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status);
614 }
615
616 /* Connect the port device object */
617 if (DriverExtension->ConnectMultiplePorts)
618 {
619 Status = ConnectKeyboardPortDriver(PortDeviceObject, DriverExtension->MainKbdclassDeviceObject);
620 if (!NT_SUCCESS(Status))
621 {
622 /* FIXME: Log the error */
623 DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
624 /* FIXME: cleanup */
625 }
626 }
627 else
628 {
629 PDEVICE_OBJECT ClassDO;
630 Status = CreateKeyboardClassDeviceObject(DriverObject, &ClassDO);
631 if (!NT_SUCCESS(Status))
632 {
633 /* FIXME: Log the error */
634 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
635 /* FIXME: cleanup */
636 continue;
637 }
638 Status = ConnectKeyboardPortDriver(PortDeviceObject, ClassDO);
639 if (!NT_SUCCESS(Status))
640 {
641 /* FIXME: Log the error */
642 DPRINT("ConnectKeyboardPortDriver() failed with status 0x%08lx\n", Status);
643 /* FIXME: cleanup */
644 }
645 }
646 }
647 if (Status == STATUS_NO_MORE_ENTRIES)
648 Status = STATUS_SUCCESS;
649
650 cleanup:
651 if (KeyValueInformation != NULL)
652 ExFreePool(KeyValueInformation);
653 if (hDeviceMapKey != (HANDLE)-1)
654 ZwClose(hDeviceMapKey);
655 if (hPortKey != (HANDLE)-1)
656 ZwClose(hPortKey);
657 return Status;
658 }
659
660 /*
661 * Standard DriverEntry method.
662 */
663 NTSTATUS NTAPI
664 DriverEntry(
665 IN PDRIVER_OBJECT DriverObject,
666 IN PUNICODE_STRING RegistryPath)
667 {
668 PKBDCLASS_DRIVER_EXTENSION DriverExtension;
669 ULONG i;
670 NTSTATUS Status;
671
672 Status = IoAllocateDriverObjectExtension(
673 DriverObject,
674 DriverObject,
675 sizeof(KBDCLASS_DRIVER_EXTENSION),
676 (PVOID*)&DriverExtension);
677 if (!NT_SUCCESS(Status))
678 {
679 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
680 return Status;
681 }
682 RtlZeroMemory(DriverExtension, sizeof(KBDCLASS_DRIVER_EXTENSION));
683
684 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
685 if (!NT_SUCCESS(Status))
686 {
687 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
688 return Status;
689 }
690
691 if (DriverExtension->ConnectMultiplePorts == 1)
692 {
693 Status = CreateKeyboardClassDeviceObject(
694 DriverObject,
695 &DriverExtension->MainKbdclassDeviceObject);
696 if (!NT_SUCCESS(Status))
697 {
698 DPRINT("CreateKeyboardClassDeviceObject() failed with status 0x%08lx\n", Status);
699 return Status;
700 }
701 }
702
703 DriverObject->DriverExtension->AddDevice = KbdclassAddDevice;
704 DriverObject->DriverUnload = DriverUnload;
705
706 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
707 DriverObject->MajorFunction[i] = IrpStub;
708
709 DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdclassCreate;
710 DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdclassClose;
711 DriverObject->MajorFunction[IRP_MJ_READ] = KbdclassRead;
712 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdclassDeviceControl;
713 DriverObject->DriverStartIo = KbdclassStartIo;
714
715 Status = SearchForLegacyDrivers(DriverObject, DriverExtension);
716
717 return Status;
718 }