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