Reactos
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#include "kbdclass.h"
11
12#include <stdio.h>
13#include <pseh/pseh2.h>
14#include <kbdmou.h>
15#include <debug.h>
16
17static DRIVER_UNLOAD DriverUnload;
18static DRIVER_DISPATCH ClassCreate;
19static DRIVER_DISPATCH ClassClose;
20static DRIVER_DISPATCH ClassCleanup;
21static DRIVER_DISPATCH ClassRead;
22static DRIVER_DISPATCH ClassDeviceControl;
23static DRIVER_DISPATCH ClassPower;
24static DRIVER_ADD_DEVICE ClassAddDevice;
25static DRIVER_STARTIO ClassStartIo;
26static DRIVER_CANCEL ClassCancelRoutine;
27static NTSTATUS
28HandleReadIrp(
29 IN PDEVICE_OBJECT DeviceObject,
30 IN PIRP Irp,
31 BOOLEAN IsInStartIo);
32
33static VOID NTAPI
34DriverUnload(IN PDRIVER_OBJECT DriverObject)
35{
36 // nothing to do here yet
37}
38
39static NTSTATUS NTAPI
40ClassCreate(
41 IN PDEVICE_OBJECT DeviceObject,
42 IN PIRP Irp)
43{
44 TRACE_(CLASS_NAME, "IRP_MJ_CREATE\n");
45
46 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
47 return ForwardIrpAndForget(DeviceObject, Irp);
48
49 /* FIXME: open all associated Port devices */
50 Irp->IoStatus.Status = STATUS_SUCCESS;
51 Irp->IoStatus.Information = 0;
52 IoCompleteRequest(Irp, IO_NO_INCREMENT);
53 return STATUS_SUCCESS;
54}
55
56static NTSTATUS NTAPI
57ClassClose(
58 IN PDEVICE_OBJECT DeviceObject,
59 IN PIRP Irp)
60{
61 TRACE_(CLASS_NAME, "IRP_MJ_CLOSE\n");
62
63 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
64 return ForwardIrpAndForget(DeviceObject, Irp);
65
66 /* FIXME: close all associated Port devices */
67 Irp->IoStatus.Status = STATUS_SUCCESS;
68 Irp->IoStatus.Information = 0;
69 IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 return STATUS_SUCCESS;
71}
72
73static NTSTATUS NTAPI
74ClassCleanup(
75 IN PDEVICE_OBJECT DeviceObject,
76 IN PIRP Irp)
77{
78 TRACE_(CLASS_NAME, "IRP_MJ_CLEANUP\n");
79
80 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
81 return ForwardIrpAndForget(DeviceObject, Irp);
82
83 /* FIXME: cleanup all associated Port devices */
84 Irp->IoStatus.Status = STATUS_SUCCESS;
85 Irp->IoStatus.Information = 0;
86 IoCompleteRequest(Irp, IO_NO_INCREMENT);
87 return STATUS_SUCCESS;
88}
89
90static NTSTATUS NTAPI
91ClassRead(
92 IN PDEVICE_OBJECT DeviceObject,
93 IN PIRP Irp)
94{
95 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
96 KIRQL OldIrql;
97 NTSTATUS Status;
98
99 TRACE_(CLASS_NAME, "IRP_MJ_READ\n");
100
101 ASSERT(DeviceExtension->Common.IsClassDO);
102
103 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
104 return ForwardIrpAndForget(DeviceObject, Irp);
105
106 if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA))
107 {
108 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
109 Irp->IoStatus.Information = 0;
110 IoCompleteRequest(Irp, IO_NO_INCREMENT);
111
112 return STATUS_BUFFER_TOO_SMALL;
113 }
114
115 KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
116 Status = HandleReadIrp(DeviceObject, Irp, FALSE);
117 KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
118 return Status;
119}
120
121static NTSTATUS NTAPI
122ClassDeviceControl(
123 IN PDEVICE_OBJECT DeviceObject,
124 IN PIRP Irp)
125{
126 //PCLASS_DEVICE_EXTENSION DeviceExtension;
127 NTSTATUS Status = STATUS_NOT_SUPPORTED;
128
129 TRACE_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL\n");
130
131 if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
132 return ForwardIrpAndForget(DeviceObject, Irp);
133
134 //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
135
136 switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
137 {
138 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
139 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
140 case IOCTL_KEYBOARD_QUERY_INDICATORS:
141 case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
142 {
143 /* FIXME: We hope that all devices will return the same result.
144 * Ask only the first one */
145 PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
146 if (Head->Flink != Head)
147 {
148 /* We have at least one device */
149 PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, PORT_DEVICE_EXTENSION, ListEntry);
150 IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
151 IoSkipCurrentIrpStackLocation(Irp);
152 return IoCallDriver(DevExt->DeviceObject, Irp);
153 }
154 break;
155 }
156 case IOCTL_KEYBOARD_SET_INDICATORS:
157 case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
158 {
159 /* Send it to all associated Port devices */
160 PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
161 PLIST_ENTRY Entry = Head->Flink;
162 Status = STATUS_SUCCESS;
163 while (Entry != Head)
164 {
165 PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Entry, PORT_DEVICE_EXTENSION, ListEntry);
166
167 IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
168
169 if (IoForwardIrpSynchronously(DevExt->LowerDevice, Irp))
170 {
171 if (!NT_SUCCESS(Irp->IoStatus.Status))
172 {
173 Status = Irp->IoStatus.Status;
174 }
175 }
176 else
177 {
178 Status = STATUS_UNSUCCESSFUL;
179 }
180
181 Entry = Entry->Flink;
182 }
183 break;
184 }
185 default:
186 WARN_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
187 IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
188 ASSERT(FALSE);
189 break;
190 }
191
192 Irp->IoStatus.Status = Status;
193 Irp->IoStatus.Information = 0;
194 IoCompleteRequest(Irp, IO_NO_INCREMENT);
195
196 return Status;
197}
198
199static NTSTATUS NTAPI
200ClassPower(
201 IN PDEVICE_OBJECT DeviceObject,
202 IN PIRP Irp)
203{
204 NTSTATUS Status;
205 PPORT_DEVICE_EXTENSION DeviceExtension;
206
207 DeviceExtension = DeviceObject->DeviceExtension;
208 if (!DeviceExtension->Common.IsClassDO)
209 {
210 /* Forward port DO IRPs to lower device */
211 PoStartNextPowerIrp(Irp);
212 IoSkipCurrentIrpStackLocation(Irp);
213 return PoCallDriver(DeviceExtension->LowerDevice, Irp);
214 }
215
216 switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction)
217 {
218 case IRP_MN_SET_POWER:
219 case IRP_MN_QUERY_POWER:
220 Irp->IoStatus.Status = STATUS_SUCCESS;
221 break;
222 }
223 Status = Irp->IoStatus.Status;
224 PoStartNextPowerIrp(Irp);
225 IoCompleteRequest(Irp, IO_NO_INCREMENT);
226 return Status;
227}
228
229static NTSTATUS
230ReadRegistryEntries(
231 IN PUNICODE_STRING RegistryPath,
232 IN PCLASS_DRIVER_EXTENSION DriverExtension)
233{
234 UNICODE_STRING ParametersRegistryKey;
235 RTL_QUERY_REGISTRY_TABLE Parameters[4];
236 NTSTATUS Status;
237
238 /* HACK: We don't support multiple devices with this disabled */
239 ULONG DefaultConnectMultiplePorts = 1;
240 ULONG DefaultDataQueueSize = 0x64;
241 PCWSTR DefaultDeviceBaseName = L"KeyboardClass";
242
243 ParametersRegistryKey.Length = 0;
244 ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
245 ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, CLASS_TAG);
246 if (!ParametersRegistryKey.Buffer)
247 {
248 WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
249 return STATUS_NO_MEMORY;
250 }
251 RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
252 RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
253 ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
254
255 RtlZeroMemory(Parameters, sizeof(Parameters));
256
257 Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
258 Parameters[0].Name = L"ConnectMultiplePorts";
259 Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
260 Parameters[0].DefaultType = REG_DWORD;
261 Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
262 Parameters[0].DefaultLength = sizeof(ULONG);
263
264 Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
265 Parameters[1].Name = L"KeyboardDataQueueSize";
266 Parameters[1].EntryContext = &DriverExtension->DataQueueSize;
267 Parameters[1].DefaultType = REG_DWORD;
268 Parameters[1].DefaultData = &DefaultDataQueueSize;
269 Parameters[1].DefaultLength = sizeof(ULONG);
270
271 Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
272 Parameters[2].Name = L"KeyboardDeviceBaseName";
273 Parameters[2].EntryContext = &DriverExtension->DeviceBaseName;
274 Parameters[2].DefaultType = REG_SZ;
275 Parameters[2].DefaultData = (PVOID)DefaultDeviceBaseName;
276 Parameters[2].DefaultLength = 0;
277
278 Status = RtlQueryRegistryValues(
279 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
280 ParametersRegistryKey.Buffer,
281 Parameters,
282 NULL,
283 NULL);
284
285 if (NT_SUCCESS(Status))
286 {
287 /* Check values */
288 if (DriverExtension->ConnectMultiplePorts != 0
289 && DriverExtension->ConnectMultiplePorts != 1)
290 {
291 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
292 }
293 if (DriverExtension->DataQueueSize == 0)
294 {
295 DriverExtension->DataQueueSize = DefaultDataQueueSize;
296 }
297 }
298 else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
299 {
300 /* Registry path doesn't exist. Set defaults */
301 DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
302 DriverExtension->DataQueueSize = DefaultDataQueueSize;
303 if (RtlCreateUnicodeString(&DriverExtension->DeviceBaseName, DefaultDeviceBaseName))
304 Status = STATUS_SUCCESS;
305 else
306 Status = STATUS_NO_MEMORY;
307 }
308
309 ExFreePoolWithTag(ParametersRegistryKey.Buffer, CLASS_TAG);
310 return Status;
311}
312
313static NTSTATUS
314CreateClassDeviceObject(
315 IN PDRIVER_OBJECT DriverObject,
316 OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
317{
318 PCLASS_DRIVER_EXTENSION DriverExtension;
319 ULONG DeviceId = 0;
320 ULONG PrefixLength;
321 UNICODE_STRING DeviceNameU;
322 PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
323 PDEVICE_OBJECT Fdo;
324 PCLASS_DEVICE_EXTENSION DeviceExtension;
325 NTSTATUS Status;
326
327 TRACE_(CLASS_NAME, "CreateClassDeviceObject(0x%p)\n", DriverObject);
328
329 /* Create new device object */
330 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
331 DeviceNameU.Length = 0;
332 DeviceNameU.MaximumLength =
333 (USHORT)wcslen(L"\\Device\\") * sizeof(WCHAR) /* "\Device\" */
334 + DriverExtension->DeviceBaseName.Length /* "KeyboardClass" */
335 + 4 * sizeof(WCHAR) /* Id between 0 and 9999 */
336 + sizeof(UNICODE_NULL); /* Final NULL char */
337 DeviceNameU.Buffer = ExAllocatePoolWithTag(PagedPool, DeviceNameU.MaximumLength, CLASS_TAG);
338 if (!DeviceNameU.Buffer)
339 {
340 WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
341 return STATUS_NO_MEMORY;
342 }
343 Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
344 if (!NT_SUCCESS(Status))
345 {
346 WARN_(CLASS_NAME, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
347 goto cleanup;
348 }
349 Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName);
350 if (!NT_SUCCESS(Status))
351 {
352 WARN_(CLASS_NAME, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
353 goto cleanup;
354 }
355 PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
356 DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
357 while (DeviceId < 9999)
358 {
359 DeviceNameU.Length = (USHORT)(PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR));
360 Status = IoCreateDevice(
361 DriverObject,
362 sizeof(CLASS_DEVICE_EXTENSION),
363 &DeviceNameU,
364 FILE_DEVICE_KEYBOARD,
365 FILE_DEVICE_SECURE_OPEN,
366 FALSE,
367 &Fdo);
368 if (NT_SUCCESS(Status))
369 goto cleanup;
370 else if (Status != STATUS_OBJECT_NAME_COLLISION)
371 {
372 WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
373 goto cleanup;
374 }
375 DeviceId++;
376 }
377 WARN_(CLASS_NAME, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName);
378 Status = STATUS_TOO_MANY_NAMES;
379cleanup:
380 if (!NT_SUCCESS(Status))
381 {
382 ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
383 return Status;
384 }
385
386 DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
387 RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
388 DeviceExtension->Common.IsClassDO = TRUE;
389 DeviceExtension->DriverExtension = DriverExtension;
390 InitializeListHead(&DeviceExtension->ListHead);
391 KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
392 KeInitializeSpinLock(&DeviceExtension->SpinLock);
393 DeviceExtension->InputCount = 0;
394 DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA), CLASS_TAG);
395 if (!DeviceExtension->PortData)
396 {
397 ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
398 return STATUS_NO_MEMORY;
399 }
400 DeviceExtension->DeviceName = DeviceNameU.Buffer;
401 Fdo->Flags |= DO_POWER_PAGABLE;
402 Fdo->Flags |= DO_BUFFERED_IO; /* FIXME: Why is it needed for 1st stage setup? */
403 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
404
405 /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
406 RtlWriteRegistryValue(
407 RTL_REGISTRY_DEVICEMAP,
408 DriverExtension->DeviceBaseName.Buffer,
409 DeviceExtension->DeviceName,
410 REG_SZ,
411 DriverExtension->RegistryPath.Buffer,
412 DriverExtension->RegistryPath.MaximumLength);
413
414 if (ClassDO)
415 *ClassDO = Fdo;
416
417 return STATUS_SUCCESS;
418}
419
420static NTSTATUS
421FillEntries(
422 IN PDEVICE_OBJECT ClassDeviceObject,
423 IN PIRP Irp,
424 IN PKEYBOARD_INPUT_DATA DataStart,
425 IN SIZE_T NumberOfEntries)
426{
427 NTSTATUS Status = STATUS_SUCCESS;
428
429 if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
430 {
431 RtlCopyMemory(
432 Irp->AssociatedIrp.SystemBuffer,
433 DataStart,
434 NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
435 }
436 else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
437 {
438 PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
439 if (DestAddress)
440 {
441 RtlCopyMemory(
442 DestAddress,
443 DataStart,
444 NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
445 }
446 else
447 Status = STATUS_UNSUCCESSFUL;
448 }
449 else
450 {
451 _SEH2_TRY
452 {
453 RtlCopyMemory(
454 Irp->UserBuffer,
455 DataStart,
456 NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
457 }
458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
459 {
460 Status = _SEH2_GetExceptionCode();
461 }
462 _SEH2_END;
463 }
464
465 return Status;
466}
467
468static BOOLEAN NTAPI
469ClassCallback(
470 IN PDEVICE_OBJECT ClassDeviceObject,
471 IN OUT PKEYBOARD_INPUT_DATA DataStart,
472 IN PKEYBOARD_INPUT_DATA DataEnd,
473 IN OUT PULONG ConsumedCount)
474{
475 PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
476 KIRQL OldIrql;
477 SIZE_T InputCount = DataEnd - DataStart;
478 SIZE_T ReadSize;
479
480 TRACE_(CLASS_NAME, "ClassCallback()\n");
481
482 ASSERT(ClassDeviceExtension->Common.IsClassDO);
483
484 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
485 if (InputCount > 0)
486 {
487 if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
488 {
489 /*
490 * We're exceeding the buffer, and data will be thrown away...
491 * FIXME: What could we do, as we are at DISPATCH_LEVEL?
492 */
493 ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount;
494 }
495 else
496 ReadSize = InputCount;
497
498 /*
499 * Move the input data from the port data queue to our class data
500 * queue.
501 */
502 RtlCopyMemory(
503 &ClassDeviceExtension->PortData[ClassDeviceExtension->InputCount],
504 (PCHAR)DataStart,
505 sizeof(KEYBOARD_INPUT_DATA) * ReadSize);
506
507 /* Move the counter up */
508 ClassDeviceExtension->InputCount += ReadSize;
509
510 (*ConsumedCount) += (ULONG)ReadSize;
511
512 /* Complete pending IRP (if any) */
513 if (ClassDeviceExtension->PendingIrp)
514 HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
515 }
516 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
517
518 TRACE_(CLASS_NAME, "Leaving ClassCallback()\n");
519 return TRUE;
520}
521
522/* Send IOCTL_INTERNAL_*_CONNECT to port */
523static NTSTATUS
524ConnectPortDriver(
525 IN PDEVICE_OBJECT PortDO,
526 IN PDEVICE_OBJECT ClassDO)
527{
528 KEVENT Event;
529 PIRP Irp;
530 IO_STATUS_BLOCK IoStatus;
531 CONNECT_DATA ConnectData;
532 NTSTATUS Status;
533
534 TRACE_(CLASS_NAME, "Connecting PortDO %p to ClassDO %p\n", PortDO, ClassDO);
535
536 KeInitializeEvent(&Event, NotificationEvent, FALSE);
537
538 ConnectData.ClassDeviceObject = ClassDO;
539 ConnectData.ClassService = ClassCallback;
540
541 Irp = IoBuildDeviceIoControlRequest(
542 IOCTL_INTERNAL_KEYBOARD_CONNECT,
543 PortDO,
544 &ConnectData, sizeof(CONNECT_DATA),
545 NULL, 0,
546 TRUE, &Event, &IoStatus);
547 if (!Irp)
548 return STATUS_INSUFFICIENT_RESOURCES;
549
550 Status = IoCallDriver(PortDO, Irp);
551
552 if (Status == STATUS_PENDING)
553 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
554 else
555 IoStatus.Status = Status;
556
557 if (NT_SUCCESS(IoStatus.Status))
558 {
559 ObReferenceObject(PortDO);
560 ExInterlockedInsertTailList(
561 &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListHead,
562 &((PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension)->ListEntry,
563 &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListSpinLock);
564 if (ClassDO->StackSize <= PortDO->StackSize)
565 {
566 /* Increase the stack size, in case we have to
567 * forward some IRPs to the port device object
568 */
569 ClassDO->StackSize = PortDO->StackSize + 1;
570 }
571 }
572
573 return IoStatus.Status;
574}
575
576/* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
577static VOID
578DestroyPortDriver(
579 IN PDEVICE_OBJECT PortDO)
580{
581 PPORT_DEVICE_EXTENSION DeviceExtension;
582 PCLASS_DEVICE_EXTENSION ClassDeviceExtension;
583 PCLASS_DRIVER_EXTENSION DriverExtension;
584 KEVENT Event;
585 PIRP Irp;
586 IO_STATUS_BLOCK IoStatus;
587 KIRQL OldIrql;
588 NTSTATUS Status;
589
590 TRACE_(CLASS_NAME, "Destroying PortDO %p\n", PortDO);
591
592 DeviceExtension = (PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension;
593 ClassDeviceExtension = DeviceExtension->ClassDO->DeviceExtension;
594 DriverExtension = IoGetDriverObjectExtension(PortDO->DriverObject, PortDO->DriverObject);
595
596 /* Send IOCTL_INTERNAL_*_DISCONNECT */
597 KeInitializeEvent(&Event, NotificationEvent, FALSE);
598 Irp = IoBuildDeviceIoControlRequest(
599 IOCTL_INTERNAL_KEYBOARD_DISCONNECT,
600 PortDO,
601 NULL, 0,
602 NULL, 0,
603 TRUE, &Event, &IoStatus);
604 if (Irp)
605 {
606 Status = IoCallDriver(PortDO, Irp);
607 if (Status == STATUS_PENDING)
608 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
609 }
610
611 /* Remove from ClassDeviceExtension->ListHead list */
612 KeAcquireSpinLock(&ClassDeviceExtension->ListSpinLock, &OldIrql);
613 RemoveEntryList(&DeviceExtension->ListEntry);
614 KeReleaseSpinLock(&ClassDeviceExtension->ListSpinLock, OldIrql);
615
616 /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
617 RtlDeleteRegistryValue(
618 RTL_REGISTRY_DEVICEMAP,
619 DriverExtension->DeviceBaseName.Buffer,
620 ClassDeviceExtension->DeviceName);
621
622 if (DeviceExtension->LowerDevice)
623 IoDetachDevice(DeviceExtension->LowerDevice);
624 ObDereferenceObject(PortDO);
625
626 if (!DriverExtension->ConnectMultiplePorts && DeviceExtension->ClassDO)
627 {
628 ExFreePoolWithTag(ClassDeviceExtension->PortData, CLASS_TAG);
629 ExFreePoolWithTag((PVOID)ClassDeviceExtension->DeviceName, CLASS_TAG);
630 IoDeleteDevice(DeviceExtension->ClassDO);
631 }
632
633 IoDeleteDevice(PortDO);
634}
635
636static NTSTATUS NTAPI
637ClassAddDevice(
638 IN PDRIVER_OBJECT DriverObject,
639 IN PDEVICE_OBJECT Pdo)
640{
641 PCLASS_DRIVER_EXTENSION DriverExtension;
642 PDEVICE_OBJECT Fdo = NULL;
643 PPORT_DEVICE_EXTENSION DeviceExtension = NULL;
644 NTSTATUS Status;
645
646 TRACE_(CLASS_NAME, "ClassAddDevice called. Pdo = 0x%p\n", Pdo);
647
648 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
649
650 if (Pdo == NULL)
651 /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
652 return STATUS_SUCCESS;
653
654 /* Create new device object */
655 Status = IoCreateDevice(
656 DriverObject,
657 sizeof(PORT_DEVICE_EXTENSION),
658 NULL,
659 Pdo->DeviceType,
660 Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
661 FALSE,
662 &Fdo);
663 if (!NT_SUCCESS(Status))
664 {
665 WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
666 goto cleanup;
667 }
668 IoSetStartIoAttributes(Fdo, TRUE, TRUE);
669
670 DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
671 RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
672 DeviceExtension->Common.IsClassDO = FALSE;
673 DeviceExtension->DeviceObject = Fdo;
674 DeviceExtension->PnpState = dsStopped;
675 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
676 if (!NT_SUCCESS(Status))
677 {
678 WARN_(CLASS_NAME, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
679 goto cleanup;
680 }
681 if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
682 Fdo->Flags |= DO_POWER_PAGABLE;
683 if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
684 Fdo->Flags |= DO_BUFFERED_IO;
685 if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
686 Fdo->Flags |= DO_DIRECT_IO;
687
688 if (DriverExtension->ConnectMultiplePorts)
689 DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
690 else
691 {
692 /* We need a new class device object for this Fdo */
693 Status = CreateClassDeviceObject(
694 DriverObject,
695 &DeviceExtension->ClassDO);
696 if (!NT_SUCCESS(Status))
697 {
698 WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
699 goto cleanup;
700 }
701 }
702 Status = ConnectPortDriver(Fdo, DeviceExtension->ClassDO);
703 if (!NT_SUCCESS(Status))
704 {
705 WARN_(CLASS_NAME, "ConnectPortDriver() failed with status 0x%08lx\n", Status);
706 goto cleanup;
707 }
708 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
709
710 /* Register interface ; ignore the error (if any) as having
711 * a registered interface is not so important... */
712 Status = IoRegisterDeviceInterface(
713 Pdo,
714 &GUID_DEVINTERFACE_KEYBOARD,
715 NULL,
716 &DeviceExtension->InterfaceName);
717 if (!NT_SUCCESS(Status))
718 DeviceExtension->InterfaceName.Length = 0;
719
720 return STATUS_SUCCESS;
721
722cleanup:
723 if (Fdo)
724 DestroyPortDriver(Fdo);
725 return Status;
726}
727
728static VOID NTAPI
729ClassCancelRoutine(
730 IN PDEVICE_OBJECT DeviceObject,
731 IN PIRP Irp)
732{
733 PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
734 KIRQL OldIrql;
735 BOOLEAN wasQueued = FALSE;
736
737 TRACE_(CLASS_NAME, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
738
739 ASSERT(ClassDeviceExtension->Common.IsClassDO);
740
741 IoReleaseCancelSpinLock(Irp->CancelIrql);
742
743 KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
744
745 if (ClassDeviceExtension->PendingIrp == Irp)
746 {
747 ClassDeviceExtension->PendingIrp = NULL;
748 wasQueued = TRUE;
749 }
750 KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
751
752 if (wasQueued)
753 {
754 Irp->IoStatus.Status = STATUS_CANCELLED;
755 Irp->IoStatus.Information = 0;
756 IoCompleteRequest(Irp, IO_NO_INCREMENT);
757 }
758 else
759 {
760 DPRINT1("Cancelled IRP is not pending. Race condition?\n");
761 }
762}
763
764static NTSTATUS
765HandleReadIrp(
766 IN PDEVICE_OBJECT DeviceObject,
767 IN PIRP Irp,
768 BOOLEAN IsInStartIo)
769{
770 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
771 NTSTATUS Status;
772 KIRQL OldIrql;
773
774 TRACE_(CLASS_NAME, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
775
776 ASSERT(DeviceExtension->Common.IsClassDO);
777
778 if (DeviceExtension->InputCount > 0)
779 {
780 SIZE_T NumberOfEntries;
781
782 NumberOfEntries = MIN(
783 DeviceExtension->InputCount,
784 IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));
785
786 Status = FillEntries(
787 DeviceObject,
788 Irp,
789 DeviceExtension->PortData,
790 NumberOfEntries);
791
792 if (NT_SUCCESS(Status))
793 {
794 if (DeviceExtension->InputCount > NumberOfEntries)
795 {
796 RtlMoveMemory(
797 &DeviceExtension->PortData[0],
798 &DeviceExtension->PortData[NumberOfEntries],
799 (DeviceExtension->InputCount - NumberOfEntries) * sizeof(KEYBOARD_INPUT_DATA));
800 }
801
802 DeviceExtension->InputCount -= NumberOfEntries;
803
804 Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
805 }
806
807 /* Go to next packet and complete this request */
808 Irp->IoStatus.Status = Status;
809
810 (VOID)IoSetCancelRoutine(Irp, NULL);
811 IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
812 DeviceExtension->PendingIrp = NULL;
813 }
814 else
815 {
816 IoAcquireCancelSpinLock(&OldIrql);
817 if (Irp->Cancel)
818 {
819 DeviceExtension->PendingIrp = NULL;
820 Status = STATUS_CANCELLED;
821 }
822 else
823 {
824 IoMarkIrpPending(Irp);
825 DeviceExtension->PendingIrp = Irp;
826 (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
827 Status = STATUS_PENDING;
828 }
829 IoReleaseCancelSpinLock(OldIrql);
830 }
831 return Status;
832}
833
834static NTSTATUS NTAPI
835ClassPnp(
836 IN PDEVICE_OBJECT DeviceObject,
837 IN PIRP Irp)
838{
839 PPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
840 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
841 OBJECT_ATTRIBUTES ObjectAttributes;
842 IO_STATUS_BLOCK Iosb;
843 NTSTATUS Status;
844
845 switch (IrpSp->MinorFunction)
846 {
847 case IRP_MN_START_DEVICE:
848 if (IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
849 {
850 Status = Irp->IoStatus.Status;
851 }
852 else
853 {
854 Status = STATUS_UNSUCCESSFUL;
855 }
856
857 if (NT_SUCCESS(Status))
858 {
859 InitializeObjectAttributes(&ObjectAttributes,
860 &DeviceExtension->InterfaceName,
861 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
862 NULL,
863 NULL);
864
865 Status = ZwOpenFile(&DeviceExtension->FileHandle,
866 FILE_READ_DATA,
867 &ObjectAttributes,
868 &Iosb,
869 0,
870 0);
871 if (!NT_SUCCESS(Status))
872 DeviceExtension->FileHandle = NULL;
873 }
874 else
875 DeviceExtension->FileHandle = NULL;
876 if (DeviceExtension->InterfaceName.Length != 0)
877 IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, TRUE);
878 Irp->IoStatus.Status = Status;
879 IoCompleteRequest(Irp, IO_NO_INCREMENT);
880 return Status;
881
882 case IRP_MN_STOP_DEVICE:
883 if (DeviceExtension->FileHandle)
884 {
885 ZwClose(DeviceExtension->FileHandle);
886 DeviceExtension->FileHandle = NULL;
887 }
888 Status = STATUS_SUCCESS;
889 break;
890
891 case IRP_MN_REMOVE_DEVICE:
892 if (DeviceExtension->InterfaceName.Length != 0)
893 IoSetDeviceInterfaceState(&DeviceExtension->InterfaceName, FALSE);
894 if (DeviceExtension->FileHandle)
895 {
896 ZwClose(DeviceExtension->FileHandle);
897 DeviceExtension->FileHandle = NULL;
898 }
899 IoSkipCurrentIrpStackLocation(Irp);
900 Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
901 DestroyPortDriver(DeviceObject);
902 return Status;
903
904 default:
905 Status = Irp->IoStatus.Status;
906 break;
907 }
908
909 Irp->IoStatus.Status = Status;
910 if (NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED)
911 {
912 IoSkipCurrentIrpStackLocation(Irp);
913 return IoCallDriver(DeviceExtension->LowerDevice, Irp);
914 }
915 else
916 {
917 IoCompleteRequest(Irp, IO_NO_INCREMENT);
918 return Status;
919 }
920}
921
922static VOID NTAPI
923ClassStartIo(
924 IN PDEVICE_OBJECT DeviceObject,
925 IN PIRP Irp)
926{
927 PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
928 KIRQL OldIrql;
929
930 TRACE_(CLASS_NAME, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
931
932 ASSERT(DeviceExtension->Common.IsClassDO);
933
934 KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
935 HandleReadIrp(DeviceObject, Irp, TRUE);
936 KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
937}
938
939static VOID NTAPI
940SearchForLegacyDrivers(
941 IN PDRIVER_OBJECT DriverObject,
942 IN PVOID Context, /* PCLASS_DRIVER_EXTENSION */
943 IN ULONG Count)
944{
945 UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
946 PCLASS_DRIVER_EXTENSION DriverExtension;
947 UNICODE_STRING PortBaseName = { 0, 0, NULL };
948 PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
949 OBJECT_ATTRIBUTES ObjectAttributes;
950 HANDLE hDeviceMapKey = (HANDLE)-1;
951 HANDLE hPortKey = (HANDLE)-1;
952 ULONG Index = 0;
953 ULONG Size, ResultLength;
954 NTSTATUS Status;
955
956 TRACE_(CLASS_NAME, "SearchForLegacyDrivers(%p %p %lu)\n",
957 DriverObject, Context, Count);
958
959 if (Count != 1)
960 return;
961 DriverExtension = (PCLASS_DRIVER_EXTENSION)Context;
962
963 /* Create port base name, by replacing Class by Port at the end of the class base name */
964 Status = DuplicateUnicodeString(
965 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
966 &DriverExtension->DeviceBaseName,
967 &PortBaseName);
968 if (!NT_SUCCESS(Status))
969 {
970 WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
971 goto cleanup;
972 }
973 PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
974 RtlAppendUnicodeToString(&PortBaseName, L"Port");
975
976 /* Allocate memory */
977 Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
978 KeyValueInformation = ExAllocatePoolWithTag(PagedPool, Size, CLASS_TAG);
979 if (!KeyValueInformation)
980 {
981 WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
982 Status = STATUS_NO_MEMORY;
983 goto cleanup;
984 }
985
986 /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
987 InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
988 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
989 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
990 {
991 INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
992 Status = STATUS_SUCCESS;
993 goto cleanup;
994 }
995 else if (!NT_SUCCESS(Status))
996 {
997 WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
998 goto cleanup;
999 }
1000
1001 /* Open sub key */
1002 InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
1003 Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
1004 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1005 {
1006 INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
1007 Status = STATUS_SUCCESS;
1008 goto cleanup;
1009 }
1010 else if (!NT_SUCCESS(Status))
1011 {
1012 WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
1013 goto cleanup;
1014 }
1015
1016 /* Read each value name */
1017 while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
1018 {
1019 UNICODE_STRING PortName;
1020 PDEVICE_OBJECT PortDeviceObject = NULL;
1021 PFILE_OBJECT FileObject = NULL;
1022
1023 PortName.Length = PortName.MaximumLength = (USHORT)KeyValueInformation->NameLength;
1024 PortName.Buffer = KeyValueInformation->Name;
1025
1026 /* Open the device object pointer */
1027 Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
1028 if (!NT_SUCCESS(Status))
1029 {
1030 WARN_(CLASS_NAME, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName, Status);
1031 continue;
1032 }
1033 INFO_(CLASS_NAME, "Legacy driver found\n");
1034
1035 Status = ClassAddDevice(DriverObject, PortDeviceObject);
1036 if (!NT_SUCCESS(Status))
1037 {
1038 /* FIXME: Log the error */
1039 WARN_(CLASS_NAME, "ClassAddDevice() failed with status 0x%08lx\n", Status);
1040 }
1041
1042 ObDereferenceObject(FileObject);
1043 }
1044
1045cleanup:
1046 if (KeyValueInformation != NULL)
1047 ExFreePoolWithTag(KeyValueInformation, CLASS_TAG);
1048 if (hDeviceMapKey != (HANDLE)-1)
1049 ZwClose(hDeviceMapKey);
1050 if (hPortKey != (HANDLE)-1)
1051 ZwClose(hPortKey);
1052}
1053
1054/*
1055 * Standard DriverEntry method.
1056 */
1057NTSTATUS NTAPI
1058DriverEntry(
1059 IN PDRIVER_OBJECT DriverObject,
1060 IN PUNICODE_STRING RegistryPath)
1061{
1062 PCLASS_DRIVER_EXTENSION DriverExtension;
1063 NTSTATUS Status;
1064
1065 Status = IoAllocateDriverObjectExtension(
1066 DriverObject,
1067 DriverObject,
1068 sizeof(CLASS_DRIVER_EXTENSION),
1069 (PVOID*)&DriverExtension);
1070 if (!NT_SUCCESS(Status))
1071 {
1072 WARN_(CLASS_NAME, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
1073 return Status;
1074 }
1075 RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
1076
1077 Status = DuplicateUnicodeString(
1078 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1079 RegistryPath,
1080 &DriverExtension->RegistryPath);
1081 if (!NT_SUCCESS(Status))
1082 {
1083 WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
1084 return Status;
1085 }
1086
1087 Status = ReadRegistryEntries(RegistryPath, DriverExtension);
1088 if (!NT_SUCCESS(Status))
1089 {
1090 WARN_(CLASS_NAME, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
1091 return Status;
1092 }
1093
1094 if (DriverExtension->ConnectMultiplePorts == 1)
1095 {
1096 Status = CreateClassDeviceObject(
1097 DriverObject,
1098 &DriverExtension->MainClassDeviceObject);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
1102 return Status;
1103 }
1104 }
1105
1106 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
1107 DriverObject->DriverUnload = DriverUnload;
1108
1109 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreate;
1110 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassClose;
1111 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClassCleanup;
1112 DriverObject->MajorFunction[IRP_MJ_READ] = ClassRead;
1113 DriverObject->MajorFunction[IRP_MJ_POWER] = ClassPower;
1114 DriverObject->MajorFunction[IRP_MJ_PNP] = ClassPnp;
1115 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
1116 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ForwardIrpAndForget;
1117 DriverObject->DriverStartIo = ClassStartIo;
1118
1119 /* We will detect the legacy devices later */
1120 IoRegisterDriverReinitialization(
1121 DriverObject,
1122 SearchForLegacyDrivers,
1123 DriverExtension);
1124
1125 return STATUS_SUCCESS;
1126}