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