|
|
1.1 root 1:
2: /*++
3:
4: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
5:
6: Module Name:
7:
8: kbdclass.c
9:
10: Abstract:
11:
12: Keyboard class driver.
13:
14: Environment:
15:
16: Kernel mode only.
17:
18: Notes:
19:
20: NOTES: (Future/outstanding issues)
21:
22: - Powerfail not implemented.
23:
24: - Consolidate common code into a function, where appropriate.
25:
26: - Unload not implemented. We don't want to allow this driver
27: to unload.
28:
29: Revision History:
30:
31: --*/
32:
33: #include "stdarg.h"
34: #include "stdio.h"
35: #include "ntddk.h"
36: #include "kbdclass.h"
37: #include "kbdmou.h"
38: #include "kbdlog.h"
39:
40:
41: NTSTATUS
42: DriverEntry(
43: IN PDRIVER_OBJECT DriverObject,
44: IN PUNICODE_STRING RegistryPath
45: );
46:
47: VOID
48: KeyboardClassCancel(
49: IN PDEVICE_OBJECT DeviceObject,
50: IN PIRP Irp
51: );
52:
53: NTSTATUS
54: KeyboardClassCleanup(
55: IN PDEVICE_OBJECT DeviceObject,
56: IN PIRP Irp
57: );
58:
59: NTSTATUS
60: KeyboardClassDeviceControl(
61: IN PDEVICE_OBJECT DeviceObject,
62: IN PIRP Irp
63: );
64:
65: NTSTATUS
66: KeyboardClassFlush(
67: IN PDEVICE_OBJECT DeviceObject,
68: IN PIRP Irp
69: );
70:
71: NTSTATUS
72: KeyboardClassOpenClose(
73: IN PDEVICE_OBJECT DeviceObject,
74: IN PIRP Irp
75: );
76:
77: NTSTATUS
78: KeyboardClassRead(
79: IN PDEVICE_OBJECT DeviceObject,
80: IN PIRP Irp
81: );
82:
83: VOID
84: KeyboardClassServiceCallback(
85: IN PDEVICE_OBJECT DeviceObject,
86: IN PKEYBOARD_INPUT_DATA InputDataStart,
87: IN PKEYBOARD_INPUT_DATA InputDataEnd,
88: IN OUT PULONG InputDataConsumed
89: );
90:
91: VOID
92: KeyboardClassStartIo(
93: IN PDEVICE_OBJECT DeviceObject,
94: IN PIRP Irp
95: );
96:
97: VOID
98: KeyboardClassUnload(
99: IN PDRIVER_OBJECT DriverObject
100: );
101:
102: BOOLEAN
103: KbdCancelRequest(
104: IN PVOID Context
105: );
106:
107: VOID
108: KbdConfiguration(
109: IN PDEVICE_EXTENSION DeviceExtension,
110: IN PUNICODE_STRING RegistryPath,
111: IN PUNICODE_STRING DeviceName
112: );
113:
114: NTSTATUS
115: KbdConnectToPort(
116: IN PDEVICE_OBJECT ClassDeviceObject,
117: IN PUNICODE_STRING FullPortName,
118: IN ULONG PortIndex
119: );
120:
121: NTSTATUS
122: KbdCreateClassObject(
123: IN PDRIVER_OBJECT DriverObject,
124: IN PDEVICE_EXTENSION TmpDeviceExtension,
125: IN PUNICODE_STRING RegistryPath,
126: IN PUNICODE_STRING FullDeviceName,
127: IN PUNICODE_STRING BaseDeviceName,
128: IN PDEVICE_OBJECT *ClassDeviceObject
129: );
130:
131: #if DBG
132:
133: VOID
134: KbdDebugPrint(
135: ULONG DebugPrintLevel,
136: PCCHAR DebugMessage,
137: ...
138: );
139:
140: //
141: // Declare the global debug flag for this driver.
142: //
143:
144: ULONG KeyboardDebug = 0;
145: #define KbdPrint(x) KbdDebugPrint x
146: #else
147: #define KbdPrint(x)
148: #endif
149:
150: NTSTATUS
151: KbdDeterminePortsServiced(
152: IN PUNICODE_STRING BasePortName,
153: IN OUT PULONG NumberPortsServiced
154: );
155:
156: NTSTATUS
157: KbdDeviceMapQueryCallback(
158: IN PWSTR ValueName,
159: IN ULONG ValueType,
160: IN PVOID ValueData,
161: IN ULONG ValueLength,
162: IN PVOID Context,
163: IN PVOID EntryContext
164: );
165:
166: NTSTATUS
167: KbdEnableDisablePort(
168: IN PDEVICE_OBJECT DeviceObject,
169: IN BOOLEAN EnableFlag,
170: IN ULONG PortIndex
171: );
172:
173: VOID
174: KbdInitializeDataQueue(
175: IN PVOID Context
176: );
177:
178: NTSTATUS
179: KbdSendConnectRequest(
180: IN PDEVICE_OBJECT DeviceObject,
181: IN PVOID ServiceCallback,
182: IN ULONG PortIndex
183: );
184:
185: //
186: // Use the alloc_text pragma to specify the driver initialization routines
187: // (they can be paged out).
188: //
189:
190: #ifdef ALLOC_PRAGMA
191: #pragma alloc_text(init,DriverEntry)
192: #pragma alloc_text(init,KbdConfiguration)
193: #pragma alloc_text(init,KbdCreateClassObject)
194: #pragma alloc_text(init,KbdDeterminePortsServiced)
195: #pragma alloc_text(init,KbdDeviceMapQueryCallback)
196: #pragma alloc_text(init,KbdConnectToPort)
197: #pragma alloc_text(init,KbdSendConnectRequest)
198: #endif
199:
200:
201: NTSTATUS
202: DriverEntry(
203: IN PDRIVER_OBJECT DriverObject,
204: IN PUNICODE_STRING RegistryPath
205: )
206:
207: /*++
208:
209: Routine Description:
210:
211: This routine initializes the keyboard class driver.
212:
213: Arguments:
214:
215: DriverObject - Pointer to driver object created by system.
216:
217: RegistryPath - Pointer to the Unicode name of the registry path
218: for this driver.
219:
220: Return Value:
221:
222: The function value is the final status from the initialization operation.
223:
224: --*/
225:
226: {
227: DEVICE_EXTENSION tmpDeviceExtension;
228: PDEVICE_OBJECT classDeviceObject = NULL;
229: PDEVICE_EXTENSION deviceExtension = NULL;
230: NTSTATUS status;
231: ULONG i;
232: ULONG portConnectionSuccessful;
233: UNICODE_STRING fullClassName;
234: UNICODE_STRING baseClassName;
235: UNICODE_STRING fullPortName;
236: UNICODE_STRING basePortName;
237: UNICODE_STRING deviceNameSuffix;
238: UNICODE_STRING registryPath;
239: PIO_ERROR_LOG_PACKET errorLogEntry;
240: ULONG uniqueErrorValue;
241: ULONG dumpCount = 0;
242: NTSTATUS errorCode = STATUS_SUCCESS;
243:
244: #define NAME_MAX 256
245: WCHAR baseClassBuffer[NAME_MAX];
246: WCHAR basePortBuffer[NAME_MAX];
247:
248: #define DUMP_COUNT 4
249: ULONG dumpData[DUMP_COUNT];
250:
251: KbdPrint((1,"\n\nKBDCLASS-KeyboardClassInitialize: enter\n"));
252:
253: //
254: // Zero-initialize various structures.
255: //
256:
257: RtlZeroMemory(&tmpDeviceExtension, sizeof(DEVICE_EXTENSION));
258:
259: fullClassName.MaximumLength = 0;
260: fullPortName.MaximumLength = 0;
261: deviceNameSuffix.MaximumLength = 0;
262: registryPath.MaximumLength = 0;
263:
264: RtlZeroMemory(baseClassBuffer, NAME_MAX * sizeof(WCHAR));
265: baseClassName.Buffer = baseClassBuffer;
266: baseClassName.Length = 0;
267: baseClassName.MaximumLength = NAME_MAX * sizeof(WCHAR);
268:
269: RtlZeroMemory(basePortBuffer, NAME_MAX * sizeof(WCHAR));
270: basePortName.Buffer = basePortBuffer;
271: basePortName.Length = 0;
272: basePortName.MaximumLength = NAME_MAX * sizeof(WCHAR);
273:
274: //
275: // Need to ensure that the registry path is null-terminated.
276: // Allocate pool to hold a null-terminated copy of the path.
277: //
278:
279: registryPath.Buffer = ExAllocatePool(
280: PagedPool,
281: RegistryPath->Length + sizeof(UNICODE_NULL)
282: );
283:
284: if (!registryPath.Buffer) {
285: KbdPrint((
286: 1,
287: "KBDCLASS-KeyboardClassInitialize: Couldn't allocate pool for registry path\n"
288: ));
289:
290: status = STATUS_UNSUCCESSFUL;
291: errorCode = KBDCLASS_INSUFFICIENT_RESOURCES;
292: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 2;
293: dumpData[0] = (ULONG) RegistryPath->Length + sizeof(UNICODE_NULL);
294: dumpCount = 1;
295: goto KeyboardClassInitializeExit;
296:
297: } else {
298:
299: registryPath.Length = RegistryPath->Length + sizeof(UNICODE_NULL);
300: registryPath.MaximumLength = registryPath.Length;
301:
302: RtlZeroMemory(
303: registryPath.Buffer,
304: registryPath.Length
305: );
306:
307: RtlMoveMemory(
308: registryPath.Buffer,
309: RegistryPath->Buffer,
310: RegistryPath->Length
311: );
312:
313: }
314:
315: //
316: // Get the configuration information for this driver.
317: //
318:
319: KbdConfiguration(&tmpDeviceExtension, ®istryPath, &baseClassName);
320:
321: //
322: // Set up space for the class's device object suffix. Note that
323: // we overallocate space for the suffix string because it is much
324: // easier than figuring out exactly how much space is required.
325: // The storage gets freed at the end of driver initialization, so
326: // who cares...
327: //
328:
329: RtlInitUnicodeString(&deviceNameSuffix, NULL);
330:
331: deviceNameSuffix.MaximumLength = KEYBOARD_PORTS_MAXIMUM * sizeof(WCHAR);
332: deviceNameSuffix.MaximumLength += sizeof(UNICODE_NULL);
333:
334: deviceNameSuffix.Buffer = ExAllocatePool(
335: PagedPool,
336: deviceNameSuffix.MaximumLength
337: );
338:
339: if (!deviceNameSuffix.Buffer) {
340:
341: KbdPrint((
342: 1,
343: "KBDCLASS-KeyboardClassInitialize: Couldn't allocate string for device object suffix\n"
344: ));
345:
346: status = STATUS_UNSUCCESSFUL;
347: errorCode = KBDCLASS_INSUFFICIENT_RESOURCES;
348: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 4;
349: dumpData[0] = (ULONG) deviceNameSuffix.MaximumLength;
350: dumpCount = 1;
351: goto KeyboardClassInitializeExit;
352:
353: }
354:
355: RtlZeroMemory(deviceNameSuffix.Buffer, deviceNameSuffix.MaximumLength);
356:
357: //
358: // Set up space for the class's full device object name.
359: //
360:
361: RtlInitUnicodeString(&fullClassName, NULL);
362:
363: fullClassName.MaximumLength = sizeof(L"\\Device\\") +
364: baseClassName.Length +
365: deviceNameSuffix.MaximumLength;
366:
367:
368: fullClassName.Buffer = ExAllocatePool(
369: PagedPool,
370: fullClassName.MaximumLength
371: );
372:
373: if (!fullClassName.Buffer) {
374:
375: KbdPrint((
376: 1,
377: "KBDCLASS-KeyboardClassInitialize: Couldn't allocate string for device object name\n"
378: ));
379:
380: status = STATUS_UNSUCCESSFUL;
381: errorCode = KBDCLASS_INSUFFICIENT_RESOURCES;
382: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 6;
383: dumpData[0] = (ULONG) fullClassName.MaximumLength;
384: dumpCount = 1;
385: goto KeyboardClassInitializeExit;
386:
387: }
388:
389: RtlZeroMemory(fullClassName.Buffer, fullClassName.MaximumLength);
390: RtlAppendUnicodeToString(&fullClassName, L"\\Device\\");
391: RtlAppendUnicodeToString(&fullClassName, baseClassName.Buffer);
392:
393: //
394: // Set up the base device name for the associated port device.
395: // It is the same as the base class name, with "Class" replaced
396: // by "Port".
397: //
398:
399: RtlCopyUnicodeString(&basePortName, &baseClassName);
400:
401: basePortName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
402:
403: RtlAppendUnicodeToString(&basePortName, L"Port");
404:
405: //
406: // Determine how many ports this class driver is to service.
407: //
408:
409: status = KbdDeterminePortsServiced(&basePortName, &i);
410:
411: if (NT_SUCCESS(status)) {
412: if (i < tmpDeviceExtension.MaximumPortsServiced)
413: tmpDeviceExtension.MaximumPortsServiced = i;
414: }
415:
416: status = STATUS_SUCCESS;
417:
418: KbdPrint((
419: 1,
420: "KBDCLASS-KeyboardClassInitialize: Will service %d port devices\n",
421: tmpDeviceExtension.MaximumPortsServiced
422: ));
423:
424: //
425: // Set up space for the full device object name for the ports.
426: //
427:
428: RtlInitUnicodeString(&fullPortName, NULL);
429:
430: fullPortName.MaximumLength = sizeof(L"\\Device\\") +
431: basePortName.Length +
432: deviceNameSuffix.MaximumLength;
433:
434: fullPortName.Buffer = ExAllocatePool(
435: PagedPool,
436: fullPortName.MaximumLength
437: );
438:
439: if (!fullPortName.Buffer) {
440:
441: KbdPrint((
442: 1,
443: "KBDCLASS-KeyboardClassInitialize: Couldn't allocate string for port device object name\n"
444: ));
445:
446: status = STATUS_UNSUCCESSFUL;
447: errorCode = KBDCLASS_INSUFFICIENT_RESOURCES;
448: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 8;
449: dumpData[0] = (ULONG) fullPortName.MaximumLength;
450: dumpCount = 1;
451: goto KeyboardClassInitializeExit;
452:
453: }
454:
455: RtlZeroMemory(fullPortName.Buffer, fullPortName.MaximumLength);
456: RtlAppendUnicodeToString(&fullPortName, L"\\Device\\");
457: RtlAppendUnicodeToString(&fullPortName, basePortName.Buffer);
458:
459: //
460: // Allocate memory for the port device object pointer list.
461: //
462:
463: (PDEVICE_OBJECT *) tmpDeviceExtension.PortDeviceObjectList =
464: ExAllocatePool(
465: NonPagedPool,
466: sizeof(PDEVICE_OBJECT) * tmpDeviceExtension.MaximumPortsServiced
467: );
468:
469: if (!tmpDeviceExtension.PortDeviceObjectList) {
470:
471: //
472: // Could not allocate memory for the port device object pointers.
473: //
474:
475: KbdPrint((
476: 1,
477: "KBDCLASS-KeyboardClassInitialize: Could not allocate PortDeviceObjectList for %ws\n",
478: fullClassName.Buffer
479: ));
480:
481: status = STATUS_INSUFFICIENT_RESOURCES;
482: errorCode = KBDCLASS_INSUFFICIENT_RESOURCES;
483: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 10;
484: dumpData[0] = (ULONG) (sizeof(PDEVICE_OBJECT) * tmpDeviceExtension.MaximumPortsServiced);
485: dumpData[1] = (ULONG) tmpDeviceExtension.MaximumPortsServiced;
486: dumpCount = 2;
487:
488: goto KeyboardClassInitializeExit;
489: }
490:
491: //
492: // Set up the class device object(s) to handle the associated
493: // port devices.
494: //
495:
496: portConnectionSuccessful = 0;
497:
498: for (i = 0; i < tmpDeviceExtension.MaximumPortsServiced; i++) {
499:
500: //
501: // Append the suffix to the device object name string. E.g., turn
502: // \Device\KeyboardClass into \Device\KeyboardClass0. Then attempt
503: // to create the device object. If the device object already
504: // exists increment the suffix and try again.
505: //
506:
507: status = RtlIntegerToUnicodeString(
508: i,
509: 10,
510: &deviceNameSuffix
511: );
512:
513: if (!NT_SUCCESS(status)) {
514: continue;
515: }
516:
517: RtlAppendUnicodeStringToString(
518: &fullClassName,
519: &deviceNameSuffix
520: );
521:
522: RtlAppendUnicodeStringToString(
523: &fullPortName,
524: &deviceNameSuffix
525: );
526:
527: //
528: // Create the class device object.
529: //
530:
531: if (tmpDeviceExtension.ConnectOneClassToOnePort
532: || (classDeviceObject == NULL)) {
533: classDeviceObject = NULL;
534: status = KbdCreateClassObject(
535: DriverObject,
536: &tmpDeviceExtension,
537: ®istryPath,
538: &fullClassName,
539: &baseClassName,
540: &classDeviceObject
541: );
542: }
543:
544: //
545: // Connect to the port device.
546: //
547:
548: if (NT_SUCCESS(status)) {
549: status = KbdConnectToPort(
550: classDeviceObject,
551: &fullPortName,
552: i
553: );
554: }
555:
556: if (NT_SUCCESS(status)) {
557:
558: portConnectionSuccessful += 1;
559:
560: if (tmpDeviceExtension.ConnectOneClassToOnePort
561: || (portConnectionSuccessful == 1)) {
562:
563: //
564: // Load the device map information into the registry so
565: // that setup can determine which keyboard class driver
566: // is active.
567: //
568:
569: status = RtlWriteRegistryValue(
570: RTL_REGISTRY_DEVICEMAP,
571: baseClassName.Buffer,
572: fullClassName.Buffer,
573: REG_SZ,
574: registryPath.Buffer,
575: registryPath.Length + sizeof(UNICODE_NULL)
576: );
577:
578: if (!NT_SUCCESS(status)) {
579:
580: KbdPrint((
581: 1,
582: "KBDCLASS-KeyboardClassInitialize: Could not store %ws in DeviceMap\n",
583: fullClassName.Buffer
584: ));
585:
586: //
587: // Stop making connections, and log an error.
588: //
589:
590: errorCode = KBDCLASS_NO_DEVICEMAP_CREATED;
591: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 14;
592: dumpCount = 0;
593:
594: //
595: // N.B. 'break' should cause execution to
596: // go to KeyboardClassInitializeExit (otherwise
597: // do an explicit 'goto').
598: //
599:
600: break;
601:
602: } else {
603:
604: KbdPrint((
605: 1,
606: "KBDCLASS-KeyboardClassInitialize: Stored %ws in DeviceMap\n",
607: fullClassName.Buffer
608: ));
609: }
610: }
611:
612: //
613: // Try the next one.
614: //
615:
616: fullClassName.Length -= deviceNameSuffix.Length;
617: fullPortName.Length -= deviceNameSuffix.Length;
618:
619: } else if (tmpDeviceExtension.ConnectOneClassToOnePort) {
620:
621: //
622: // Stop doing 1:1 class-port connections if there is
623: // a failure.
624: //
625: // Note that if we are doing 1:many class-port connections
626: // and we encounter an error, we continue to try to connect
627: // to port devices.
628: //
629:
630: break;
631: }
632: }
633:
634: if (!portConnectionSuccessful) {
635:
636: //
637: // The class driver was unable to connect to any port devices.
638: // Log a warning message.
639: //
640:
641: errorCode = KBDCLASS_NO_PORT_DEVICE_OBJECT;
642: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 18;
643:
644: }
645:
646: KeyboardClassInitializeExit:
647:
648: if (errorCode != STATUS_SUCCESS) {
649:
650: //
651: // The initialization failed in some way. Log an error.
652: //
653:
654: errorLogEntry = (PIO_ERROR_LOG_PACKET)
655: IoAllocateErrorLogEntry(
656: (classDeviceObject == NULL) ?
657: (PVOID) DriverObject : (PVOID) classDeviceObject,
658: (UCHAR) (sizeof(IO_ERROR_LOG_PACKET)
659: + (dumpCount * sizeof(ULONG)))
660: );
661:
662: if (errorLogEntry != NULL) {
663:
664: errorLogEntry->ErrorCode = errorCode;
665: errorLogEntry->DumpDataSize = dumpCount * sizeof(ULONG);
666: errorLogEntry->SequenceNumber = 0;
667: errorLogEntry->MajorFunctionCode = 0;
668: errorLogEntry->IoControlCode = 0;
669: errorLogEntry->RetryCount = 0;
670: errorLogEntry->UniqueErrorValue = uniqueErrorValue;
671: errorLogEntry->FinalStatus = status;
672: for (i = 0; i < dumpCount; i++)
673: errorLogEntry->DumpData[i] = dumpData[i];
674:
675: IoWriteErrorLogEntry(errorLogEntry);
676: }
677: }
678:
679: //
680: // Free the unicode strings.
681: //
682:
683: if (deviceNameSuffix.MaximumLength != 0)
684: ExFreePool(deviceNameSuffix.Buffer);
685: if (fullClassName.MaximumLength != 0)
686: ExFreePool(fullClassName.Buffer);
687: if (fullPortName.MaximumLength != 0)
688: ExFreePool(fullPortName.Buffer);
689: if (registryPath.MaximumLength != 0)
690: ExFreePool(registryPath.Buffer);
691:
692: if ((tmpDeviceExtension.ConnectOneClassToOnePort
693: && (!NT_SUCCESS(status))) ||
694: !portConnectionSuccessful) {
695:
696: //
697: // Clean up leftover resources. If we're doing 1:1 class-port
698: // connections, then we may have created a class device object
699: // for which the connect failed. If we're doing 1:many
700: // connections, we may have created a class device object but
701: // failed to make ANY connections. In either case, we
702: // free the ring buffer and delete the class device object.
703: //
704:
705: if (classDeviceObject) {
706: deviceExtension =
707: (PDEVICE_EXTENSION) classDeviceObject->DeviceExtension;
708: if ((deviceExtension) && (deviceExtension->InputData))
709: ExFreePool(deviceExtension->InputData);
710: IoDeleteDevice(classDeviceObject);
711: }
712: }
713:
714: //
715: // If we successfully connected to at least one keyboard port device,
716: // this driver's initialization was successful.
717: //
718:
719: if (portConnectionSuccessful) {
720:
721: //
722: // Set up the device driver entry points.
723: //
724:
725: DriverObject->DriverStartIo = KeyboardClassStartIo;
726: DriverObject->MajorFunction[IRP_MJ_CREATE] = KeyboardClassOpenClose;
727: DriverObject->MajorFunction[IRP_MJ_CLOSE] = KeyboardClassOpenClose;
728: DriverObject->MajorFunction[IRP_MJ_READ] = KeyboardClassRead;
729: DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] =
730: KeyboardClassFlush;
731: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
732: KeyboardClassDeviceControl;
733: DriverObject->MajorFunction[IRP_MJ_CLEANUP] = KeyboardClassCleanup;
734:
735: //
736: // NOTE: Don't allow this driver to unload. Otherwise, we would set
737: // DriverObject->DriverUnload = KeyboardClassUnload.
738: //
739:
740: status = STATUS_SUCCESS;
741: }
742:
743: KbdPrint((1,"KBDCLASS-KeyboardClassInitialize: exit\n"));
744:
745: return(status);
746:
747: }
748:
749: VOID
750: KeyboardClassCancel(
751: IN PDEVICE_OBJECT DeviceObject,
752: IN PIRP Irp
753: )
754:
755: /*++
756:
757: Routine Description:
758:
759: This routine is the class cancellation routine. It is
760: called from the I/O system when a request is cancelled. Read requests
761: are currently the only cancellable requests.
762:
763: N.B. The cancel spinlock is already held upon entry to this routine.
764: Also, there is no ISR to synchronize with.
765:
766: Arguments:
767:
768: DeviceObject - Pointer to class device object.
769:
770: Irp - Pointer to the request packet to be cancelled.
771:
772: Return Value:
773:
774: None.
775:
776: --*/
777:
778: {
779: PDEVICE_EXTENSION deviceExtension;
780: KIRQL currentIrql;
781: KIRQL cancelIrql;
782:
783: KbdPrint((2,"KBDCLASS-KeyboardClassCancel: enter\n"));
784:
785: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
786:
787: //
788: // Release the cancel spinlock and grab the keyboard class spinlock (it
789: // protects the RequestIsPending flag).
790: //
791:
792: IoReleaseCancelSpinLock(Irp->CancelIrql);
793: KeAcquireSpinLock(&deviceExtension->SpinLock, ¤tIrql);
794:
795: if ((deviceExtension->RequestIsPending)
796: && (Irp == DeviceObject->CurrentIrp)) {
797:
798: //
799: // The current request is being cancelled. Set the CurrentIrp to
800: // null, clear the RequestIsPending flag, and release the keyboard
801: // class spinlock before starting the next packet.
802: //
803:
804: DeviceObject->CurrentIrp = NULL;
805: deviceExtension->RequestIsPending = FALSE;
806: KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
807: IoStartNextPacket(DeviceObject, TRUE);
808:
809: } else {
810:
811: //
812: // Cancel a request in the device queue. Reacquire the cancel
813: // spinlock, remove the request from the queue, and release the
814: // cancel spinlock. Release the keyboard class spinlock.
815: //
816:
817: IoAcquireCancelSpinLock(&cancelIrql);
818: if (TRUE != KeRemoveEntryDeviceQueue(
819: &DeviceObject->DeviceQueue,
820: &Irp->Tail.Overlay.DeviceQueueEntry
821: )) {
822: KbdPrint((
823: 1,
824: "KBDCLASS-KeyboardClassCancel: Irp 0x%x not in device queue?!?\n",
825: Irp
826: ));
827: }
828: IoReleaseCancelSpinLock(cancelIrql);
829: KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
830: }
831:
832: //
833: // Complete the request with STATUS_CANCELLED.
834: //
835:
836: Irp->IoStatus.Status = STATUS_CANCELLED;
837: Irp->IoStatus.Information = 0;
838: IoCompleteRequest (Irp, IO_KEYBOARD_INCREMENT);
839:
840: KbdPrint((2,"KBDCLASS-KeyboardClassCancel: exit\n"));
841:
842: return;
843: }
844:
845: NTSTATUS
846: KeyboardClassCleanup(
847: IN PDEVICE_OBJECT DeviceObject,
848: IN PIRP Irp
849: )
850:
851: /*++
852:
853: Routine Description:
854:
855: This routine is the dispatch routine for cleanup requests.
856: All requests queued to the mouse class device (on behalf of
857: the thread for whom the cleanup request was generated) are
858: completed with STATUS_CANCELLED.
859:
860: Arguments:
861:
862: DeviceObject - Pointer to class device object.
863:
864: Irp - Pointer to the request packet.
865:
866: Return Value:
867:
868: Status is returned.
869:
870: --*/
871:
872: {
873: KIRQL spinlockIrql;
874: KIRQL cancelIrql;
875: PDEVICE_EXTENSION deviceExtension;
876: PKDEVICE_QUEUE_ENTRY packet;
877: PIRP currentIrp = NULL;
878: PIO_STACK_LOCATION irpSp;
879:
880: KbdPrint((2,"KBDCLASS-KeyboardClassCleanup: enter\n"));
881:
882: deviceExtension = DeviceObject->DeviceExtension;
883:
884: //
885: // Acquire the keyboard class spinlock and the cancel spinlock.
886: //
887:
888: KeAcquireSpinLock(&deviceExtension->SpinLock, &spinlockIrql);
889: IoAcquireCancelSpinLock(&cancelIrql);
890:
891: //
892: // Get a pointer to the current stack location for this request.
893: //
894:
895: irpSp = IoGetCurrentIrpStackLocation(Irp);
896:
897: //
898: // If the file object's FsContext is non-null, then the cleanup
899: // request is being executed by the trusted subsystem. Since the
900: // trusted subsystem is the only one with sufficient privilege to make
901: // Read requests to the driver, and since only Read requests get queued
902: // to the device queue, a cleanup request from the trusted subsystem is
903: // handled by cancelling all queued requests.
904: //
905: // If the FsContext is null, there is no cleanup work to perform
906: // (only read requests can be cancelled).
907: //
908: // NOTE: If this driver is to allow more than one trusted subsystem
909: // to make read requests to the same device object some day in
910: // the future, then there needs to be a mechanism that
911: // allows Cleanup to remove only those queued requests that
912: // were made by threads using the same FileObject as the
913: // file object in the Cleanup request.
914: //
915:
916: if (irpSp->FileObject->FsContext) {
917:
918: //
919: // Indicate that the cleanup routine has been called (StartIo cares
920: // about this).
921: //
922:
923: deviceExtension->CleanupWasInitiated = TRUE;
924:
925: //
926: // Complete all requests queued by this thread with STATUS_CANCELLED.
927: // Start with the real CurrentIrp, and run down the list of requests
928: // in the device queue. Be sure to set the real CurrentIrp to NULL
929: // and the RequestIsPending flag to FALSE, so that the class
930: // service callback routine won't attempt to complete CurrentIrp.
931: // Note that we can really only trust CurrentIrp when RequestIsPending.
932: //
933:
934: currentIrp = DeviceObject->CurrentIrp;
935: DeviceObject->CurrentIrp = NULL;
936: deviceExtension->RequestIsPending = FALSE;
937:
938: while (currentIrp != NULL) {
939:
940: //
941: // Remove the CurrentIrp from the cancellable state.
942: //
943: //
944:
945: IoSetCancelRoutine(currentIrp, NULL);
946:
947: //
948: // Set Status to CANCELLED, release the spinlocks,
949: // and complete the request. Note that the IRQL is reset to
950: // DISPATCH_LEVEL when we release the spinlocks.
951: //
952:
953: currentIrp->IoStatus.Status = STATUS_CANCELLED;
954: currentIrp->IoStatus.Information = 0;
955:
956: IoReleaseCancelSpinLock(cancelIrql);
957: KeReleaseSpinLock(&deviceExtension->SpinLock, spinlockIrql);
958: IoCompleteRequest(currentIrp, IO_KEYBOARD_INCREMENT);
959:
960: //
961: // Reacquire the spinlocks.
962: //
963:
964: KeAcquireSpinLock(&deviceExtension->SpinLock, &spinlockIrql);
965: IoAcquireCancelSpinLock(&cancelIrql);
966:
967: //
968: // Dequeue the next packet (IRP) from the device work queue.
969: //
970:
971: packet = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
972: if (packet != NULL) {
973: currentIrp =
974: CONTAINING_RECORD(packet, IRP, Tail.Overlay.DeviceQueueEntry);
975: } else {
976: currentIrp = (PIRP) NULL;
977: }
978:
979: } // end while
980: }
981:
982: //
983: // Release the spinlocks and lower IRQL.
984: //
985:
986: IoReleaseCancelSpinLock(cancelIrql);
987: KeReleaseSpinLock(&deviceExtension->SpinLock, spinlockIrql);
988:
989: //
990: // Complete the cleanup request with STATUS_SUCCESS.
991: //
992:
993: Irp->IoStatus.Status = STATUS_SUCCESS;
994: Irp->IoStatus.Information = 0;
995: IoCompleteRequest (Irp, IO_NO_INCREMENT);
996:
997: KbdPrint((2,"KBDCLASS-KeyboardClassCleanup: exit\n"));
998:
999: return(STATUS_SUCCESS);
1000:
1001: }
1002:
1003: NTSTATUS
1004: KeyboardClassDeviceControl(
1005: IN PDEVICE_OBJECT DeviceObject,
1006: IN PIRP Irp
1007: )
1008:
1009: /*++
1010:
1011: Routine Description:
1012:
1013: This routine is the dispatch routine for device control requests.
1014: All device control subfunctions are passed, asynchronously, to the
1015: connected port driver for processing and completion.
1016:
1017: Arguments:
1018:
1019: DeviceObject - Pointer to class device object.
1020:
1021: Irp - Pointer to the request packet.
1022:
1023: Return Value:
1024:
1025: Status is returned.
1026:
1027: --*/
1028:
1029: {
1030: PIO_STACK_LOCATION irpSp;
1031: PIO_STACK_LOCATION nextSp;
1032: PDEVICE_EXTENSION deviceExtension;
1033: NTSTATUS status = STATUS_SUCCESS;
1034: ULONG unitId;
1035:
1036: KbdPrint((2,"KBDCLASS-KeyboardClassDeviceControl: enter\n"));
1037:
1038: //
1039: // Get a pointer to the device extension.
1040: //
1041:
1042: deviceExtension = DeviceObject->DeviceExtension;
1043:
1044: //
1045: // Get a pointer to the current parameters for this request. The
1046: // information is contained in the current stack location.
1047: //
1048:
1049: irpSp = IoGetCurrentIrpStackLocation(Irp);
1050:
1051: //
1052: // Check for adequate input buffer length. The input buffer
1053: // should, at a minimum, contain the unit ID specifying one of
1054: // the connected port devices. If there is no input buffer (i.e.,
1055: // the input buffer length is zero), then we assume the unit ID
1056: // is zero (for backwards compatibility).
1057: //
1058:
1059: if (irpSp->Parameters.DeviceIoControl.InputBufferLength == 0) {
1060: unitId = 0;
1061: } else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
1062: sizeof(KEYBOARD_UNIT_ID_PARAMETER)) {
1063: status = STATUS_BUFFER_TOO_SMALL;
1064:
1065: } else {
1066: unitId = ((PKEYBOARD_UNIT_ID_PARAMETER)
1067: Irp->AssociatedIrp.SystemBuffer)->UnitId;
1068: if (unitId >= deviceExtension->MaximumPortsServiced) {
1069: status = STATUS_INVALID_PARAMETER;
1070: }
1071: }
1072:
1073: if (NT_SUCCESS(status)) {
1074:
1075: //
1076: // Pass the device control request on to the port driver,
1077: // asynchronously. Get the next IRP stack location and copy the
1078: // input parameters to the next stack location. Change the major
1079: // function to internal device control.
1080: //
1081:
1082: nextSp = IoGetNextIrpStackLocation(Irp);
1083: ASSERT(nextSp != NULL);
1084: nextSp->Parameters.DeviceIoControl =
1085: irpSp->Parameters.DeviceIoControl;
1086: nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1087:
1088: //
1089: // Mark the packet pending.
1090: //
1091:
1092: IoMarkIrpPending(Irp);
1093:
1094: //
1095: // Pass the IRP on to the connected port device (specified by
1096: // the unit ID). The port device driver will process the request.
1097: //
1098:
1099: status = IoCallDriver(
1100: deviceExtension->PortDeviceObjectList[unitId],
1101: Irp
1102: );
1103: } else {
1104:
1105: //
1106: // Complete the request.
1107: //
1108:
1109: Irp->IoStatus.Status = status;
1110: Irp->IoStatus.Information = 0;
1111: IoCompleteRequest(Irp, IO_NO_INCREMENT);
1112: }
1113:
1114: KbdPrint((2,"KBDCLASS-KeyboardClassDeviceControl: exit\n"));
1115:
1116: return(status);
1117:
1118: }
1119:
1120: NTSTATUS
1121: KeyboardClassFlush(
1122: IN PDEVICE_OBJECT DeviceObject,
1123: IN PIRP Irp
1124: )
1125:
1126: /*++
1127:
1128: Routine Description:
1129:
1130: This routine is the dispatch routine for flush requests. The class
1131: input data queue is reinitialized.
1132:
1133: Arguments:
1134:
1135: DeviceObject - Pointer to class device object.
1136:
1137: Irp - Pointer to the request packet.
1138:
1139: Return Value:
1140:
1141: Status is returned.
1142:
1143: --*/
1144:
1145: {
1146: PDEVICE_EXTENSION deviceExtension;
1147: NTSTATUS status = STATUS_SUCCESS;
1148:
1149: KbdPrint((2,"KBDCLASS-KeyboardClassFlush: enter\n"));
1150:
1151: //
1152: // Get a pointer to the device extension.
1153: //
1154:
1155: deviceExtension = DeviceObject->DeviceExtension;
1156:
1157: //
1158: // Initialize keyboard class input data queue.
1159: //
1160:
1161: KbdInitializeDataQueue((PVOID)deviceExtension);
1162:
1163: //
1164: // Complete the request and return status.
1165: //
1166:
1167: Irp->IoStatus.Status = status;
1168: Irp->IoStatus.Information = 0;
1169: IoCompleteRequest(Irp, IO_NO_INCREMENT);
1170:
1171: KbdPrint((2,"KBDCLASS-KeyboardClassFlush: exit\n"));
1172:
1173: return(status);
1174:
1175: }
1176:
1177: NTSTATUS
1178: KeyboardClassOpenClose(
1179: IN PDEVICE_OBJECT DeviceObject,
1180: IN PIRP Irp
1181: )
1182:
1183: /*++
1184:
1185: Routine Description:
1186:
1187: This routine is the dispatch routine for create/open and close requests.
1188: Open/close requests are completed here.
1189:
1190: Arguments:
1191:
1192: DeviceObject - Pointer to class device object.
1193:
1194: Irp - Pointer to the request packet.
1195:
1196: Return Value:
1197:
1198: Status is returned.
1199:
1200: --*/
1201:
1202: {
1203: PIO_STACK_LOCATION irpSp;
1204: PDEVICE_EXTENSION deviceExtension;
1205: KIRQL oldIrql;
1206: BOOLEAN enableFlag = FALSE;
1207: NTSTATUS status = STATUS_SUCCESS;
1208: PIO_ERROR_LOG_PACKET errorLogEntry;
1209: BOOLEAN SomeEnableDisableSucceeded = FALSE;
1210: ULONG i;
1211:
1212: KbdPrint((2,"KBDCLASS-KeyboardClassOpenClose: enter\n"));
1213:
1214: //
1215: // Get a pointer to the device extension.
1216: //
1217:
1218: deviceExtension = DeviceObject->DeviceExtension;
1219:
1220: //
1221: // Get a pointer to the current parameters for this request. The
1222: // information is contained in the current stack location.
1223: //
1224:
1225: irpSp = IoGetCurrentIrpStackLocation(Irp);
1226:
1227: //
1228: // Case on the function that is being performed by the requestor.
1229: //
1230:
1231: switch (irpSp->MajorFunction) {
1232:
1233: //
1234: // For the create/open operation, send a KEYBOARD_ENABLE internal
1235: // device control request to the port driver to enable interrupts.
1236: //
1237:
1238: case IRP_MJ_CREATE:
1239:
1240: //
1241: // First, if the requestor is the trusted subsystem (the single
1242: // reader), reset the the cleanup indicator and set the file
1243: // object's FsContext to non-null (KeyboardClassRead uses
1244: // FsContext to determine if the requestor has sufficient
1245: // privilege to perform the read operation).
1246: //
1247:
1248: if (SeSinglePrivilegeCheck(RtlConvertLongToLargeInteger(
1249: SE_TCB_PRIVILEGE),
1250: Irp->RequestorMode
1251: )) {
1252:
1253: KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
1254: deviceExtension->CleanupWasInitiated = FALSE;
1255: irpSp->FileObject->FsContext = (PVOID) 1;
1256: KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
1257: }
1258:
1259: enableFlag = TRUE;
1260:
1261: break;
1262:
1263: //
1264: // For the close operation, send a KEYBOARD_DISABLE internal device
1265: // control request to the port driver to disable interrupts.
1266: //
1267:
1268: case IRP_MJ_CLOSE:
1269:
1270: break;
1271:
1272: }
1273:
1274: //
1275: // Enable/disable interrupts via port driver.
1276: //
1277:
1278: for (i = 0; i < deviceExtension->MaximumPortsServiced; i++) {
1279:
1280: status = KbdEnableDisablePort(DeviceObject, enableFlag, i);
1281:
1282: if (status != STATUS_SUCCESS) {
1283:
1284: KbdPrint((
1285: 0,
1286: "KBDCLASS-KeyboardClassOpenClose: Could not enable/disable interrupts for port device object @ 0x%x\n",
1287: deviceExtension->PortDeviceObjectList[i]
1288: ));
1289:
1290: //
1291: // Log an error.
1292: //
1293:
1294: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
1295: DeviceObject,
1296: sizeof(IO_ERROR_LOG_PACKET)
1297: );
1298:
1299: if (errorLogEntry != NULL) {
1300:
1301: errorLogEntry->ErrorCode =
1302: enableFlag? KBDCLASS_PORT_INTERRUPTS_NOT_ENABLED:
1303: KBDCLASS_PORT_INTERRUPTS_NOT_DISABLED;
1304: errorLogEntry->SequenceNumber = 0;
1305: errorLogEntry->MajorFunctionCode = irpSp->MajorFunction;
1306: errorLogEntry->IoControlCode = 0;
1307: errorLogEntry->RetryCount = 0;
1308: errorLogEntry->UniqueErrorValue =
1309: KEYBOARD_ERROR_VALUE_BASE + 120;
1310: errorLogEntry->FinalStatus = status;
1311:
1312: IoWriteErrorLogEntry(errorLogEntry);
1313: }
1314:
1315: } else {
1316: SomeEnableDisableSucceeded = TRUE;
1317: }
1318: }
1319:
1320: //
1321: // Complete the request and return status.
1322: //
1323: // NOTE: We complete the request successfully if any one of the
1324: // connected port devices successfully handled the request.
1325: // The RIT only knows about one pointing device.
1326: //
1327:
1328: if (SomeEnableDisableSucceeded) {
1329: status = STATUS_SUCCESS;
1330: }
1331:
1332: Irp->IoStatus.Status = status;
1333: Irp->IoStatus.Information = 0;
1334: IoCompleteRequest(Irp, IO_NO_INCREMENT);
1335:
1336: KbdPrint((2,"KBDCLASS-KeyboardClassOpenClose: exit\n"));
1337:
1338: return(status);
1339: }
1340:
1341: NTSTATUS
1342: KeyboardClassRead(
1343: IN PDEVICE_OBJECT DeviceObject,
1344: IN PIRP Irp
1345: )
1346:
1347: /*++
1348:
1349: Routine Description:
1350:
1351: This routine is the dispatch routine for read requests. Valid read
1352: requests are marked pending, and started via IoStartPacket.
1353:
1354: Arguments:
1355:
1356: DeviceObject - Pointer to class device object.
1357:
1358: Irp - Pointer to the request packet.
1359:
1360: Return Value:
1361:
1362: Status is returned.
1363:
1364: --*/
1365:
1366: {
1367: NTSTATUS status;
1368: PIO_STACK_LOCATION irpSp;
1369:
1370: KbdPrint((2,"KBDCLASS-KeyboardClassRead: enter\n"));
1371:
1372: irpSp = IoGetCurrentIrpStackLocation(Irp);
1373:
1374: //
1375: // Validate the read request parameters. The read length should be an
1376: // integral number of KEYBOARD_INPUT_DATA structures.
1377: //
1378:
1379:
1380: if (irpSp->Parameters.Read.Length == 0) {
1381: status = STATUS_SUCCESS;
1382: }
1383: else if (irpSp->Parameters.Read.Length % sizeof(KEYBOARD_INPUT_DATA)) {
1384: status = STATUS_BUFFER_TOO_SMALL;
1385: }
1386: else if (irpSp->FileObject->FsContext) {
1387:
1388: //
1389: // If the file object's FsContext is non-null, then we've already
1390: // done the Read privilege check once before for this thread. Skip
1391: // the privilege check.
1392: //
1393:
1394: status = STATUS_PENDING;
1395: }
1396: else {
1397:
1398: //
1399: // We only allow a trusted subsystem with the appropriate privilege
1400: // level to execute a Read call.
1401: //
1402:
1403: status = STATUS_PRIVILEGE_NOT_HELD;
1404:
1405:
1406: }
1407:
1408: //
1409: // If status is pending, mark the packet pending and start the packet
1410: // in a cancellable state. Otherwise, complete the request.
1411: //
1412:
1413: Irp->IoStatus.Status = status;
1414: Irp->IoStatus.Information = 0;
1415: if (status == STATUS_PENDING) {
1416: IoMarkIrpPending(Irp);
1417: IoStartPacket(DeviceObject, Irp, (PULONG)NULL, KeyboardClassCancel);
1418: } else {
1419: IoCompleteRequest(Irp, IO_NO_INCREMENT);
1420: }
1421:
1422: KbdPrint((2,"KBDCLASS-KeyboardClassRead: exit\n"));
1423:
1424: return(status);
1425:
1426: }
1427:
1428: VOID
1429: KeyboardClassServiceCallback(
1430: IN PDEVICE_OBJECT DeviceObject,
1431: IN PKEYBOARD_INPUT_DATA InputDataStart,
1432: IN PKEYBOARD_INPUT_DATA InputDataEnd,
1433: IN OUT PULONG InputDataConsumed
1434: )
1435:
1436: /*++
1437:
1438: Routine Description:
1439:
1440: This routine is the class service callback routine. It is
1441: called from the port driver's interrupt service DPC. If there is an
1442: outstanding read request, the request is satisfied from the port input
1443: data queue. Unsolicited keyboard input is moved from the port input
1444: data queue to the class input data queue.
1445:
1446: N.B. This routine is entered at DISPATCH_LEVEL IRQL from the port
1447: driver's ISR DPC routine.
1448:
1449: Arguments:
1450:
1451: DeviceObject - Pointer to class device object.
1452:
1453: InputDataStart - Pointer to the start of the data in the port input
1454: data queue.
1455:
1456: InputDataEnd - Points one input data structure past the end of the
1457: valid port input data.
1458:
1459: InputDataConsumed - Pointer to storage in which the number of input
1460: data structures consumed by this call is returned.
1461:
1462: NOTE: Could pull the duplicate code out into a called procedure.
1463:
1464: Return Value:
1465:
1466: None.
1467:
1468: --*/
1469:
1470: {
1471: PDEVICE_EXTENSION deviceExtension;
1472: PIO_STACK_LOCATION irpSp;
1473: PIRP irp;
1474: KIRQL cancelIrql;
1475: ULONG bytesInQueue;
1476: ULONG bytesToMove;
1477: ULONG moveSize;
1478: BOOLEAN satisfiedPendingReadRequest = FALSE;
1479: PIO_ERROR_LOG_PACKET errorLogEntry;
1480:
1481: KbdPrint((2,"KBDCLASS-KeyboardClassServiceCallback: enter\n"));
1482:
1483: deviceExtension = DeviceObject->DeviceExtension;
1484: bytesInQueue = (PCHAR) InputDataEnd - (PCHAR) InputDataStart;
1485: moveSize = 0;
1486: *InputDataConsumed = 0;
1487:
1488: //
1489: // Acquire the spinlock that protects the class device extension
1490: // (so we can look at RequestIsPending synchronously). If there is
1491: // a pending read request, satisfy it.
1492: //
1493: // N.B. We can use KeAcquireSpinLockAtDpcLevel, instead of
1494: // KeAcquireSpinLock, because this routine is already running
1495: // at DISPATCH_IRQL.
1496: //
1497:
1498: KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
1499:
1500: if (deviceExtension->RequestIsPending) {
1501:
1502: //
1503: // Acquire the cancel spinlock, remove the request from the
1504: // cancellable state, and free the cancel spinlock.
1505: //
1506:
1507: IoAcquireCancelSpinLock(&cancelIrql);
1508: irp = DeviceObject->CurrentIrp;
1509: IoSetCancelRoutine(irp, NULL);
1510: DeviceObject->CurrentIrp = NULL;
1511: IoReleaseCancelSpinLock(cancelIrql);
1512:
1513: //
1514: // An outstanding read request exists. Clear the RequestIsPending
1515: // flag to indicate there is no longer an outstanding read request
1516: // pending.
1517: //
1518:
1519: deviceExtension->RequestIsPending = FALSE;
1520:
1521: //
1522: // Copy as much of the input data possible from the port input
1523: // data queue to the SystemBuffer to satisfy the read.
1524: //
1525:
1526: irpSp = IoGetCurrentIrpStackLocation(irp);
1527: bytesToMove = irpSp->Parameters.Read.Length;
1528: moveSize = (bytesInQueue < bytesToMove) ?
1529: bytesInQueue:bytesToMove;
1530: *InputDataConsumed += (moveSize / sizeof(KEYBOARD_INPUT_DATA));
1531:
1532: KbdPrint((
1533: 3,
1534: "KBDCLASS-KeyboardClassServiceCallback: port queue length 0x%lx, read length 0x%lx\n",
1535: bytesInQueue,
1536: bytesToMove
1537: ));
1538: KbdPrint((
1539: 3,
1540: "KBDCLASS-KeyboardClassServiceCallback: number of bytes to move from port to SystemBuffer 0x%lx\n",
1541: moveSize
1542: ));
1543: KbdPrint((
1544: 3,
1545: "KBDCLASS-KeyboardClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
1546: (PCHAR) InputDataStart,
1547: irp->AssociatedIrp.SystemBuffer
1548: ));
1549:
1550: RtlMoveMemory(
1551: irp->AssociatedIrp.SystemBuffer,
1552: (PCHAR) InputDataStart,
1553: moveSize
1554: );
1555:
1556: //
1557: // Set the flag so that we start the next packet and complete
1558: // this read request (with STATUS_SUCCESS) prior to return.
1559: //
1560:
1561: irp->IoStatus.Status = STATUS_SUCCESS;
1562: irp->IoStatus.Information = moveSize;
1563: irpSp->Parameters.Read.Length = moveSize;
1564: satisfiedPendingReadRequest = TRUE;
1565:
1566: }
1567:
1568: //
1569: // If there is still data in the port input data queue, move it to the class
1570: // input data queue.
1571: //
1572:
1573: InputDataStart = (PKEYBOARD_INPUT_DATA) ((PCHAR) InputDataStart + moveSize);
1574: moveSize = bytesInQueue - moveSize;
1575: KbdPrint((
1576: 3,
1577: "KBDCLASS-KeyboardClassServiceCallback: bytes remaining after move to SystemBuffer 0x%lx\n",
1578: moveSize
1579: ));
1580:
1581: if (moveSize > 0) {
1582:
1583: //
1584: // Move the remaining data from the port input data queue to
1585: // the class input data queue. The move will happen in two
1586: // parts in the case where the class input data buffer wraps.
1587:
1588: bytesInQueue =
1589: deviceExtension->KeyboardAttributes.InputDataQueueLength -
1590: (deviceExtension->InputCount * sizeof(KEYBOARD_INPUT_DATA));
1591: bytesToMove = moveSize;
1592:
1593: KbdPrint((
1594: 3,
1595: "KBDCLASS-KeyboardClassServiceCallback: unused bytes in class queue 0x%lx, remaining bytes in port queue 0x%lx\n",
1596: bytesInQueue,
1597: bytesToMove
1598: ));
1599:
1600: if (bytesInQueue == 0) {
1601:
1602: //
1603: // Refuse to move any bytes that would cause a class input data
1604: // queue overflow. Just drop the bytes on the floor, and
1605: // log an overrun error.
1606: //
1607:
1608: KbdPrint((
1609: 1,
1610: "KBDCLASS-KeyboardClassServiceCallback: Class input data queue OVERRUN\n"
1611: ));
1612:
1613: if (deviceExtension->OkayToLogOverflow) {
1614:
1615: //
1616: // Log an error.
1617: //
1618:
1619: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
1620: DeviceObject,
1621: sizeof(IO_ERROR_LOG_PACKET)
1622: + (2 * sizeof(ULONG))
1623: );
1624:
1625: if (errorLogEntry != NULL) {
1626:
1627: errorLogEntry->ErrorCode = KBDCLASS_KBD_BUFFER_OVERFLOW;
1628: errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
1629: errorLogEntry->SequenceNumber = 0;
1630: errorLogEntry->MajorFunctionCode = 0;
1631: errorLogEntry->IoControlCode = 0;
1632: errorLogEntry->RetryCount = 0;
1633: errorLogEntry->UniqueErrorValue =
1634: KEYBOARD_ERROR_VALUE_BASE + 210;
1635: errorLogEntry->FinalStatus = 0;
1636: errorLogEntry->DumpData[0] = bytesToMove;
1637: errorLogEntry->DumpData[1] =
1638: deviceExtension->KeyboardAttributes.InputDataQueueLength;
1639:
1640: IoWriteErrorLogEntry(errorLogEntry);
1641: }
1642:
1643: deviceExtension->OkayToLogOverflow = FALSE;
1644: }
1645:
1646: } else {
1647:
1648: //
1649: // There is room in the class input data queue, so move
1650: // the remaining port input data to it.
1651: //
1652: // BytesToMove <- MIN(Number of unused bytes in class input data
1653: // queue, Number of bytes remaining in port
1654: // input queue).
1655: // This is the total number of bytes that actually will move from
1656: // the port input data queue to the class input data queue.
1657: //
1658:
1659: bytesToMove = (bytesInQueue < bytesToMove) ?
1660: bytesInQueue:bytesToMove;
1661:
1662: //
1663: // BytesInQueue <- Number of unused bytes from insertion pointer to
1664: // the end of the class input data queue (i.e., until the buffer
1665: // wraps).
1666: //
1667:
1668: bytesInQueue = ((PCHAR) deviceExtension->InputData +
1669: deviceExtension->KeyboardAttributes.InputDataQueueLength) -
1670: (PCHAR) deviceExtension->DataIn;
1671:
1672: KbdPrint((
1673: 3,
1674: "KBDCLASS-KeyboardClassServiceCallback: total number of bytes to move to class queue 0x%lx\n",
1675: bytesToMove
1676: ));
1677: KbdPrint((
1678: 3,
1679: "KBDCLASS-KeyboardClassServiceCallback: number of bytes to end of class buffer 0x%lx\n",
1680: bytesInQueue
1681: ));
1682:
1683: //
1684: // MoveSize <- Number of bytes to handle in the first move.
1685: //
1686:
1687: moveSize = (bytesToMove < bytesInQueue) ?
1688: bytesToMove:bytesInQueue;
1689: KbdPrint((
1690: 3,
1691: "KBDCLASS-KeyboardClassServiceCallback: number of bytes in first move to class 0x%lx\n",
1692: moveSize
1693: ));
1694:
1695: //
1696: // Do the move from the port data queue to the class data queue.
1697: //
1698:
1699: KbdPrint((
1700: 3,
1701: "KBDCLASS-KeyboardClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
1702: (PCHAR) InputDataStart,
1703: (PCHAR) deviceExtension->DataIn
1704: ));
1705: RtlMoveMemory(
1706: (PCHAR) deviceExtension->DataIn,
1707: (PCHAR) InputDataStart,
1708: moveSize
1709: );
1710:
1711: //
1712: // Increment the port data queue pointer and the class input
1713: // data queue insertion pointer. Wrap the insertion pointer,
1714: // if necessary.
1715: //
1716:
1717: InputDataStart = (PKEYBOARD_INPUT_DATA)
1718: (((PCHAR) InputDataStart) + moveSize);
1719: deviceExtension->DataIn = (PKEYBOARD_INPUT_DATA)
1720: (((PCHAR) deviceExtension->DataIn) + moveSize);
1721: if ((PCHAR) deviceExtension->DataIn >=
1722: ((PCHAR) deviceExtension->InputData +
1723: deviceExtension->KeyboardAttributes.InputDataQueueLength)) {
1724: deviceExtension->DataIn = deviceExtension->InputData;
1725: }
1726:
1727: if ((bytesToMove - moveSize) > 0) {
1728:
1729: //
1730: // Special case. The data must wrap in the class input data buffer.
1731: // Copy the rest of the port input data into the beginning of the
1732: // class input data queue.
1733: //
1734:
1735: //
1736: // MoveSize <- Number of bytes to handle in the second move.
1737: //
1738:
1739: moveSize = bytesToMove - moveSize;
1740:
1741: //
1742: // Do the move from the port data queue to the class data queue.
1743: //
1744:
1745: KbdPrint((
1746: 3,
1747: "KBDCLASS-KeyboardClassServiceCallback: number of bytes in second move to class 0x%lx\n",
1748: moveSize
1749: ));
1750: KbdPrint((
1751: 3,
1752: "KBDCLASS-KeyboardClassServiceCallback: move bytes from 0x%lx to 0x%lx\n",
1753: (PCHAR) InputDataStart,
1754: (PCHAR) deviceExtension->DataIn
1755: ));
1756:
1757: RtlMoveMemory(
1758: (PCHAR) deviceExtension->DataIn,
1759: (PCHAR) InputDataStart,
1760: moveSize
1761: );
1762:
1763: //
1764: // Update the class input data queue insertion pointer.
1765: //
1766:
1767: deviceExtension->DataIn = (PKEYBOARD_INPUT_DATA)
1768: (((PCHAR) deviceExtension->DataIn) + moveSize);
1769: }
1770:
1771: //
1772: // Update the input data queue counter.
1773: //
1774:
1775: deviceExtension->InputCount +=
1776: (bytesToMove / sizeof(KEYBOARD_INPUT_DATA));
1777: *InputDataConsumed += (bytesToMove / sizeof(KEYBOARD_INPUT_DATA));
1778:
1779: KbdPrint((
1780: 3,
1781: "KBDCLASS-KeyboardClassServiceCallback: changed InputCount to %ld entries in the class queue\n",
1782: deviceExtension->InputCount
1783: ));
1784: KbdPrint((
1785: 3,
1786: "KBDCLASS-KeyboardClassServiceCallback: DataIn 0x%lx, DataOut 0x%lx\n",
1787: deviceExtension->DataIn,
1788: deviceExtension->DataOut
1789: ));
1790: KbdPrint((
1791: 3,
1792: "KBDCLASS-KeyboardClassServiceCallback: Input data items consumed = %d\n",
1793: *InputDataConsumed
1794: ));
1795:
1796: }
1797: }
1798:
1799: //
1800: // Release the class input data queue spinlock.
1801: //
1802:
1803: KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
1804:
1805: //
1806: // If we satisfied an outstanding read request, start the next
1807: // packet and complete the request.
1808: //
1809:
1810: if (satisfiedPendingReadRequest) {
1811: IoStartNextPacket(DeviceObject, TRUE);
1812: IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);
1813: }
1814:
1815: KbdPrint((2,"KBDCLASS-KeyboardClassServiceCallback: exit\n"));
1816:
1817: return;
1818:
1819: }
1820:
1821: VOID
1822: KeyboardClassStartIo(
1823: IN PDEVICE_OBJECT DeviceObject,
1824: IN PIRP Irp
1825: )
1826:
1827: /*++
1828:
1829: Routine Description:
1830:
1831: This routine is the StartIo routine. It is invoked to start a Read
1832: request. If the class input data queue contains input data, the input
1833: data is copied to the SystemBuffer to satisfy the read.
1834:
1835: N.B. Requests enter KeyboardClassStartIo in a cancellable state. Also,
1836: there is an implicit assumption that only read requests are
1837: queued to the device queue (and handled by StartIo). If this
1838: changes in the future, the KeyboardClassCleanup routine will
1839: be impacted.
1840:
1841: NOTE: Could pull the duplicate code out into a called procedure.
1842:
1843: Arguments:
1844:
1845: DeviceObject - Pointer to class device object.
1846:
1847: Irp - Pointer to the request packet.
1848:
1849: Return Value:
1850:
1851: None.
1852:
1853: --*/
1854:
1855: {
1856: PDEVICE_EXTENSION deviceExtension;
1857: PIO_STACK_LOCATION irpSp;
1858: KIRQL cancelIrql;
1859: PCHAR destination;
1860: ULONG bytesInQueue;
1861: ULONG bytesToMove;
1862: ULONG moveSize;
1863:
1864: KbdPrint((2,"KBDCLASS-KeyboardClassStartIo: enter\n"));
1865:
1866: deviceExtension = DeviceObject->DeviceExtension;
1867:
1868: //
1869: // Bump the error log sequence number.
1870: //
1871:
1872: deviceExtension->SequenceNumber += 1;
1873:
1874: //
1875: // Acquire the class spinlock to protect the input data queue and associated
1876: // pointers. Note that StartIo is already running at DISPATCH_LEVEL
1877: // IRQL, so we can use KeAcquireSpinLockAtDpcLevel instead of
1878: // KeAcquireSpinLock.
1879: //
1880:
1881: KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
1882:
1883: //
1884: // Acquire the cancel spinlock and verify that the Irp has not been
1885: // cancelled and that cleanup is not in progress.
1886: //
1887:
1888: IoAcquireCancelSpinLock(&cancelIrql);
1889: if (Irp->Cancel || deviceExtension->CleanupWasInitiated) {
1890: IoReleaseCancelSpinLock(cancelIrql);
1891: KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
1892: return;
1893: }
1894:
1895: KbdPrint((
1896: 3,
1897: "KBDCLASS-KeyboardClassStartIo: DataIn 0x%lx, DataOut 0x%lx\n",
1898: deviceExtension->DataIn,
1899: deviceExtension->DataOut
1900: ));
1901:
1902: KbdPrint((
1903: 3,
1904: "KBDCLASS-KeyboardClassStartIo: entries in queue %ld\n",
1905: deviceExtension->InputCount
1906: ));
1907:
1908: //
1909: // If the input data queue is non-empty, satisfy the read request.
1910: // Otherwise, hold the request pending.
1911: //
1912:
1913: if (deviceExtension->InputCount != 0) {
1914:
1915: //
1916: // Copy as much of the input data as possible from the class input
1917: // data queue to the SystemBuffer to satisfy the read. It may be
1918: // necessary to copy the data in two chunks (i.e., if the circular
1919: // queue wraps).
1920: // First, remove the request from the cancellable state, and free the
1921: // cancel spinlock.
1922: //
1923:
1924: IoSetCancelRoutine(Irp, NULL);
1925: DeviceObject->CurrentIrp = NULL;
1926: IoReleaseCancelSpinLock(cancelIrql);
1927:
1928: irpSp = IoGetCurrentIrpStackLocation(Irp);
1929:
1930: //
1931: // BytesToMove <- MIN(Number of filled bytes in class input data queue,
1932: // Requested read length).
1933: //
1934:
1935: bytesInQueue = deviceExtension->InputCount *
1936: sizeof(KEYBOARD_INPUT_DATA);
1937: bytesToMove = irpSp->Parameters.Read.Length;
1938: KbdPrint((
1939: 3,
1940: "KBDCLASS-KeyboardClassStartIo: queue size 0x%lx, read length 0x%lx\n",
1941: bytesInQueue,
1942: bytesToMove
1943: ));
1944: bytesToMove = (bytesInQueue < bytesToMove) ?
1945: bytesInQueue:bytesToMove;
1946:
1947: //
1948: // MoveSize <- MIN(Number of bytes to be moved from the class queue,
1949: // Number of bytes to end of class input data queue).
1950: //
1951:
1952: bytesInQueue = ((PCHAR) deviceExtension->InputData +
1953: deviceExtension->KeyboardAttributes.InputDataQueueLength) -
1954: (PCHAR) deviceExtension->DataOut;
1955: moveSize = (bytesToMove < bytesInQueue) ?
1956: bytesToMove:bytesInQueue;
1957: KbdPrint((
1958: 3,
1959: "KBDCLASS-KeyboardClassStartIo: bytes to end of queue 0x%lx\n",
1960: bytesInQueue
1961: ));
1962:
1963: //
1964: // Move bytes from the class input data queue to SystemBuffer, until
1965: // the request is satisfied or we wrap the class input data buffer.
1966: //
1967:
1968: destination = Irp->AssociatedIrp.SystemBuffer;
1969: KbdPrint((
1970: 3,
1971: "KBDCLASS-KeyboardClassStartIo: number of bytes in first move 0x%lx\n",
1972: moveSize
1973: ));
1974: KbdPrint((
1975: 3,
1976: "KBDCLASS-KeyboardClassStartIo: move bytes from 0x%lx to 0x%lx\n",
1977: (PCHAR) deviceExtension->DataOut, destination
1978: ));
1979: RtlMoveMemory(
1980: destination,
1981: (PCHAR) deviceExtension->DataOut,
1982: moveSize
1983: );
1984: destination += moveSize;
1985:
1986: //
1987: // If the data wraps in the class input data buffer, copy the rest
1988: // of the data from the start of the input data queue
1989: // buffer through the end of the queued data.
1990: //
1991:
1992: if ((bytesToMove - moveSize) > 0) {
1993:
1994: //
1995: // MoveSize <- Remaining number bytes to move.
1996: //
1997:
1998: moveSize = bytesToMove - moveSize;
1999:
2000: //
2001: // Move the bytes from the class input data queue to SystemBuffer.
2002: //
2003:
2004: KbdPrint((
2005: 3,
2006: "KBDCLASS-KeyboardClassStartIo: number of bytes in second move 0x%lx\n",
2007: moveSize
2008: ));
2009: KbdPrint((
2010: 3,
2011: "KBDCLASS-KeyboardClassStartIo: move bytes from 0x%lx to 0x%lx\n",
2012: (PCHAR) deviceExtension->InputData,
2013: destination
2014: ));
2015: RtlMoveMemory(
2016: destination,
2017: (PCHAR) deviceExtension->InputData,
2018: moveSize
2019: );
2020:
2021: //
2022: // Update the class input data queue removal pointer.
2023: //
2024:
2025: deviceExtension->DataOut = (PKEYBOARD_INPUT_DATA)
2026: (((PCHAR) deviceExtension->InputData) + moveSize);
2027: } else {
2028:
2029: //
2030: // Update the input data queue removal pointer.
2031: //
2032:
2033: deviceExtension->DataOut = (PKEYBOARD_INPUT_DATA)
2034: (((PCHAR) deviceExtension->DataOut) + moveSize);
2035: }
2036:
2037: //
2038: // Update the class input data queue InputCount.
2039: //
2040:
2041: deviceExtension->InputCount -=
2042: (bytesToMove / sizeof(KEYBOARD_INPUT_DATA));
2043:
2044: if (deviceExtension->InputCount == 0) {
2045:
2046: //
2047: // Reset the flag that determines whether it is time to log
2048: // queue overflow errors. We don't want to log errors too often.
2049: // Instead, log an error on the first overflow that occurs after
2050: // the ring buffer has been emptied, and then stop logging errors
2051: // until it gets cleared out and overflows again.
2052: //
2053:
2054: KbdPrint((
2055: 1,
2056: "KBDCLASS-KeyboardClassStartIo: Okay to log overflow\n"
2057: ));
2058: deviceExtension->OkayToLogOverflow = TRUE;
2059: }
2060:
2061: KbdPrint((
2062: 3,
2063: "KBDCLASS-KeyboardClassStartIo: new DataIn 0x%lx, DataOut 0x%lx\n",
2064: deviceExtension->DataIn,
2065: deviceExtension->DataOut
2066: ));
2067: KbdPrint((
2068: 3,
2069: "KBDCLASS-KeyboardClassStartIo: new InputCount %ld\n",
2070: deviceExtension->InputCount
2071: ));
2072:
2073: //
2074: // Clear the RequestIsPending flag to indicate this request is
2075: // not held pending.
2076: //
2077:
2078: deviceExtension->RequestIsPending = FALSE;
2079:
2080: //
2081: // Release the class input data queue spinlock.
2082: //
2083:
2084: KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
2085:
2086: //
2087: // Start the next packet, and complete this read request
2088: // with STATUS_SUCCESS.
2089: //
2090:
2091: Irp->IoStatus.Status = STATUS_SUCCESS;
2092: Irp->IoStatus.Information = bytesToMove;
2093: irpSp->Parameters.Read.Length = bytesToMove;
2094: IoStartNextPacket(DeviceObject, TRUE);
2095: IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
2096:
2097: } else {
2098:
2099: //
2100: // Set the RequestIsPending flag to indicate this request is
2101: // held pending for the callback routine to complete.
2102: //
2103:
2104: deviceExtension->RequestIsPending = TRUE;
2105:
2106: //
2107: // Hold the read request pending. It remains in the cancellable
2108: // state. When new input is received, the class service
2109: // callback routine will eventually complete the request. For now,
2110: // merely free the cancel spinlock and the class input data queue
2111: // spinlock.
2112: //
2113:
2114: IoReleaseCancelSpinLock(cancelIrql);
2115: KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
2116: }
2117:
2118: KbdPrint((2,"KBDCLASS-KeyboardClassStartIo: exit\n"));
2119:
2120: return;
2121:
2122: }
2123:
2124: VOID
2125: KeyboardClassUnload(
2126: IN PDRIVER_OBJECT DriverObject
2127: )
2128:
2129: /*++
2130:
2131: Routine Description:
2132:
2133: This routine is the class driver unload routine.
2134:
2135: NOTE: Not currently implemented.
2136:
2137: Arguments:
2138:
2139: DeviceObject - Pointer to class device object.
2140:
2141: Return Value:
2142:
2143: None.
2144:
2145: --*/
2146:
2147: {
2148: UNREFERENCED_PARAMETER(DriverObject);
2149:
2150: KbdPrint((2,"KBDCLASS-KeyboardClassUnload: enter\n"));
2151: KbdPrint((2,"KBDCLASS-KeyboardClassUnload: exit\n"));
2152:
2153: return;
2154: }
2155:
2156: VOID
2157: KbdConfiguration(
2158: IN PDEVICE_EXTENSION DeviceExtension,
2159: IN PUNICODE_STRING RegistryPath,
2160: IN PUNICODE_STRING DeviceName
2161: )
2162:
2163: /*++
2164:
2165: Routine Description:
2166:
2167: This routine stores the configuration information for this device.
2168:
2169: Arguments:
2170:
2171: DeviceExtension - Pointer to the device extension.
2172:
2173: RegistryPath - Pointer to the null-terminated Unicode name of the
2174: registry path for this driver.
2175:
2176: DeviceName - Pointer to the Unicode string that will receive
2177: the port device name.
2178:
2179: Return Value:
2180:
2181: None. As a side-effect, sets fields in
2182: DeviceExtension->KeyboardAttributes.
2183:
2184: --*/
2185:
2186: {
2187: PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
2188: UNICODE_STRING parametersPath;
2189: ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
2190: ULONG defaultMaximumPortsServiced = 1;
2191: ULONG defaultConnectMultiplePorts = 0;
2192: NTSTATUS status = STATUS_SUCCESS;
2193: UNICODE_STRING defaultUnicodeName;
2194: PWSTR path = NULL;
2195: USHORT queriesPlusOne = 5;
2196:
2197: parametersPath.Buffer = NULL;
2198:
2199: //
2200: // Registry path is already null-terminated, so just use it.
2201: //
2202:
2203: path = RegistryPath->Buffer;
2204:
2205: if (NT_SUCCESS(status)) {
2206:
2207: //
2208: // Allocate the Rtl query table.
2209: //
2210:
2211: parameters = ExAllocatePool(
2212: PagedPool,
2213: sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
2214: );
2215:
2216: if (!parameters) {
2217:
2218: KbdPrint((
2219: 1,
2220: "KBDCLASS-KbdConfiguration: Couldn't allocate table for Rtl query to parameters for %ws\n",
2221: path
2222: ));
2223:
2224: status = STATUS_UNSUCCESSFUL;
2225:
2226: } else {
2227:
2228: RtlZeroMemory(
2229: parameters,
2230: sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
2231: );
2232:
2233: //
2234: // Form a path to this driver's Parameters subkey.
2235: //
2236:
2237: RtlInitUnicodeString(
2238: ¶metersPath,
2239: NULL
2240: );
2241:
2242: parametersPath.MaximumLength = RegistryPath->Length +
2243: sizeof(L"\\Parameters");
2244:
2245: parametersPath.Buffer = ExAllocatePool(
2246: PagedPool,
2247: parametersPath.MaximumLength
2248: );
2249:
2250: if (!parametersPath.Buffer) {
2251:
2252: KbdPrint((
2253: 1,
2254: "KBDCLASS-KbdConfiguration: Couldn't allocate string for path to parameters for %ws\n",
2255: path
2256: ));
2257:
2258: status = STATUS_UNSUCCESSFUL;
2259:
2260: }
2261: }
2262: }
2263:
2264: if (NT_SUCCESS(status)) {
2265:
2266: //
2267: // Form the parameters path.
2268: //
2269:
2270: RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength);
2271: RtlAppendUnicodeToString(¶metersPath, path);
2272: RtlAppendUnicodeToString(¶metersPath, L"\\Parameters");
2273:
2274: KbdPrint((
2275: 1,
2276: "KBDCLASS-KbdConfiguration: parameters path is %ws\n",
2277: parametersPath.Buffer
2278: ));
2279:
2280: //
2281: // Form the default keyboard class device name, in case it is not
2282: // specified in the registry.
2283: //
2284:
2285: RtlInitUnicodeString(
2286: &defaultUnicodeName,
2287: DD_KEYBOARD_CLASS_BASE_NAME_U
2288: );
2289:
2290: //
2291: // Gather all of the "user specified" information from
2292: // the registry.
2293: //
2294:
2295: parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2296: parameters[0].Name = L"KeyboardDataQueueSize";
2297: parameters[0].EntryContext =
2298: &DeviceExtension->KeyboardAttributes.InputDataQueueLength;
2299: parameters[0].DefaultType = REG_DWORD;
2300: parameters[0].DefaultData = &defaultDataQueueSize;
2301: parameters[0].DefaultLength = sizeof(ULONG);
2302:
2303: parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2304: parameters[1].Name = L"MaximumPortsServiced";
2305: parameters[1].EntryContext =
2306: &DeviceExtension->MaximumPortsServiced;
2307: parameters[1].DefaultType = REG_DWORD;
2308: parameters[1].DefaultData = &defaultMaximumPortsServiced;
2309: parameters[1].DefaultLength = sizeof(ULONG);
2310:
2311: parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
2312: parameters[2].Name = L"KeyboardDeviceBaseName";
2313: parameters[2].EntryContext = DeviceName;
2314: parameters[2].DefaultType = REG_SZ;
2315: parameters[2].DefaultData = defaultUnicodeName.Buffer;
2316: parameters[2].DefaultLength = 0;
2317:
2318: parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
2319: parameters[3].Name = L"ConnectMultiplePorts";
2320: parameters[3].EntryContext =
2321: &DeviceExtension->ConnectOneClassToOnePort;
2322: parameters[3].DefaultType = REG_DWORD;
2323: parameters[3].DefaultData = &defaultConnectMultiplePorts;
2324: parameters[3].DefaultLength = sizeof(ULONG);
2325:
2326: status = RtlQueryRegistryValues(
2327: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
2328: parametersPath.Buffer,
2329: parameters,
2330: NULL,
2331: NULL
2332: );
2333:
2334: if (!NT_SUCCESS(status)) {
2335: KbdPrint((
2336: 1,
2337: "KBDCLASS-KbdConfiguration: RtlQueryRegistryValues failed with 0x%x\n",
2338: status
2339: ));
2340: }
2341: }
2342:
2343: if (!NT_SUCCESS(status)) {
2344:
2345: //
2346: // Go ahead and assign driver defaults.
2347: //
2348:
2349: DeviceExtension->KeyboardAttributes.InputDataQueueLength =
2350: defaultDataQueueSize;
2351: DeviceExtension->MaximumPortsServiced = defaultMaximumPortsServiced;
2352: DeviceExtension->ConnectOneClassToOnePort =
2353: !defaultConnectMultiplePorts;
2354: RtlCopyUnicodeString(DeviceName, &defaultUnicodeName);
2355: }
2356:
2357: KbdPrint((
2358: 1,
2359: "KBDCLASS-KbdConfiguration: Keyboard class base name = %ws\n",
2360: DeviceName->Buffer
2361: ));
2362:
2363: if (DeviceExtension->KeyboardAttributes.InputDataQueueLength == 0) {
2364:
2365: KbdPrint((
2366: 1,
2367: "KBDCLASS-KbdConfiguration: overriding KeyboardInputDataQueueLength = 0x%x\n",
2368: DeviceExtension->KeyboardAttributes.InputDataQueueLength
2369: ));
2370:
2371: DeviceExtension->KeyboardAttributes.InputDataQueueLength =
2372: defaultDataQueueSize;
2373: }
2374:
2375: DeviceExtension->KeyboardAttributes.InputDataQueueLength *=
2376: sizeof(KEYBOARD_INPUT_DATA);
2377:
2378: KbdPrint((
2379: 1,
2380: "KBDCLASS-KbdConfiguration: KeyboardInputDataQueueLength = 0x%x\n",
2381: DeviceExtension->KeyboardAttributes.InputDataQueueLength
2382: ));
2383:
2384: KbdPrint((
2385: 1,
2386: "KBDCLASS-KbdConfiguration: MaximumPortsServiced = %d\n",
2387: DeviceExtension->MaximumPortsServiced
2388: ));
2389:
2390: //
2391: // Invert the flag that specifies the type of class/port connections.
2392: // We used it in the RtlQuery call in an inverted fashion.
2393: //
2394:
2395: DeviceExtension->ConnectOneClassToOnePort =
2396: !DeviceExtension->ConnectOneClassToOnePort;
2397:
2398: KbdPrint((
2399: 1,
2400: "KBDCLASS-KbdConfiguration: Connection Type = %d\n",
2401: DeviceExtension->ConnectOneClassToOnePort
2402: ));
2403:
2404: //
2405: // Free the allocated memory before returning.
2406: //
2407:
2408: if (parametersPath.Buffer)
2409: ExFreePool(parametersPath.Buffer);
2410: if (parameters)
2411: ExFreePool(parameters);
2412:
2413: }
2414:
2415: NTSTATUS
2416: KbdConnectToPort(
2417: IN PDEVICE_OBJECT ClassDeviceObject,
2418: IN PUNICODE_STRING FullPortName,
2419: IN ULONG PortIndex
2420: )
2421:
2422: /*++
2423:
2424: Routine Description:
2425:
2426: This routine creates the keyboard class device object and connects
2427: to the port device.
2428:
2429:
2430: Arguments:
2431:
2432: ClassDeviceObject - Pointer to the device object for the class device.
2433:
2434: FullPortName - Pointer to the Unicode string that is the full path name
2435: for the port device object.
2436:
2437: PortIndex - The index into the PortDeviceObjectList[] for the
2438: current connection.
2439:
2440: Return Value:
2441:
2442: The function value is the final status from the operation.
2443:
2444: --*/
2445:
2446: {
2447: PDEVICE_EXTENSION deviceExtension = NULL;
2448: NTSTATUS status;
2449: PFILE_OBJECT fileObject = NULL;
2450: PDEVICE_OBJECT portDeviceObject = NULL;
2451: PIO_ERROR_LOG_PACKET errorLogEntry;
2452: ULONG uniqueErrorValue;
2453: NTSTATUS errorCode = STATUS_SUCCESS;
2454:
2455: KbdPrint((1,"\n\nKBDCLASS-KbdConnectToPort: enter\n"));
2456:
2457: //
2458: // Get a pointer to the port device object.
2459: //
2460:
2461: KbdPrint((
2462: 2,
2463: "KBDCLASS-KbdConnectToPort: Keyboard port name %ws\n",
2464: FullPortName->Buffer
2465: ));
2466:
2467: status = IoGetDeviceObjectPointer(
2468: FullPortName,
2469: FILE_READ_ATTRIBUTES,
2470: &fileObject,
2471: &portDeviceObject
2472: );
2473:
2474: if (status != STATUS_SUCCESS) {
2475: KbdPrint((
2476: 1,
2477: "KBDCLASS-KbdConnectToPort: Could not get port device object %ws\n",
2478: FullPortName->Buffer
2479: ));
2480:
2481: goto KbdConnectToPortExit;
2482: }
2483:
2484: deviceExtension =
2485: (PDEVICE_EXTENSION) ClassDeviceObject->DeviceExtension;
2486: deviceExtension->PortDeviceObjectList[PortIndex] = portDeviceObject;
2487:
2488: //
2489: // Set the IRP stack size (add 1 for the class layer).
2490: //
2491: // NOTE: This is a bit funky for 1:many connections (we end up setting
2492: // StackSize each time through this routine). Note also that
2493: // there is an assumption that the number of layers in the
2494: // class/port driver model is always the same (i.e., if there is
2495: // a layer between the class and the port driver for one device,
2496: // that is true for every device).
2497: //
2498:
2499: ClassDeviceObject->StackSize =
2500: (CCHAR) deviceExtension->PortDeviceObjectList[PortIndex]->StackSize + 1;
2501:
2502: //
2503: // Connect to port device.
2504: //
2505:
2506: status = KbdSendConnectRequest(
2507: ClassDeviceObject,
2508: (PVOID)KeyboardClassServiceCallback,
2509: PortIndex
2510: );
2511:
2512: if (status != STATUS_SUCCESS) {
2513: KbdPrint((
2514: 1,
2515: "KBDCLASS-KbdConnectToPort: Could not connect to port device %ws\n",
2516: FullPortName->Buffer
2517: ));
2518:
2519: //
2520: // Log an error.
2521: //
2522:
2523: errorCode = KBDCLASS_NO_PORT_CONNECT;
2524: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 30;
2525: goto KbdConnectToPortExit;
2526: }
2527:
2528: KbdConnectToPortExit:
2529:
2530: if (status != STATUS_SUCCESS) {
2531:
2532: //
2533: // Some part of the initialization failed. Log an error, and
2534: // clean up the resources for the failed part of the initialization.
2535: //
2536:
2537: if (errorCode != STATUS_SUCCESS) {
2538: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
2539: ClassDeviceObject,
2540: sizeof(IO_ERROR_LOG_PACKET)
2541: );
2542:
2543: if (errorLogEntry != NULL) {
2544:
2545: errorLogEntry->ErrorCode = errorCode;
2546: errorLogEntry->SequenceNumber = 0;
2547: errorLogEntry->MajorFunctionCode = 0;
2548: errorLogEntry->IoControlCode = 0;
2549: errorLogEntry->RetryCount = 0;
2550: errorLogEntry->UniqueErrorValue = uniqueErrorValue;
2551: errorLogEntry->FinalStatus = status;
2552:
2553: IoWriteErrorLogEntry(errorLogEntry);
2554: }
2555: }
2556:
2557: if (fileObject) {
2558: ObDereferenceObject(fileObject);
2559: }
2560:
2561: //
2562: // We count on the caller to free the ring buffer and delete
2563: // the class device object.
2564: //
2565: }
2566:
2567: KbdPrint((1,"KBDCLASS-KbdConnectToPort: exit\n"));
2568:
2569: return(status);
2570:
2571: }
2572:
2573: NTSTATUS
2574: KbdCreateClassObject(
2575: IN PDRIVER_OBJECT DriverObject,
2576: IN PDEVICE_EXTENSION TmpDeviceExtension,
2577: IN PUNICODE_STRING RegistryPath,
2578: IN PUNICODE_STRING FullDeviceName,
2579: IN PUNICODE_STRING BaseDeviceName,
2580: IN PDEVICE_OBJECT *ClassDeviceObject
2581: )
2582:
2583: /*++
2584:
2585: Routine Description:
2586:
2587: This routine creates the keyboard class device object.
2588:
2589:
2590: Arguments:
2591:
2592: DriverObject - Pointer to driver object created by system.
2593:
2594: TmpDeviceExtension - Pointer to the template device extension.
2595:
2596: RegistryPath - Pointer to the null-terminated Unicode name of the
2597: registry path for this driver.
2598:
2599: FullDeviceName - Pointer to the Unicode string that is the full path name
2600: for the class device object.
2601:
2602: BaseDeviceName - Pointer to the Unicode string that is the base path name
2603: for the class device.
2604:
2605: ClassDeviceObject - Pointer to a pointer to the class device object.
2606:
2607: Return Value:
2608:
2609: The function value is the final status from the operation.
2610:
2611: --*/
2612:
2613: {
2614: PDEVICE_EXTENSION deviceExtension = NULL;
2615: NTSTATUS status;
2616: PIO_ERROR_LOG_PACKET errorLogEntry;
2617: ULONG uniqueErrorValue;
2618: NTSTATUS errorCode = STATUS_SUCCESS;
2619:
2620: KbdPrint((1,"\n\nKBDCLASS-KbdCreateClassObject: enter\n"));
2621:
2622: //
2623: // Create a non-exclusive device object for the keyboard class device.
2624: //
2625:
2626: KbdPrint((
2627: 1,
2628: "KBDCLASS-KbdCreateClassObject: Creating device object named %ws\n",
2629: FullDeviceName->Buffer
2630: ));
2631:
2632: status = IoCreateDevice(
2633: DriverObject,
2634: sizeof(DEVICE_EXTENSION),
2635: FullDeviceName,
2636: FILE_DEVICE_KEYBOARD,
2637: 0,
2638: FALSE,
2639: ClassDeviceObject
2640: );
2641:
2642: if (!NT_SUCCESS(status)) {
2643: KbdPrint((
2644: 1,
2645: "KBDCLASS-KbdCreateClassObject: Could not create class device object = %ws\n",
2646: FullDeviceName->Buffer
2647: ));
2648: goto KbdCreateClassObjectExit;
2649:
2650: }
2651:
2652: //
2653: // Do buffered I/O. I.e., the I/O system will copy to/from user data
2654: // from/to a system buffer.
2655: //
2656:
2657: (*ClassDeviceObject)->Flags |= DO_BUFFERED_IO;
2658: deviceExtension =
2659: (PDEVICE_EXTENSION)(*ClassDeviceObject)->DeviceExtension;
2660: *deviceExtension = *TmpDeviceExtension;
2661:
2662: //
2663: // Initialize spin lock for critical sections.
2664: //
2665:
2666: KeInitializeSpinLock(&deviceExtension->SpinLock);
2667:
2668: //
2669: // Initialize keyboard class flags to indicate there is no outstanding
2670: // read request pending and cleanup has not been initiated.
2671: //
2672:
2673: deviceExtension->RequestIsPending = FALSE;
2674: deviceExtension->CleanupWasInitiated = FALSE;
2675:
2676: //
2677: // Allocate the ring buffer for the keyboard class input data.
2678: //
2679:
2680: deviceExtension->InputData =
2681: ExAllocatePool(
2682: NonPagedPool,
2683: deviceExtension->KeyboardAttributes.InputDataQueueLength
2684: );
2685:
2686: if (!deviceExtension->InputData) {
2687:
2688: //
2689: // Could not allocate memory for the keyboard class data queue.
2690: //
2691:
2692: KbdPrint((
2693: 1,
2694: "KBDCLASS-KbdCreateClassObject: Could not allocate input data queue for %ws\n",
2695: FullDeviceName->Buffer
2696: ));
2697:
2698: status = STATUS_INSUFFICIENT_RESOURCES;
2699:
2700: //
2701: // Log an error.
2702: //
2703:
2704: errorCode = KBDCLASS_NO_BUFFER_ALLOCATED;
2705: uniqueErrorValue = KEYBOARD_ERROR_VALUE_BASE + 20;
2706: goto KbdCreateClassObjectExit;
2707: }
2708:
2709: //
2710: // Initialize keyboard class input data queue.
2711: //
2712:
2713: KbdInitializeDataQueue((PVOID)deviceExtension);
2714:
2715: KbdCreateClassObjectExit:
2716:
2717: if (status != STATUS_SUCCESS) {
2718:
2719: //
2720: // Some part of the initialization failed. Log an error, and
2721: // clean up the resources for the failed part of the initialization.
2722: //
2723:
2724: if (errorCode != STATUS_SUCCESS) {
2725: errorLogEntry = (PIO_ERROR_LOG_PACKET)
2726: IoAllocateErrorLogEntry(
2727: (*ClassDeviceObject == NULL) ?
2728: (PVOID) DriverObject : (PVOID) *ClassDeviceObject,
2729: sizeof(IO_ERROR_LOG_PACKET)
2730: );
2731:
2732: if (errorLogEntry != NULL) {
2733:
2734: errorLogEntry->ErrorCode = errorCode;
2735: errorLogEntry->SequenceNumber = 0;
2736: errorLogEntry->MajorFunctionCode = 0;
2737: errorLogEntry->IoControlCode = 0;
2738: errorLogEntry->RetryCount = 0;
2739: errorLogEntry->UniqueErrorValue = uniqueErrorValue;
2740: errorLogEntry->FinalStatus = status;
2741:
2742: IoWriteErrorLogEntry(errorLogEntry);
2743: }
2744: }
2745:
2746: if ((deviceExtension) && (deviceExtension->InputData))
2747: ExFreePool(deviceExtension->InputData);
2748: if (*ClassDeviceObject) {
2749: IoDeleteDevice(*ClassDeviceObject);
2750: *ClassDeviceObject = NULL;
2751: }
2752: }
2753:
2754: KbdPrint((1,"KBDCLASS-KbdCreateClassObject: exit\n"));
2755:
2756: return(status);
2757:
2758: }
2759:
2760: #if DBG
2761: VOID
2762: KbdDebugPrint(
2763: ULONG DebugPrintLevel,
2764: PCCHAR DebugMessage,
2765: ...
2766: )
2767:
2768: /*++
2769:
2770: Routine Description:
2771:
2772: Debug print routine.
2773:
2774: Arguments:
2775:
2776: Debug print level between 0 and 3, with 3 being the most verbose.
2777:
2778: Return Value:
2779:
2780: None.
2781:
2782: --*/
2783:
2784: {
2785: va_list ap;
2786:
2787: va_start(ap, DebugMessage);
2788:
2789: if (DebugPrintLevel <= KeyboardDebug) {
2790:
2791: char buffer[256];
2792:
2793: (VOID) vsprintf(buffer, DebugMessage, ap);
2794:
2795: DbgPrint(buffer);
2796: }
2797:
2798: va_end(ap);
2799:
2800: }
2801: #endif
2802:
2803: NTSTATUS
2804: KbdDeterminePortsServiced(
2805: IN PUNICODE_STRING BasePortName,
2806: IN OUT PULONG NumberPortsServiced
2807: )
2808:
2809: /*++
2810:
2811: Routine Description:
2812:
2813: This routine reads the DEVICEMAP portion of the registry to determine
2814: how many ports the class driver is to service. Depending on the
2815: value of DeviceExtension->ConnectOneClassToOnePort, the class driver
2816: will eventually create one device object per port device serviced, or
2817: one class device object that connects to multiple port device objects.
2818:
2819: Assumptions:
2820:
2821: 1. If the base device name for the class driver is "KeyboardClass",
2822: ^^^^^
2823: then the port drivers it can service are found under the
2824: "KeyboardPort" subkey in the DEVICEMAP portion of the registry.
2825: ^^^^
2826:
2827: 2. The port device objects are created with suffixes in strictly
2828: ascending order, starting with suffix 0. E.g.,
2829: \Device\KeyboardPort0 indicates the first keyboard port device,
2830: \Device\KeyboardPort1 the second, and so on. There are no gaps
2831: in the list.
2832:
2833: 3. If ConnectOneClassToOnePort is non-zero, there is a 1:1
2834: correspondence between class device objects and port device
2835: objects. I.e., \Device\KeyboardClass0 will connect to
2836: \Device\KeyboardPort0, \Device\KeyboardClass1 to
2837: \Device\KeyboardPort1, and so on.
2838:
2839: 4. If ConnectOneClassToOnePort is zero, there is a 1:many
2840: correspondence between class device objects and port device
2841: objects. I.e., \Device\KeyboardClass0 will connect to
2842: \Device\KeyboardPort0, and \Device\KeyboardPort1, and so on.
2843:
2844:
2845: Note that for Product 1, the Raw Input Thread (Windows USER) will
2846: only deign to open and read from one keyboard device. Hence, it is
2847: safe to make simplifying assumptions because the driver is basically
2848: providing much more functionality than the RIT will use.
2849:
2850: Arguments:
2851:
2852: BasePortName - Pointer to the Unicode string that is the base path name
2853: for the port device.
2854:
2855: NumberPortsServiced - Pointer to storage that will receive the
2856: number of ports this class driver should service.
2857:
2858: Return Value:
2859:
2860: The function value is the final status from the operation.
2861:
2862: --*/
2863:
2864: {
2865:
2866: NTSTATUS status;
2867: PRTL_QUERY_REGISTRY_TABLE registryTable = NULL;
2868: USHORT queriesPlusOne = 2;
2869:
2870: //
2871: // Initialize the result.
2872: //
2873:
2874: *NumberPortsServiced = 0;
2875:
2876: //
2877: // Allocate the Rtl query table.
2878: //
2879:
2880: registryTable = ExAllocatePool(
2881: PagedPool,
2882: sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
2883: );
2884:
2885: if (!registryTable) {
2886:
2887: KbdPrint((
2888: 1,
2889: "KBDCLASS-KbdDeterminePortsServiced: Couldn't allocate table for Rtl query\n"
2890: ));
2891:
2892: status = STATUS_UNSUCCESSFUL;
2893:
2894: } else {
2895:
2896: RtlZeroMemory(
2897: registryTable,
2898: sizeof(RTL_QUERY_REGISTRY_TABLE) * queriesPlusOne
2899: );
2900:
2901: //
2902: // Set things up so that KbdDeviceMapQueryCallback will be
2903: // called once for every value in the keyboard port section
2904: // of the registry's hardware devicemap.
2905: //
2906:
2907: registryTable[0].QueryRoutine = KbdDeviceMapQueryCallback;
2908: registryTable[0].Name = NULL;
2909:
2910: status = RtlQueryRegistryValues(
2911: RTL_REGISTRY_DEVICEMAP | RTL_REGISTRY_OPTIONAL,
2912: BasePortName->Buffer,
2913: registryTable,
2914: NumberPortsServiced,
2915: NULL
2916: );
2917:
2918: if (!NT_SUCCESS(status)) {
2919: KbdPrint((
2920: 1,
2921: "KBDCLASS-KbdDeterminePortsServiced: RtlQueryRegistryValues failed with 0x%x\n",
2922: status
2923: ));
2924: }
2925:
2926: ExFreePool(registryTable);
2927: }
2928:
2929: return(status);
2930: }
2931:
2932: NTSTATUS
2933: KbdDeviceMapQueryCallback(
2934: IN PWSTR ValueName,
2935: IN ULONG ValueType,
2936: IN PVOID ValueData,
2937: IN ULONG ValueLength,
2938: IN PVOID Context,
2939: IN PVOID EntryContext
2940: )
2941:
2942: /*++
2943:
2944: Routine Description:
2945:
2946: This is the callout routine specified in a call to
2947: RtlQueryRegistryValues. It increments the value pointed
2948: to by the Context parameter.
2949:
2950: Arguments:
2951:
2952: ValueName - Unused.
2953:
2954: ValueType - Unused.
2955:
2956: ValueData - Unused.
2957:
2958: ValueLength - Unused.
2959:
2960: Context - Pointer to a count of the number of times this
2961: routine has been called. This is the number of ports
2962: the class driver needs to service.
2963:
2964: EntryContext - Unused.
2965:
2966: Return Value:
2967:
2968: The function value is the final status from the operation.
2969:
2970: --*/
2971:
2972: {
2973: *(PULONG)Context += 1;
2974:
2975: return(STATUS_SUCCESS);
2976: }
2977:
2978: NTSTATUS
2979: KbdEnableDisablePort(
2980: IN PDEVICE_OBJECT DeviceObject,
2981: IN BOOLEAN EnableFlag,
2982: IN ULONG PortIndex
2983: )
2984:
2985: /*++
2986:
2987: Routine Description:
2988:
2989: This routine sends an enable or a disable request to the port driver.
2990:
2991: Arguments:
2992:
2993: DeviceObject - Pointer to class device object.
2994:
2995: EnableFlag - If TRUE, send an ENABLE request; otherwise, send DISABLE.
2996:
2997: PortIndex - Index into the PortDeviceObjectList[] for the current
2998: enable/disable request.
2999:
3000: Return Value:
3001:
3002: Status is returned.
3003:
3004: --*/
3005:
3006: {
3007: PIRP irp;
3008: IO_STATUS_BLOCK ioStatus;
3009: NTSTATUS status;
3010: KEVENT event;
3011: PDEVICE_EXTENSION deviceExtension;
3012:
3013: KbdPrint((2,"KBDCLASS-KbdEnableDisablePort: enter\n"));
3014:
3015: //
3016: // Get a pointer to the device extension.
3017: //
3018:
3019: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
3020:
3021: //
3022: // Create notification event object to be used to signal the
3023: // request completion.
3024: //
3025:
3026: KeInitializeEvent(&event, NotificationEvent, FALSE);
3027:
3028: //
3029: // Build the synchronous request to be sent to the port driver
3030: // to perform the request. Allocate an IRP to issue the port internal
3031: // device control Enable/Disable call.
3032: //
3033:
3034: irp = IoBuildDeviceIoControlRequest(
3035: EnableFlag? IOCTL_INTERNAL_KEYBOARD_ENABLE:
3036: IOCTL_INTERNAL_KEYBOARD_DISABLE,
3037: deviceExtension->PortDeviceObjectList[PortIndex],
3038: NULL,
3039: 0,
3040: NULL,
3041: 0,
3042: TRUE,
3043: &event,
3044: &ioStatus
3045: );
3046:
3047: //
3048: // Call the port driver to perform the operation. If the returned status
3049: // is PENDING, wait for the request to complete.
3050: //
3051:
3052: status = IoCallDriver(
3053: deviceExtension->PortDeviceObjectList[PortIndex],
3054: irp
3055: );
3056:
3057: if (status == STATUS_PENDING) {
3058: (VOID) KeWaitForSingleObject(
3059: &event,
3060: Suspended,
3061: KernelMode,
3062: FALSE,
3063: NULL
3064: );
3065: } else {
3066:
3067: //
3068: // Ensure that the proper status value gets picked up.
3069: //
3070:
3071: ioStatus.Status = status;
3072: }
3073:
3074: KbdPrint((2,"KBDCLASS-KbdEnableDisablePort: exit\n"));
3075:
3076: return(ioStatus.Status);
3077:
3078: }
3079:
3080: VOID
3081: KbdInitializeDataQueue (
3082: IN PVOID Context
3083: )
3084:
3085: /*++
3086:
3087: Routine Description:
3088:
3089: This routine initializes the input data queue. IRQL is raised to
3090: DISPATCH_LEVEL to synchronize with StartIo, and the device object
3091: spinlock is acquired.
3092:
3093: Arguments:
3094:
3095: Context - Supplies a pointer to the device extension.
3096:
3097: Return Value:
3098:
3099: None.
3100:
3101: --*/
3102:
3103: {
3104:
3105: KIRQL oldIrql;
3106: PDEVICE_EXTENSION deviceExtension;
3107:
3108: KbdPrint((3,"KBDCLASS-KbdInitializeDataQueue: enter\n"));
3109:
3110: //
3111: // Get address of device extension.
3112: //
3113:
3114: deviceExtension = (PDEVICE_EXTENSION)Context;
3115:
3116: //
3117: // Acquire the spinlock to protect the input data
3118: // queue and associated pointers.
3119: //
3120:
3121: KeAcquireSpinLock(&deviceExtension->SpinLock, &oldIrql);
3122:
3123: //
3124: // Initialize the input data queue.
3125: //
3126:
3127: deviceExtension->InputCount = 0;
3128: deviceExtension->DataIn = deviceExtension->InputData;
3129: deviceExtension->DataOut = deviceExtension->InputData;
3130:
3131: deviceExtension->OkayToLogOverflow = TRUE;
3132:
3133: //
3134: // Release the spinlock and lower IRQL.
3135: //
3136:
3137: KeReleaseSpinLock(&deviceExtension->SpinLock, oldIrql);
3138:
3139: KbdPrint((3,"KBDCLASS-KbdInitializeDataQueue: exit\n"));
3140:
3141: }
3142:
3143: NTSTATUS
3144: KbdSendConnectRequest(
3145: IN PDEVICE_OBJECT DeviceObject,
3146: IN PVOID ServiceCallback,
3147: IN ULONG PortIndex
3148: )
3149:
3150: /*++
3151:
3152: Routine Description:
3153:
3154: This routine sends a connect request to the port driver.
3155:
3156: Arguments:
3157:
3158: DeviceObject - Pointer to class device object.
3159:
3160: ServiceCallback - Pointer to the class service callback routine.
3161:
3162: PortIndex - The index into the PortDeviceObjectList[] for the current
3163: connect request.
3164:
3165: Return Value:
3166:
3167: Status is returned.
3168:
3169: --*/
3170:
3171: {
3172: PIRP irp;
3173: IO_STATUS_BLOCK ioStatus;
3174: NTSTATUS status;
3175: KEVENT event;
3176: PDEVICE_EXTENSION deviceExtension;
3177: CONNECT_DATA connectData;
3178:
3179: KbdPrint((2,"KBDCLASS-KbdSendConnectRequest: enter\n"));
3180:
3181: //
3182: // Get a pointer to the device extension.
3183: //
3184:
3185: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
3186:
3187: //
3188: // Create notification event object to be used to signal the
3189: // request completion.
3190: //
3191:
3192: KeInitializeEvent(&event, NotificationEvent, FALSE);
3193:
3194: //
3195: // Build the synchronous request to be sent to the port driver
3196: // to perform the request. Allocate an IRP to issue the port internal
3197: // device control connect call. The connect parameters are passed in
3198: // the input buffer, and the keyboard attributes are copied back
3199: // from the port driver directly into the class device extension.
3200: //
3201:
3202: connectData.ClassDeviceObject = DeviceObject;
3203: connectData.ClassService = ServiceCallback;
3204:
3205: irp = IoBuildDeviceIoControlRequest(
3206: IOCTL_INTERNAL_KEYBOARD_CONNECT,
3207: deviceExtension->PortDeviceObjectList[PortIndex],
3208: &connectData,
3209: sizeof(CONNECT_DATA),
3210: NULL,
3211: 0,
3212: TRUE,
3213: &event,
3214: &ioStatus
3215: );
3216:
3217: //
3218: // Call the port driver to perform the operation. If the returned status
3219: // is PENDING, wait for the request to complete.
3220: //
3221:
3222: status = IoCallDriver(
3223: deviceExtension->PortDeviceObjectList[PortIndex],
3224: irp
3225: );
3226:
3227: if (status == STATUS_PENDING) {
3228: (VOID) KeWaitForSingleObject(
3229: &event,
3230: Suspended,
3231: KernelMode,
3232: FALSE,
3233: NULL
3234: );
3235: } else {
3236:
3237: //
3238: // Ensure that the proper status value gets picked up.
3239: //
3240:
3241: ioStatus.Status = status;
3242: }
3243:
3244: KbdPrint((2,"KBDCLASS-KbdSendConnectRequest: exit\n"));
3245:
3246: return(ioStatus.Status);
3247:
3248: } // end KbdSendConnectRequest()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.