|
|
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.