229e6b143bccb9a0751f3f5eaa9a613a9f456445
[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 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
486
487 /* Create new device object */
488 Status = IoCreateDevice(
489 DriverObject,
490 sizeof(PORT_DEVICE_EXTENSION),
491 NULL,
492 Pdo->DeviceType,
493 FILE_DEVICE_SECURE_OPEN,
494 TRUE,
495 &Fdo);
496 if (!NT_SUCCESS(Status))
497 {
498 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
499 return Status;
500 }
501
502 DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
503 RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
504 DeviceExtension->Common.IsClassDO = FALSE;
505 DeviceExtension->PnpState = dsStopped;
506 Fdo->Flags |= DO_POWER_PAGABLE;
507 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
508 if (!NT_SUCCESS(Status))
509 {
510 DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
511 IoDeleteDevice(Fdo);
512 return Status;
513 }
514 Fdo->Flags |= DO_BUFFERED_IO;
515
516 if (DriverExtension->ConnectMultiplePorts)
517 Status = ConnectPortDriver(Fdo, DriverExtension->MainClassDeviceObject);
518 else
519 Status = ConnectPortDriver(Fdo, Fdo);
520 if (!NT_SUCCESS(Status))
521 {
522 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
523 IoDetachDevice(DeviceExtension->LowerDevice);
524 /* FIXME: why can't I cleanup without error? */
525 //IoDeleteDevice(Fdo);
526 return Status;
527 }
528 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
529
530 /* Register interface */
531 Status = IoRegisterDeviceInterface(
532 Pdo,
533 &GUID_DEVINTERFACE_KEYBOARD,
534 NULL,
535 &DeviceExtension->InterfaceName);
536 if (!NT_SUCCESS(Status))
537 {
538 DPRINT("IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
539 return Status;
540 }
541
542 return STATUS_SUCCESS;
543 }
544
545 static VOID NTAPI
546 ClassStartIo(
547 IN PDEVICE_OBJECT DeviceObject,
548 IN PIRP Irp)
549 {
550 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
551 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
552
553 ASSERT(DeviceExtension->Common.IsClassDO);
554
555 if (DeviceExtension->InputCount > 0)
556 {
557 KIRQL oldIrql;
558
559 KeAcquireSpinLock(&DeviceExtension->SpinLock, &oldIrql);
560
561 /* FIXME: use SEH */
562 RtlCopyMemory(
563 Irp->MdlAddress ? MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) : Irp->UserBuffer,
564 DeviceExtension->PortData - DeviceExtension->InputCount,
565 sizeof(KEYBOARD_INPUT_DATA));
566
567 if (DeviceExtension->InputCount > 1)
568 {
569 RtlMoveMemory(
570 DeviceExtension->PortData - DeviceExtension->InputCount,
571 DeviceExtension->PortData - DeviceExtension->InputCount + 1,
572 (DeviceExtension->InputCount - 1) * sizeof(KEYBOARD_INPUT_DATA));
573 }
574 DeviceExtension->PortData--;
575 DeviceExtension->InputCount--;
576 DeviceExtension->ReadIsPending = FALSE;
577
578 /* Go to next packet and complete this request with STATUS_SUCCESS */
579 Irp->IoStatus.Status = STATUS_SUCCESS;
580 Irp->IoStatus.Information = sizeof(KEYBOARD_INPUT_DATA);
581 Stack->Parameters.Read.Length = sizeof(KEYBOARD_INPUT_DATA);
582 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
583
584 IoStartNextPacket(DeviceObject, FALSE);
585 KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
586 }
587 else
588 {
589 DeviceExtension->ReadIsPending = TRUE;
590 }
591 }
592
593 static NTSTATUS
594 SearchForLegacyDrivers(
595 IN PDRIVER_OBJECT DriverObject,
596 IN PCLASS_DRIVER_EXTENSION DriverExtension)
597 {
598 UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
599 UNICODE_STRING PortBaseName = {0, };
600 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
601 OBJECT_ATTRIBUTES ObjectAttributes;
602 HANDLE hDeviceMapKey = (HANDLE)-1;
603 HANDLE hPortKey = (HANDLE)-1;
604 ULONG Index = 0;
605 ULONG Size, ResultLength;
606 NTSTATUS Status;
607
608 /* Create port base name, by replacing Class by Port at the end of the class base name */
609 Status = RtlDuplicateUnicodeString(
610 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
611 &DriverExtension->DeviceBaseName,
612 &PortBaseName);
613 if (!NT_SUCCESS(Status))
614 {
615 DPRINT("RtlDuplicateUnicodeString() failed with status 0x%08lx\n", Status);
616 goto cleanup;
617 }
618 PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
619 RtlAppendUnicodeToString(&PortBaseName, L"Port");
620
621 /* Allocate memory */
622 Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
623 KeyValueInformation = ExAllocatePool(PagedPool, Size);
624 if (!KeyValueInformation)
625 {
626 DPRINT("ExAllocatePool() failed\n");
627 Status = STATUS_INSUFFICIENT_RESOURCES;
628 goto cleanup;
629 }
630
631 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
632 InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
633 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
634 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
635 {
636 DPRINT("HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
637 Status = STATUS_SUCCESS;
638 goto cleanup;
639 }
640 else if (!NT_SUCCESS(Status))
641 {
642 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
643 goto cleanup;
644 }
645
646 /* Open sub key */
647 InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
648 Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
649 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
650 {
651 DPRINT("HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
652 Status = STATUS_SUCCESS;
653 goto cleanup;
654 }
655 else if (!NT_SUCCESS(Status))
656 {
657 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
658 goto cleanup;
659 }
660
661 /* Read each value name */
662 while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
663 {
664 UNICODE_STRING PortName;
665 PDEVICE_OBJECT PortDeviceObject = NULL;
666 PFILE_OBJECT FileObject = NULL;
667
668 PortName.Length = PortName.MaximumLength = KeyValueInformation->NameLength;
669 PortName.Buffer = KeyValueInformation->Name;
670
671 /* Open the device object pointer */
672 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
673 if (!NT_SUCCESS(Status))
674 {
675 DPRINT("IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", Status);
676 }
677
678 /* Connect the port device object */
679 if (DriverExtension->ConnectMultiplePorts)
680 {
681 Status = ConnectPortDriver(PortDeviceObject, DriverExtension->MainClassDeviceObject);
682 if (!NT_SUCCESS(Status))
683 {
684 /* FIXME: Log the error */
685 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
686 ObDereferenceObject(PortDeviceObject);
687 }
688 }
689 else
690 {
691 PDEVICE_OBJECT ClassDO;
692 Status = CreateClassDeviceObject(DriverObject, &ClassDO);
693 if (!NT_SUCCESS(Status))
694 {
695 /* FIXME: Log the error */
696 DPRINT("CreatePointerClassDeviceObject() failed with status 0x%08lx\n", Status);
697 ObDereferenceObject(PortDeviceObject);
698 continue;
699 }
700 Status = ConnectPortDriver(PortDeviceObject, ClassDO);
701 if (!NT_SUCCESS(Status))
702 {
703 /* FIXME: Log the error */
704 DPRINT("ConnectPortDriver() failed with status 0x%08lx\n", Status);
705 ObDereferenceObject(PortDeviceObject);
706 IoDeleteDevice(ClassDO);
707 }
708 }
709 }
710 if (Status == STATUS_NO_MORE_ENTRIES)
711 Status = STATUS_SUCCESS;
712
713 cleanup:
714 if (KeyValueInformation != NULL)
715 ExFreePool(KeyValueInformation);
716 if (hDeviceMapKey != (HANDLE)-1)
717 ZwClose(hDeviceMapKey);
718 if (hPortKey != (HANDLE)-1)
719 ZwClose(hPortKey);
720 return Status;
721 }
722
723 /*
724 * Standard DriverEntry method.
725 */
726 NTSTATUS NTAPI
727 DriverEntry(
728 IN PDRIVER_OBJECT DriverObject,
729 IN PUNICODE_STRING RegistryPath)
730 {
731 PCLASS_DRIVER_EXTENSION DriverExtension;
732 ULONG i;
733 NTSTATUS Status;
734
735 Status = IoAllocateDriverObjectExtension(
736 DriverObject,
737 DriverObject,
738 sizeof(CLASS_DRIVER_EXTENSION),
739 (PVOID*)&DriverExtension);
740 if (!NT_SUCCESS(Status))
741 {
742 DPRINT("IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
743 return Status;
744 }
745 RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
746
747 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
748 if (!NT_SUCCESS(Status))
749 {
750 DPRINT("ReadRegistryEntries() failed with status 0x%08lx\n", Status);
751 return Status;
752 }
753
754 if (DriverExtension->ConnectMultiplePorts == 1)
755 {
756 Status = CreateClassDeviceObject(
757 DriverObject,
758 &DriverExtension->MainClassDeviceObject);
759 if (!NT_SUCCESS(Status))
760 {
761 DPRINT("CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
762 return Status;
763 }
764 }
765
766 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
767 DriverObject->DriverUnload = DriverUnload;
768
769 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
770 DriverObject->MajorFunction[i] = IrpStub;
771
772 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate;
773 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose;
774 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup;
775 DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead;
776 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
777 DriverObject->DriverStartIo = ClassStartIo;
778
779 Status = SearchForLegacyDrivers(DriverObject, DriverExtension);
780
781 return Status;
782 }