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