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