|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: initunlo.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains the code that is very specific to initialization ! 12: and unloading of the parallel driver. ! 13: ! 14: Author: ! 15: ! 16: Anthony V. Ercolano 1-Aug-1992 ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode ! 21: ! 22: Revision History : ! 23: ! 24: --*/ ! 25: ! 26: #include <stddef.h> ! 27: #include "ntddk.h" ! 28: #include "par.h" ! 29: #include "parlog.h" ! 30: ! 31: ! 32: // ! 33: // This is the actual definition of ParDebugLevel. ! 34: // Note that it is only defined if this is a "debug" ! 35: // build. ! 36: // ! 37: #if DBG ! 38: extern ULONG ParDebugLevel = 0; ! 39: #endif ! 40: ! 41: // ! 42: // Give a timeout of 300 seconds. Some postscript printers will ! 43: // buffer up a lot of commands then proceed to render what they ! 44: // have. The printer will then refuse to accept any characters ! 45: // until it's done with the rendering. This render process can ! 46: // take a while. We'll give it 300 seconds. ! 47: // ! 48: // Note that an application can change this value. ! 49: // ! 50: #define PAR_WRITE_TIMEOUT_VALUE 300 ! 51: ! 52: static const PHYSICAL_ADDRESS ParPhysicalZero = {0}; ! 53: ! 54: NTSTATUS ! 55: DriverEntry( ! 56: IN PDRIVER_OBJECT DriverObject, ! 57: IN PUNICODE_STRING RegistryPath ! 58: ); ! 59: ! 60: NTSTATUS ! 61: ParInitializeController( ! 62: IN PDRIVER_OBJECT DriverObject, ! 63: IN PCONFIG_DATA ConfigData ! 64: ); ! 65: ! 66: NTSTATUS ! 67: ParItemCallBack( ! 68: IN PVOID Context, ! 69: IN PUNICODE_STRING PathName, ! 70: IN INTERFACE_TYPE BusType, ! 71: IN ULONG BusNumber, ! 72: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 73: IN CONFIGURATION_TYPE ControllerType, ! 74: IN ULONG ControllerNumber, ! 75: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 76: IN CONFIGURATION_TYPE PeripheralType, ! 77: IN ULONG PeripheralNumber, ! 78: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 79: ); ! 80: ! 81: NTSTATUS ! 82: ParConfigCallBack( ! 83: IN PVOID Context, ! 84: IN PUNICODE_STRING PathName, ! 85: IN INTERFACE_TYPE BusType, ! 86: IN ULONG BusNumber, ! 87: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 88: IN CONFIGURATION_TYPE ControllerType, ! 89: IN ULONG ControllerNumber, ! 90: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 91: IN CONFIGURATION_TYPE PeripheralType, ! 92: IN ULONG PeripheralNumber, ! 93: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 94: ); ! 95: ! 96: VOID ! 97: ParGetConfigInfo( ! 98: IN PDRIVER_OBJECT DriverObject, ! 99: IN PUNICODE_STRING RegistryPath, ! 100: OUT PLIST_ENTRY ConfigList ! 101: ); ! 102: ! 103: BOOLEAN ! 104: ParPutInConfigList( ! 105: IN PDRIVER_OBJECT DriverObject, ! 106: IN OUT PLIST_ENTRY ConfigList, ! 107: IN PCONFIG_DATA New ! 108: ); ! 109: ! 110: PVOID ! 111: ParGetMappedAddress( ! 112: IN INTERFACE_TYPE BusType, ! 113: IN ULONG BusNumber, ! 114: PHYSICAL_ADDRESS IoAddress, ! 115: ULONG NumberOfBytes, ! 116: ULONG AddressSpace, ! 117: PBOOLEAN MappedAddress ! 118: ); ! 119: ! 120: VOID ! 121: ParSetupExternalNaming( ! 122: IN PPAR_DEVICE_EXTENSION Extension ! 123: ); ! 124: ! 125: VOID ! 126: ParCleanupDevice( ! 127: IN PPAR_DEVICE_EXTENSION Extension ! 128: ); ! 129: ! 130: VOID ! 131: ParCleanupExternalNaming( ! 132: IN PPAR_DEVICE_EXTENSION Extension ! 133: ); ! 134: ! 135: typedef enum _PAR_MEM_COMPARES { ! 136: AddressesAreEqual, ! 137: AddressesOverlap, ! 138: AddressesAreDisjoint ! 139: } PAR_MEM_COMPARES,*PPAR_MEM_COMPARES; ! 140: ! 141: PAR_MEM_COMPARES ! 142: ParMemCompare( ! 143: IN PHYSICAL_ADDRESS A, ! 144: IN ULONG SpanOfA, ! 145: IN PHYSICAL_ADDRESS B, ! 146: IN ULONG SpanOfB ! 147: ); ! 148: ! 149: ! 150: VOID ! 151: ParUnReportResourcesDevice( ! 152: IN PPAR_DEVICE_EXTENSION Extension ! 153: ); ! 154: ! 155: VOID ! 156: ParReportResourcesDevice( ! 157: IN PPAR_DEVICE_EXTENSION Extension, ! 158: IN BOOLEAN ClaimInterrupt, ! 159: OUT BOOLEAN *ConflictDetected ! 160: ); ! 161: ! 162: #ifdef ALLOC_PRAGMA ! 163: #pragma alloc_text(init,DriverEntry) ! 164: #pragma alloc_text(init,ParInitializeController) ! 165: #pragma alloc_text(init,ParItemCallBack) ! 166: #pragma alloc_text(init,ParConfigCallBack) ! 167: #pragma alloc_text(init,ParGetConfigInfo) ! 168: #pragma alloc_text(init,ParPutInConfigList) ! 169: #pragma alloc_text(init,ParGetMappedAddress) ! 170: #pragma alloc_text(init,ParSetupExternalNaming) ! 171: #pragma alloc_text(init,ParReportResourcesDevice) ! 172: #endif ! 173: ! 174: NTSTATUS ! 175: DriverEntry( ! 176: IN PDRIVER_OBJECT DriverObject, ! 177: IN PUNICODE_STRING RegistryPath ! 178: ) ! 179: ! 180: /*++ ! 181: ! 182: Routine Description: ! 183: ! 184: The entry point that the system point calls to initialize ! 185: any driver. ! 186: ! 187: This path will gather the configuration information, ! 188: attempt to initialize all driver data structures, ! 189: connect to interrupts for ports. If the above ! 190: goes reasonably well it will fill in the dispatch points, ! 191: reset the parallel devices and then return to the system. ! 192: ! 193: Arguments: ! 194: ! 195: DriverObject - Just what it says, really of little use ! 196: to the driver itself, it is something that the IO system ! 197: cares more about. ! 198: ! 199: PathToRegistry - points to the entry for this driver ! 200: in the current control set of the registry. ! 201: ! 202: Return Value: ! 203: ! 204: STATUS_SUCCESS if we could initialize a single device, ! 205: otherwise STATUS_NO_SUCH_DEVICE. ! 206: ! 207: --*/ ! 208: ! 209: { ! 210: ! 211: // ! 212: // Holds status information return by various OS and driver ! 213: // initialization routines. ! 214: // ! 215: NTSTATUS status; ! 216: ! 217: // ! 218: // List head for configuration records. ! 219: // ! 220: LIST_ENTRY configList; ! 221: ! 222: // ! 223: // Pointer to a device object in the device object chain ! 224: // hanging off of the driver object. ! 225: // ! 226: PDEVICE_OBJECT currentDevice; ! 227: ! 228: // ! 229: // We use this to query into the registry as to whether we ! 230: // should break at driver entry. ! 231: // ! 232: RTL_QUERY_REGISTRY_TABLE paramTable[3]; ! 233: ULONG zero = 0; ! 234: ULONG debugLevel = 0; ! 235: ULONG shouldBreak = 0; ! 236: PWCHAR path; ! 237: ! 238: // ! 239: // Since the registry path parameter is a "counted" UNICODE string, it ! 240: // might not be zero terminated. For a very short time allocate memory ! 241: // to hold the registry path zero terminated so that we can use it to ! 242: // delve into the registry. ! 243: // ! 244: // NOTE NOTE!!!! This is not an architected way of breaking into ! 245: // a driver. It happens to work for this driver because the author ! 246: // likes to do things this way. ! 247: // ! 248: ! 249: if (path = ExAllocatePool( ! 250: PagedPool, ! 251: RegistryPath->Length+sizeof(WCHAR) ! 252: )) { ! 253: ! 254: RtlZeroMemory( ! 255: ¶mTable[0], ! 256: sizeof(paramTable) ! 257: ); ! 258: RtlZeroMemory( ! 259: path, ! 260: RegistryPath->Length+sizeof(WCHAR) ! 261: ); ! 262: RtlMoveMemory( ! 263: path, ! 264: RegistryPath->Buffer, ! 265: RegistryPath->Length ! 266: ); ! 267: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 268: paramTable[0].Name = L"BreakOnEntry"; ! 269: paramTable[0].EntryContext = &shouldBreak; ! 270: paramTable[0].DefaultType = REG_DWORD; ! 271: paramTable[0].DefaultData = &zero; ! 272: paramTable[0].DefaultLength = sizeof(ULONG); ! 273: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 274: paramTable[1].Name = L"DebugLevel"; ! 275: paramTable[1].EntryContext = &debugLevel; ! 276: paramTable[1].DefaultType = REG_DWORD; ! 277: paramTable[1].DefaultData = &zero; ! 278: paramTable[1].DefaultLength = sizeof(ULONG); ! 279: ! 280: if (!NT_SUCCESS(RtlQueryRegistryValues( ! 281: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, ! 282: path, ! 283: ¶mTable[0], ! 284: NULL, ! 285: NULL ! 286: ))) { ! 287: ! 288: shouldBreak = 0; ! 289: debugLevel = 0; ! 290: ! 291: } ! 292: ! 293: } ! 294: ! 295: // ! 296: // We don't need that path anymore. ! 297: // ! 298: ! 299: if (path) { ! 300: ! 301: ExFreePool(path); ! 302: ! 303: } ! 304: ! 305: #if DBG ! 306: ParDebugLevel = debugLevel; ! 307: #endif ! 308: ! 309: if (shouldBreak) { ! 310: ! 311: DbgBreakPoint(); ! 312: ! 313: } ! 314: ! 315: ParGetConfigInfo( ! 316: DriverObject, ! 317: RegistryPath, ! 318: &configList ! 319: ); ! 320: ! 321: // ! 322: // Initialize each item in the list of configuration records. ! 323: // ! 324: ! 325: while (!IsListEmpty(&configList)) { ! 326: ! 327: PCONFIG_DATA currentConfig; ! 328: PLIST_ENTRY head; ! 329: ! 330: head = RemoveHeadList(&configList); ! 331: ! 332: currentConfig = CONTAINING_RECORD( ! 333: head, ! 334: CONFIG_DATA, ! 335: ConfigList ! 336: ); ! 337: ! 338: ParInitializeController( ! 339: DriverObject, ! 340: currentConfig ! 341: ); ! 342: ! 343: } ! 344: ! 345: // ! 346: // We've initialized all of the hardware that this driver ! 347: // will ever know about. All of the hardware that we know ! 348: // about is set up to NOT interrupt. We now go through ! 349: // all of the devices and connect an interrupt object for ! 350: // all. ! 351: // ! 352: ! 353: currentDevice = DriverObject->DeviceObject; ! 354: ! 355: while (currentDevice) { ! 356: ! 357: PPAR_DEVICE_EXTENSION extension = currentDevice->DeviceExtension; ! 358: ! 359: if (!extension->UsingATimer) { ! 360: ! 361: status = IoConnectInterrupt( ! 362: &extension->Interrupt, ! 363: ParInterruptServiceRoutine, ! 364: extension->DeviceObject, ! 365: NULL, ! 366: extension->Vector, ! 367: extension->Irql, ! 368: extension->Irql, ! 369: extension->InterruptMode, ! 370: extension->InterruptShareable, ! 371: extension->ProcessorAffinity, ! 372: FALSE ! 373: ); ! 374: ! 375: if (!NT_SUCCESS(status)) { ! 376: ! 377: BOOLEAN junk; ! 378: ! 379: // ! 380: // Hmmm. Must be a BAD driver out there that isn't claiming ! 381: // its resources. Just switch this device to running off ! 382: // the timer. Also, switch the resources to be just the ! 383: // port. ! 384: // ! 385: ! 386: ParLogError( ! 387: extension->DeviceObject->DriverObject, ! 388: extension->DeviceObject, ! 389: extension->OriginalController, ! 390: ParPhysicalZero, ! 391: 0, ! 392: 0, ! 393: 0, ! 394: 1, ! 395: status, ! 396: PAR_UNREPORTED_IRQL_CONFLICT ! 397: ); ! 398: ParReportResourcesDevice( ! 399: extension, ! 400: FALSE, ! 401: &junk ! 402: ); ! 403: extension->UsingATimer = TRUE; ! 404: ! 405: } ! 406: ! 407: } ! 408: ! 409: currentDevice = currentDevice->NextDevice; ! 410: ! 411: } ! 412: ! 413: // ! 414: // We've connected up to the interrupt for everything. Now ! 415: // we initialize the device. (This could cause an interrupt.) ! 416: // ! 417: ! 418: currentDevice = DriverObject->DeviceObject; ! 419: ! 420: while (currentDevice) { ! 421: ! 422: IoStartTimer(currentDevice); ! 423: ParSynchronizeExecution( ! 424: currentDevice->DeviceExtension, ! 425: ParInitializeDevice, ! 426: currentDevice->DeviceExtension ! 427: ); ! 428: currentDevice = currentDevice->NextDevice; ! 429: ! 430: } ! 431: ! 432: if (DriverObject->DeviceObject) { ! 433: ! 434: status = STATUS_SUCCESS; ! 435: ! 436: // ! 437: // Initialize the Driver Object with driver's entry points ! 438: // ! 439: ! 440: DriverObject->DriverStartIo = ParStartIo; ! 441: DriverObject->MajorFunction[IRP_MJ_WRITE] = ParDispatch; ! 442: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ParDispatch; ! 443: DriverObject->MajorFunction[IRP_MJ_CREATE] = ParDispatch; ! 444: DriverObject->MajorFunction[IRP_MJ_CLOSE] = ParDispatch; ! 445: DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = ! 446: ParQueryInformationFile; ! 447: DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = ! 448: ParSetInformationFile; ! 449: DriverObject->DriverUnload = ParUnload; ! 450: ! 451: } else { ! 452: ! 453: status = STATUS_NO_SUCH_DEVICE; ! 454: ! 455: } ! 456: ! 457: return status; ! 458: } ! 459: ! 460: NTSTATUS ! 461: ParInitializeController( ! 462: IN PDRIVER_OBJECT DriverObject, ! 463: IN PCONFIG_DATA ConfigData ! 464: ) ! 465: ! 466: /*++ ! 467: ! 468: Routine Description: ! 469: ! 470: Really too many things to mention here. In general, it forms ! 471: and sets up names, creates the device, translates bus relative ! 472: items... ! 473: ! 474: ! 475: Arguments: ! 476: ! 477: DriverObject - Just used to create the device object. ! 478: ! 479: ConfigData - Pointer to a record for a single port. ! 480: ! 481: NOTE: This routine will deallocate the config data. ! 482: ! 483: Return Value: ! 484: ! 485: STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status ! 486: otherwise. ! 487: ! 488: --*/ ! 489: ! 490: { ! 491: ! 492: // ! 493: // This will hold the string that we need to use to describe ! 494: // the name of the device to the IO system. ! 495: // ! 496: UNICODE_STRING uniNameString; ! 497: ! 498: // ! 499: // Holds the NT Status that is returned from each call to the ! 500: // kernel and executive. ! 501: // ! 502: NTSTATUS status = STATUS_SUCCESS; ! 503: ! 504: // ! 505: // Points to the device object (not the extension) created ! 506: // for this device. ! 507: // ! 508: PDEVICE_OBJECT deviceObject; ! 509: ! 510: // ! 511: // Points to the device extension for the device object ! 512: // (see above) created for the device we are initializing. ! 513: // ! 514: PPAR_DEVICE_EXTENSION extension = NULL; ! 515: ! 516: // ! 517: // Passed back from the resource reporting code to indicate ! 518: // whether the requested resources are already being used by ! 519: // another device. ! 520: // ! 521: BOOLEAN conflict; ! 522: ! 523: ! 524: ParDump( ! 525: PARCONFIG, ! 526: ("PARALLEL: Initializing for configuration record of %wZ\n", ! 527: &ConfigData->NtNameForPort) ! 528: ); ! 529: ! 530: // ! 531: // Form a name like \Device\Parallel0. ! 532: // ! 533: // First we allocate space for the name. ! 534: // ! 535: ! 536: RtlInitUnicodeString( ! 537: &uniNameString, ! 538: NULL ! 539: ); ! 540: ! 541: uniNameString.MaximumLength = sizeof(L"\\Device\\") + ! 542: ConfigData->NtNameForPort.Length+sizeof(WCHAR); ! 543: uniNameString.Buffer = ExAllocatePool( ! 544: PagedPool, ! 545: uniNameString.MaximumLength ! 546: ); ! 547: ! 548: // ! 549: // The only reason the above could have failed is if ! 550: // there wasn't enough system memory to form the UNICODE ! 551: // string. ! 552: // ! 553: ! 554: if (!uniNameString.Buffer) { ! 555: ! 556: ParLogError( ! 557: DriverObject, ! 558: NULL, ! 559: ConfigData->Controller, ! 560: ParPhysicalZero, ! 561: 0, ! 562: 0, ! 563: 0, ! 564: 2, ! 565: STATUS_SUCCESS, ! 566: PAR_INSUFFICIENT_RESOURCES ! 567: ); ! 568: ParDump( ! 569: PARERRORS, ! 570: ("PARALLEL: Could not form Unicode name string for %wZ\n", ! 571: &ConfigData->NtNameForPort) ! 572: ); ! 573: ExFreePool(ConfigData->ObjectDirectory.Buffer); ! 574: ExFreePool(ConfigData->NtNameForPort.Buffer); ! 575: ExFreePool(ConfigData->SymbolicLinkName.Buffer); ! 576: ExFreePool(ConfigData); ! 577: return STATUS_INSUFFICIENT_RESOURCES; ! 578: ! 579: } ! 580: ! 581: // ! 582: // Actually form the Name. ! 583: // ! 584: ! 585: RtlZeroMemory( ! 586: uniNameString.Buffer, ! 587: uniNameString.MaximumLength ! 588: ); ! 589: ! 590: RtlAppendUnicodeToString( ! 591: &uniNameString, ! 592: L"\\Device\\" ! 593: ); ! 594: ! 595: RtlAppendUnicodeStringToString( ! 596: &uniNameString, ! 597: &ConfigData->NtNameForPort ! 598: ); ! 599: ! 600: // ! 601: // Create the device object for this device. ! 602: // ! 603: ! 604: status = IoCreateDevice( ! 605: DriverObject, ! 606: sizeof(PAR_DEVICE_EXTENSION), ! 607: &uniNameString, ! 608: FILE_DEVICE_PARALLEL_PORT, ! 609: 0, ! 610: TRUE, ! 611: &deviceObject ! 612: ); ! 613: ! 614: // ! 615: // If we couldn't create the device object, then there ! 616: // is no point in going on. ! 617: // ! 618: ! 619: if (!NT_SUCCESS(status)) { ! 620: ! 621: ParLogError( ! 622: DriverObject, ! 623: NULL, ! 624: ConfigData->Controller, ! 625: ParPhysicalZero, ! 626: 0, ! 627: 0, ! 628: 0, ! 629: 3, ! 630: STATUS_SUCCESS, ! 631: PAR_INSUFFICIENT_RESOURCES ! 632: ); ! 633: ParDump( ! 634: PARERRORS, ! 635: ("PARALLEL: Could not create a device for %wZ\n", ! 636: &ConfigData->NtNameForPort) ! 637: ); ! 638: ExFreePool(ConfigData->ObjectDirectory.Buffer); ! 639: ExFreePool(ConfigData->NtNameForPort.Buffer); ! 640: ExFreePool(ConfigData->SymbolicLinkName.Buffer); ! 641: ExFreePool(ConfigData); ! 642: ExFreePool(uniNameString.Buffer); ! 643: return STATUS_INSUFFICIENT_RESOURCES; ! 644: ! 645: } ! 646: ! 647: // ! 648: // We have created the device, increment the counter in the ! 649: // IO system that keep track. Anyplace that we do an IoDeleteDevice ! 650: // we need to decrement. ! 651: // ! 652: ! 653: IoGetConfigurationInformation()->ParallelCount++; ! 654: ! 655: // ! 656: // The device object has a pointer to an area of non-paged ! 657: // pool allocated for this device. This will be the device ! 658: // extension. ! 659: // ! 660: ! 661: extension = deviceObject->DeviceExtension; ! 662: ! 663: // ! 664: // Zero all of the memory associated with the device ! 665: // extension. ! 666: // ! 667: ! 668: RtlZeroMemory( ! 669: extension, ! 670: sizeof(PAR_DEVICE_EXTENSION) ! 671: ); ! 672: ! 673: IoInitializeTimer( ! 674: deviceObject, ! 675: ParTimerRoutine, ! 676: NULL ! 677: ); ! 678: IoInitializeDpcRequest( ! 679: deviceObject, ! 680: ParDpcRoutine ! 681: ); ! 682: ! 683: // ! 684: // Save off our name. ! 685: // ! 686: ! 687: RtlInitUnicodeString( ! 688: &extension->DeviceName, ! 689: NULL ! 690: ); ! 691: ! 692: extension->DeviceName.Length = uniNameString.Length; ! 693: extension->DeviceName.MaximumLength = uniNameString.MaximumLength; ! 694: extension->DeviceName.Buffer = uniNameString.Buffer; ! 695: ! 696: // ! 697: // Just initialize the names so that we don't try ! 698: // to "clean" them up if we cant intialize the ! 699: // controller all the way. ! 700: // ! 701: ! 702: RtlInitUnicodeString( ! 703: &extension->ObjectDirectory, ! 704: NULL ! 705: ); ! 706: RtlInitUnicodeString( ! 707: &extension->NtNameForPort, ! 708: NULL ! 709: ); ! 710: RtlInitUnicodeString( ! 711: &extension->SymbolicLinkName, ! 712: NULL ! 713: ); ! 714: ! 715: // ! 716: // Get a "back pointer" to the device object and specify ! 717: // that this driver only supports buffered IO. This basically ! 718: // means that the IO system copies the users data to and from ! 719: // system supplied buffers. ! 720: // ! 721: ! 722: extension->DeviceObject = deviceObject; ! 723: deviceObject->Flags |= DO_BUFFERED_IO; ! 724: ! 725: // ! 726: // Map the memory for the control registers for the parallel device ! 727: // into virtual memory. ! 728: // ! 729: ! 730: extension->Controller = ParGetMappedAddress( ! 731: ConfigData->InterfaceType, ! 732: ConfigData->BusNumber, ! 733: ConfigData->Controller, ! 734: ConfigData->SpanOfController, ! 735: (BOOLEAN)ConfigData->AddressSpace, ! 736: &extension->UnMapRegisters ! 737: ); ! 738: ! 739: if (!extension->Controller) { ! 740: ! 741: ParLogError( ! 742: deviceObject->DriverObject, ! 743: deviceObject, ! 744: ConfigData->Controller, ! 745: ParPhysicalZero, ! 746: 0, ! 747: 0, ! 748: 0, ! 749: 4, ! 750: STATUS_SUCCESS, ! 751: PAR_REGISTERS_NOT_MAPPED ! 752: ); ! 753: ParDump( ! 754: PARERRORS, ! 755: ("PARALLEL: Could not map memory for device registers for %wZ\n", ! 756: &ConfigData->NtNameForPort) ! 757: ); ! 758: extension->UnMapRegisters = FALSE; ! 759: status = STATUS_NONE_MAPPED; ! 760: goto ExtensionCleanup; ! 761: ! 762: } ! 763: ! 764: extension->AddressSpace = ConfigData->AddressSpace; ! 765: extension->OriginalController = ConfigData->Controller; ! 766: extension->SpanOfController = ConfigData->SpanOfController; ! 767: ! 768: // ! 769: // Save off the interface type and the bus number. ! 770: // ! 771: ! 772: extension->InterfaceType = ConfigData->InterfaceType; ! 773: extension->BusNumber = ConfigData->BusNumber; ! 774: ! 775: // ! 776: // We now try to claim the ports used by this device. ! 777: // ! 778: // We only go for the ports first, since we can run this ! 779: // device without using interrupts (although we prefer ! 780: // to use the interrupts). If we can't get the ! 781: // ports then we just cleanup. If we can get the ports ! 782: // the we try to claim the ports and the interrupt. If ! 783: // we can't get the interrupt then we'll just run the ! 784: // port off a timer. ! 785: // ! 786: // NOTE NOTE NOTE!!!!! ! 787: // ! 788: // Running the port off the timer can ONLY work when we ! 789: // are ONLY doing output to the port. To support a ! 790: // BI-DIRECTIONAL port is ****MUCH**** more complicated. ! 791: // ! 792: // As an additional note - somebody else could be using ! 793: // these port addresses and not claimed them, but, there ! 794: // isn't really much we can do about that. ! 795: // ! 796: ! 797: ParReportResourcesDevice( ! 798: extension, ! 799: FALSE, ! 800: &conflict ! 801: ); ! 802: ! 803: if (conflict) { ! 804: ! 805: status = STATUS_NO_SUCH_DEVICE; ! 806: ParLogError( ! 807: deviceObject->DriverObject, ! 808: deviceObject, ! 809: ConfigData->Controller, ! 810: ParPhysicalZero, ! 811: 0, ! 812: 0, ! 813: 0, ! 814: 5, ! 815: STATUS_SUCCESS, ! 816: PAR_ADDRESS_CONFLICT ! 817: ); ! 818: ParDump( ! 819: PARERRORS, ! 820: ("PARALLEL: Could not claim the device registers for %wZ\n", ! 821: &ConfigData->NtNameForPort) ! 822: ); ! 823: goto ExtensionCleanup; ! 824: ! 825: } ! 826: ! 827: // ! 828: // The user might not have specified an interrupt. We can ! 829: // only assume that they wanted to run it off a timer. ! 830: // ! 831: ! 832: if (ConfigData->OriginalVector != MAXULONG) { ! 833: ! 834: // ! 835: // For now, assume that unless we are on a MicroChannel ! 836: // machine the interrupt isn't shareable. ! 837: // ! 838: // BUG BUG Is there some EISA data out there that will ! 839: // BUG BUG tell us whether the card is a true EISA card? ! 840: // ! 841: ! 842: if (ConfigData->InterfaceType == MicroChannel) { ! 843: ! 844: extension->InterruptShareable = TRUE; ! 845: ! 846: } else { ! 847: ! 848: extension->InterruptShareable = FALSE; ! 849: ! 850: } ! 851: // ! 852: // From the Hal, get the interrupt vector and level. ! 853: // ! 854: ! 855: extension->InterruptMode = ConfigData->InterruptMode; ! 856: extension->OriginalIrql = ConfigData->OriginalIrql; ! 857: extension->OriginalVector = ConfigData->OriginalVector; ! 858: extension->Vector = HalGetInterruptVector( ! 859: ConfigData->InterfaceType, ! 860: ConfigData->BusNumber, ! 861: ConfigData->OriginalIrql, ! 862: ConfigData->OriginalVector, ! 863: &extension->Irql, ! 864: &extension->ProcessorAffinity ! 865: ); ! 866: ! 867: // ! 868: // Ok, now try for the interrupt. ! 869: // ! 870: // NOTE NOTE even if the following call can claim, this doesn't ! 871: // mean we get to use the interrupt. There might be some BAD ! 872: // device driver out there that is using that interrupt and ! 873: // hasn't reported its resources. We won't really find out ! 874: // until we try to connect to the interrupt. ! 875: // ! 876: ! 877: ParReportResourcesDevice( ! 878: extension, ! 879: TRUE, ! 880: &extension->UsingATimer ! 881: ); ! 882: ! 883: if (extension->UsingATimer) { ! 884: ! 885: ParLogError( ! 886: deviceObject->DriverObject, ! 887: deviceObject, ! 888: ConfigData->Controller, ! 889: ParPhysicalZero, ! 890: 0, ! 891: 0, ! 892: 0, ! 893: 6, ! 894: STATUS_SUCCESS, ! 895: PAR_REPORTED_IRQL_CONFLICT ! 896: ); ! 897: ! 898: } ! 899: ! 900: } else { ! 901: ! 902: extension->UsingATimer = TRUE; ! 903: ! 904: } ! 905: ! 906: ! 907: // ! 908: // Setup for using just a timer. We might have to drop down ! 909: // to this mode if we got an interrupt storm or we never ! 910: // see the interrupt. ! 911: // ! 912: ! 913: KeInitializeSpinLock(&extension->PollingLock); ! 914: KeInitializeTimer(&extension->PollingTimer); ! 915: KeInitializeDpc( ! 916: &extension->PollingDpc, ! 917: ParPollingDpcRoutine, ! 918: extension ! 919: ); ! 920: ! 921: // ! 922: // For now just set the delay amount to 1, this ! 923: // should get us to the next system timer "tick". ! 924: // ! 925: ! 926: extension->PollingDelayAmount.LowPart = 1; ! 927: extension->PollingDelayAmount.HighPart = 0; ! 928: extension->PollingDelayAmount = RtlLargeIntegerNegate( ! 929: extension->PollingDelayAmount ! 930: ); ! 931: ! 932: ! 933: // ! 934: // Disable the device from interrupting. ! 935: // ! 936: ! 937: StoreControl( ! 938: extension->Controller, ! 939: (UCHAR)PAR_CONTROL_WR_CONTROL ! 940: ); ! 941: KeStallExecutionProcessor(60); ! 942: ! 943: // ! 944: // If it was requested that the port be disabled, now is the ! 945: // time to do it. ! 946: // ! 947: ! 948: if (ConfigData->DisablePort) { ! 949: ! 950: ! 951: status = STATUS_NO_SUCH_DEVICE; ! 952: ParLogError( ! 953: deviceObject->DriverObject, ! 954: deviceObject, ! 955: ConfigData->Controller, ! 956: ParPhysicalZero, ! 957: 0, ! 958: 0, ! 959: 0, ! 960: 40, ! 961: STATUS_SUCCESS, ! 962: PAR_DISABLED_PORT ! 963: ); ! 964: ParDump( ! 965: PARERRORS, ! 966: ("PARALLEL: Port %wZ disabled as requested\n", ! 967: &ConfigData->NtNameForPort) ! 968: ); ! 969: goto ExtensionCleanup; ! 970: } ! 971: ! 972: // ! 973: // The call will set up the naming necessary for ! 974: // external applications to get to the driver. It ! 975: // will also set up the device map. ! 976: // ! 977: ! 978: extension->ObjectDirectory = ConfigData->ObjectDirectory; ! 979: extension->NtNameForPort = ConfigData->NtNameForPort; ! 980: extension->SymbolicLinkName = ConfigData->SymbolicLinkName; ! 981: ParSetupExternalNaming(extension); ! 982: ! 983: extension->Initialized = FALSE; ! 984: extension->CountBuffer = 0; ! 985: extension->Initializing = FALSE; ! 986: extension->AutoFeed = FALSE; ! 987: extension->TimerCount = -1; ! 988: extension->TimerStart = PAR_WRITE_TIMEOUT_VALUE; ! 989: ! 990: // ! 991: // To get around some hardware bugs associated with the busy ! 992: // bit being set when it should be, we set up a couple of DPC's ! 993: // and a timer. See the comments in the interrupt service routine ! 994: // for details of the problem and the solution. ! 995: // ! 996: ! 997: KeInitializeTimer(&extension->BusyTimer); ! 998: KeInitializeDpc( ! 999: &extension->StartBusyTimerDpc, ! 1000: ParStartBusyTimer, ! 1001: extension ! 1002: ); ! 1003: KeInitializeDpc( ! 1004: &extension->BusyTimerDpc, ! 1005: ParBusyTimer, ! 1006: extension ! 1007: ); ! 1008: ! 1009: extension->BusyDelayAmount.LowPart = 1; ! 1010: extension->BusyDelayAmount.HighPart = 0; ! 1011: extension->BusyDelayAmount = RtlLargeIntegerNegate( ! 1012: extension->BusyDelayAmount ! 1013: ); ! 1014: ! 1015: // ! 1016: // Common error path cleanup. If the status is ! 1017: // bad, get rid of the device extension, device object ! 1018: // and any memory associated with it. ! 1019: // ! 1020: ! 1021: ExtensionCleanup: ; ! 1022: ! 1023: ExFreePool(ConfigData); ! 1024: ! 1025: if (NT_ERROR(status)) { ! 1026: ! 1027: if (extension) { ! 1028: ! 1029: ParCleanupDevice(extension); ! 1030: IoDeleteDevice(deviceObject); ! 1031: IoGetConfigurationInformation()->ParallelCount--; ! 1032: ! 1033: ! 1034: } ! 1035: ! 1036: } ! 1037: ! 1038: return status; ! 1039: ! 1040: } ! 1041: ! 1042: NTSTATUS ! 1043: ParItemCallBack( ! 1044: IN PVOID Context, ! 1045: IN PUNICODE_STRING PathName, ! 1046: IN INTERFACE_TYPE BusType, ! 1047: IN ULONG BusNumber, ! 1048: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 1049: IN CONFIGURATION_TYPE ControllerType, ! 1050: IN ULONG ControllerNumber, ! 1051: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 1052: IN CONFIGURATION_TYPE PeripheralType, ! 1053: IN ULONG PeripheralNumber, ! 1054: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 1055: ) ! 1056: ! 1057: /*++ ! 1058: ! 1059: Routine Description: ! 1060: ! 1061: This routine is called to check if a particular item ! 1062: is present in the registry. ! 1063: ! 1064: Arguments: ! 1065: ! 1066: Context - Pointer to a boolean. ! 1067: ! 1068: PathName - unicode registry path. Not Used. ! 1069: ! 1070: BusType - Internal, Isa, ... ! 1071: ! 1072: BusNumber - Which bus if we are on a multibus system. ! 1073: ! 1074: BusInformation - Configuration information about the bus. Not Used. ! 1075: ! 1076: ControllerType - Controller type. ! 1077: ! 1078: ControllerNumber - Which controller if there is more than one ! 1079: controller in the system. ! 1080: ! 1081: ControllerInformation - Array of pointers to the three pieces of ! 1082: registry information. ! 1083: ! 1084: PeripheralType - Should be a peripheral. ! 1085: ! 1086: PeripheralNumber - Which peripheral - not used.. ! 1087: ! 1088: PeripheralInformation - Configuration information. Not Used. ! 1089: ! 1090: Return Value: ! 1091: ! 1092: STATUS_SUCCESS ! 1093: ! 1094: --*/ ! 1095: ! 1096: { ! 1097: ! 1098: *((BOOLEAN *)Context) = TRUE; ! 1099: return STATUS_SUCCESS; ! 1100: } ! 1101: ! 1102: // ! 1103: // This structure is only used to communicate between the ! 1104: // code that queries what the firmware found and the code ! 1105: // that is calling the quering of the firmware data. ! 1106: // ! 1107: typedef struct PARALLEL_FIRMWARE_DATA { ! 1108: PDRIVER_OBJECT DriverObject; ! 1109: ULONG ControllersFound; ! 1110: UNICODE_STRING Directory; ! 1111: UNICODE_STRING NtNameSuffix; ! 1112: UNICODE_STRING DirectorySymbolicName; ! 1113: LIST_ENTRY ConfigList; ! 1114: } PARALLEL_FIRMWARE_DATA,*PPARALLEL_FIRMWARE_DATA; ! 1115: ! 1116: ! 1117: NTSTATUS ! 1118: ParConfigCallBack( ! 1119: IN PVOID Context, ! 1120: IN PUNICODE_STRING PathName, ! 1121: IN INTERFACE_TYPE BusType, ! 1122: IN ULONG BusNumber, ! 1123: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 1124: IN CONFIGURATION_TYPE ControllerType, ! 1125: IN ULONG ControllerNumber, ! 1126: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 1127: IN CONFIGURATION_TYPE PeripheralType, ! 1128: IN ULONG PeripheralNumber, ! 1129: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 1130: ) ! 1131: ! 1132: /*++ ! 1133: ! 1134: Routine Description: ! 1135: ! 1136: This routine is used to acquire all of the configuration ! 1137: information for each parallel controller found by the firmware ! 1138: ! 1139: Arguments: ! 1140: ! 1141: Context - Pointer to the list head of the list of configuration ! 1142: records that we are building up. ! 1143: ! 1144: PathName - unicode registry path. Not Used. ! 1145: ! 1146: BusType - Internal, Isa, ... ! 1147: ! 1148: BusNumber - Which bus if we are on a multibus system. ! 1149: ! 1150: BusInformation - Configuration information about the bus. Not Used. ! 1151: ! 1152: ControllerType - Should always be ParallelController. ! 1153: ! 1154: ControllerNumber - Which controller if there is more than one ! 1155: controller in the system. ! 1156: ! 1157: ControllerInformation - Array of pointers to the three pieces of ! 1158: registry information. ! 1159: ! 1160: PeripheralType - Undefined for this call. ! 1161: ! 1162: PeripheralNumber - Undefined for this call. ! 1163: ! 1164: PeripheralInformation - Undefined for this call. ! 1165: ! 1166: Return Value: ! 1167: ! 1168: STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES ! 1169: if all of the resource information couldn't be acquired. ! 1170: ! 1171: --*/ ! 1172: ! 1173: { ! 1174: ! 1175: // ! 1176: // So we don't have to typecast the context. ! 1177: // ! 1178: PPARALLEL_FIRMWARE_DATA config = Context; ! 1179: ! 1180: // ! 1181: // Pointer to the configuration stuff for this controller. ! 1182: // ! 1183: PCONFIG_DATA controller; ! 1184: ! 1185: // ! 1186: // Two booleans to help us determine that we got enough configuration ! 1187: // data. ! 1188: // ! 1189: BOOLEAN foundPort = FALSE; ! 1190: BOOLEAN foundInterrupt = FALSE; ! 1191: ! 1192: // ! 1193: // Simple iteration variable. ! 1194: // ! 1195: ULONG i; ! 1196: ! 1197: // ! 1198: // Pointer to the configuration "data" portion of the configuration ! 1199: // structures in the registry for this device. ! 1200: // ! 1201: PCM_FULL_RESOURCE_DESCRIPTOR controllerData = ! 1202: (PCM_FULL_RESOURCE_DESCRIPTOR) ! 1203: (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) + ! 1204: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset); ! 1205: ! 1206: ASSERT(ControllerType == ParallelController); ! 1207: ! 1208: config->ControllersFound++; ! 1209: ! 1210: // ! 1211: // Allocate the memory for the controller config data out of paged pool ! 1212: // since we will only be accessing it at initialization time. ! 1213: // ! 1214: ! 1215: controller = ExAllocatePool( ! 1216: PagedPool, ! 1217: sizeof(CONFIG_DATA) ! 1218: ); ! 1219: ! 1220: if (!controller) { ! 1221: ! 1222: ParLogError( ! 1223: config->DriverObject, ! 1224: NULL, ! 1225: ParPhysicalZero, ! 1226: ParPhysicalZero, ! 1227: 0, ! 1228: 0, ! 1229: 0, ! 1230: 7, ! 1231: STATUS_SUCCESS, ! 1232: PAR_INSUFFICIENT_RESOURCES ! 1233: ); ! 1234: ParDump( ! 1235: PARERRORS, ! 1236: ("PARALLEL: Couldn't allocate memory for the configuration data\n" ! 1237: "-------- for firmware data\n") ! 1238: ); ! 1239: return STATUS_INSUFFICIENT_RESOURCES; ! 1240: ! 1241: } ! 1242: ! 1243: RtlZeroMemory( ! 1244: controller, ! 1245: sizeof(CONFIG_DATA) ! 1246: ); ! 1247: InitializeListHead(&controller->ConfigList); ! 1248: ! 1249: controller->InterfaceType = BusType; ! 1250: controller->BusNumber = BusNumber; ! 1251: ! 1252: // ! 1253: // We need to get the following information out of the partial ! 1254: // resource descriptors. ! 1255: // ! 1256: // The irql and vector. ! 1257: // ! 1258: // The base address and span covered by the parallel controllers ! 1259: // registers. ! 1260: // ! 1261: // It is not defined how these appear in the partial resource ! 1262: // lists, so we will just loop over all of them. If we find ! 1263: // something we don't recognize, we drop that information on ! 1264: // the floor. When we have finished going through all the ! 1265: // partial information, we validate that we got the above ! 1266: // two. ! 1267: // ! 1268: ! 1269: for ( ! 1270: i = 0; ! 1271: i < controllerData->PartialResourceList.Count; ! 1272: i++ ! 1273: ) { ! 1274: ! 1275: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial = ! 1276: &controllerData->PartialResourceList.PartialDescriptors[i]; ! 1277: ! 1278: switch (partial->Type) { ! 1279: ! 1280: case CmResourceTypePort: { ! 1281: ! 1282: foundPort = TRUE; ! 1283: ! 1284: // ! 1285: // No matter what the registry says, we ! 1286: // know how long the register set is. ! 1287: // ! 1288: ! 1289: controller->SpanOfController = PARALLEL_REGISTER_SPAN; ! 1290: controller->Controller = partial->u.Port.Start; ! 1291: controller->AddressSpace = partial->Flags; ! 1292: ! 1293: break; ! 1294: } ! 1295: case CmResourceTypeInterrupt: { ! 1296: ! 1297: foundInterrupt = TRUE; ! 1298: if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) { ! 1299: ! 1300: controller->InterruptMode = Latched; ! 1301: ! 1302: } else { ! 1303: ! 1304: controller->InterruptMode = LevelSensitive; ! 1305: ! 1306: } ! 1307: ! 1308: controller->OriginalIrql = partial->u.Interrupt.Level; ! 1309: controller->OriginalVector = partial->u.Interrupt.Vector; ! 1310: ! 1311: break; ! 1312: ! 1313: } ! 1314: default: { ! 1315: ! 1316: break; ! 1317: ! 1318: } ! 1319: ! 1320: } ! 1321: ! 1322: } ! 1323: ! 1324: if (foundPort && foundInterrupt) { ! 1325: ! 1326: // ! 1327: // The following are so the we can form the ! 1328: // name following the \Device ! 1329: // and the default name that will be symbolic ! 1330: // linked to the device and the object directory ! 1331: // that link will go in. ! 1332: // ! 1333: ! 1334: WCHAR ntNumberBuffer[100]; ! 1335: WCHAR symbolicNumberBuffer[100]; ! 1336: UNICODE_STRING ntNumberString; ! 1337: UNICODE_STRING symbolicNumberString; ! 1338: ! 1339: ntNumberString.Length = 0; ! 1340: ntNumberString.MaximumLength = 100; ! 1341: ntNumberString.Buffer = &ntNumberBuffer[0]; ! 1342: ! 1343: symbolicNumberString.Length = 0; ! 1344: symbolicNumberString.MaximumLength = 100; ! 1345: symbolicNumberString.Buffer = &symbolicNumberBuffer[0]; ! 1346: ! 1347: // ! 1348: // Everthing is great so far. We now need to form the ! 1349: // Nt Names and symbolic link names. ! 1350: // ! 1351: ! 1352: if (!NT_SUCCESS(RtlIntegerToUnicodeString( ! 1353: config->ControllersFound - 1, ! 1354: 10, ! 1355: &ntNumberString ! 1356: ))) { ! 1357: ! 1358: ParLogError( ! 1359: config->DriverObject, ! 1360: NULL, ! 1361: ParPhysicalZero, ! 1362: ParPhysicalZero, ! 1363: 0, ! 1364: 0, ! 1365: 0, ! 1366: 8, ! 1367: STATUS_SUCCESS, ! 1368: PAR_INSUFFICIENT_RESOURCES ! 1369: ); ! 1370: ParDump( ! 1371: PARERRORS, ! 1372: ("PARALLEL: Couldn't convert NT controller number to\n" ! 1373: "-------- to unicode for firmware data: %d\n", ! 1374: config->ControllersFound - 1) ! 1375: ); ! 1376: // ! 1377: // Oh well, ignore this controller. ! 1378: // ! 1379: ExFreePool(controller); ! 1380: ! 1381: } else { ! 1382: ! 1383: if (!NT_SUCCESS(RtlIntegerToUnicodeString( ! 1384: config->ControllersFound, ! 1385: 10, ! 1386: &symbolicNumberString ! 1387: ))) { ! 1388: ! 1389: ParLogError( ! 1390: config->DriverObject, ! 1391: NULL, ! 1392: ParPhysicalZero, ! 1393: ParPhysicalZero, ! 1394: 0, ! 1395: 0, ! 1396: 0, ! 1397: 9, ! 1398: STATUS_SUCCESS, ! 1399: PAR_INSUFFICIENT_RESOURCES ! 1400: ); ! 1401: ParDump( ! 1402: PARERRORS, ! 1403: ("PARALLEL: Couldn't convert symbolic controller number to\n" ! 1404: "-------- to unicode for firmware data: %d\n", ! 1405: config->ControllersFound) ! 1406: ); ! 1407: ExFreePool(controller); ! 1408: ! 1409: } else { ! 1410: ! 1411: UNICODE_STRING Temp; ! 1412: ! 1413: // ! 1414: // Ok, we have the non-constant portions of the ! 1415: // names all figured out. Now allocate memory ! 1416: // for what will be used later. ! 1417: // ! 1418: ! 1419: // ! 1420: // Save off a copy of the object directory name. ! 1421: // ! 1422: ! 1423: // ! 1424: // Init the destination. ! 1425: // ! 1426: RtlInitUnicodeString( ! 1427: &controller->ObjectDirectory, ! 1428: NULL ! 1429: ); ! 1430: ! 1431: // ! 1432: // This will get its length. ! 1433: // ! 1434: RtlInitUnicodeString( ! 1435: &Temp, ! 1436: DEFAULT_DIRECTORY ! 1437: ); ! 1438: ! 1439: ! 1440: // ! 1441: // Now allocate that much. ! 1442: // ! 1443: ! 1444: controller->ObjectDirectory.Buffer = ! 1445: ExAllocatePool( ! 1446: PagedPool, ! 1447: Temp.Length+sizeof(WCHAR) ! 1448: ); ! 1449: ! 1450: if (!controller->ObjectDirectory.Buffer) { ! 1451: ! 1452: ParLogError( ! 1453: config->DriverObject, ! 1454: NULL, ! 1455: ParPhysicalZero, ! 1456: ParPhysicalZero, ! 1457: 0, ! 1458: 0, ! 1459: 0, ! 1460: 10, ! 1461: STATUS_SUCCESS, ! 1462: PAR_INSUFFICIENT_RESOURCES ! 1463: ); ! 1464: ParDump( ! 1465: PARERRORS, ! 1466: ("PARALLEL: Couldn't allocate memory for object\n" ! 1467: "-------- directory for NT firmware data: %d\n", ! 1468: config->ControllersFound - 1) ! 1469: ); ! 1470: ExFreePool(controller); ! 1471: return STATUS_SUCCESS; ! 1472: ! 1473: } else { ! 1474: ! 1475: controller->ObjectDirectory.MaximumLength = ! 1476: Temp.Length+sizeof(WCHAR); ! 1477: ! 1478: // ! 1479: // Zero fill it. ! 1480: // ! 1481: ! 1482: RtlZeroMemory( ! 1483: controller->ObjectDirectory.Buffer, ! 1484: controller->ObjectDirectory.MaximumLength ! 1485: ); ! 1486: ! 1487: RtlAppendUnicodeStringToString( ! 1488: &controller->ObjectDirectory, ! 1489: &Temp ! 1490: ); ! 1491: ! 1492: } ! 1493: ! 1494: // ! 1495: // Init the destination. ! 1496: // ! 1497: RtlInitUnicodeString( ! 1498: &controller->NtNameForPort, ! 1499: NULL ! 1500: ); ! 1501: ! 1502: // ! 1503: // This will get its length. ! 1504: // ! 1505: RtlInitUnicodeString( ! 1506: &Temp, ! 1507: DEFAULT_NT_SUFFIX ! 1508: ); ! 1509: ! 1510: // ! 1511: // Allocate enough for the suffix and the number. ! 1512: // ! 1513: ! 1514: controller->NtNameForPort.Buffer = ! 1515: ExAllocatePool( ! 1516: PagedPool, ! 1517: Temp.Length + ! 1518: ntNumberString.Length + sizeof(WCHAR) ! 1519: ); ! 1520: ! 1521: if (!controller->NtNameForPort.Buffer) { ! 1522: ! 1523: ParLogError( ! 1524: config->DriverObject, ! 1525: NULL, ! 1526: ParPhysicalZero, ! 1527: ParPhysicalZero, ! 1528: 0, ! 1529: 0, ! 1530: 0, ! 1531: 11, ! 1532: STATUS_SUCCESS, ! 1533: PAR_INSUFFICIENT_RESOURCES ! 1534: ); ! 1535: ParDump( ! 1536: PARERRORS, ! 1537: ("PARALLEL: Couldn't allocate memory for NT\n" ! 1538: "-------- name for NT firmware data: %d\n", ! 1539: config->ControllersFound - 1) ! 1540: ); ! 1541: ExFreePool(controller->ObjectDirectory.Buffer); ! 1542: ExFreePool(controller); ! 1543: return STATUS_SUCCESS; ! 1544: ! 1545: } else { ! 1546: ! 1547: controller->NtNameForPort.MaximumLength = ! 1548: Temp.Length+ntNumberString.Length+sizeof(WCHAR); ! 1549: ! 1550: RtlZeroMemory( ! 1551: controller->NtNameForPort.Buffer, ! 1552: controller->NtNameForPort.MaximumLength ! 1553: ); ! 1554: ! 1555: RtlAppendUnicodeStringToString( ! 1556: &controller->NtNameForPort, ! 1557: &Temp ! 1558: ); ! 1559: ! 1560: RtlAppendUnicodeStringToString( ! 1561: &controller->NtNameForPort, ! 1562: &ntNumberString ! 1563: ); ! 1564: ! 1565: } ! 1566: ! 1567: // ! 1568: // Now form that name that will be used as a ! 1569: // symbolic link to the actual device name ! 1570: // we just formed. ! 1571: // ! 1572: ! 1573: RtlInitUnicodeString( ! 1574: &controller->SymbolicLinkName, ! 1575: NULL ! 1576: ); ! 1577: ! 1578: // ! 1579: // This will get its length. ! 1580: // ! 1581: RtlInitUnicodeString( ! 1582: &Temp, ! 1583: DEFAULT_PARALLEL_NAME ! 1584: ); ! 1585: ! 1586: // ! 1587: // Allocate enough for the suffix and the number. ! 1588: // ! 1589: ! 1590: controller->SymbolicLinkName.Buffer = ! 1591: ExAllocatePool( ! 1592: PagedPool, ! 1593: Temp.Length + ! 1594: symbolicNumberString.Length+sizeof(WCHAR) ! 1595: ); ! 1596: ! 1597: if (!controller->SymbolicLinkName.Buffer) { ! 1598: ! 1599: ParLogError( ! 1600: config->DriverObject, ! 1601: NULL, ! 1602: ParPhysicalZero, ! 1603: ParPhysicalZero, ! 1604: 0, ! 1605: 0, ! 1606: 0, ! 1607: 12, ! 1608: STATUS_SUCCESS, ! 1609: PAR_INSUFFICIENT_RESOURCES ! 1610: ); ! 1611: ParDump( ! 1612: PARERRORS, ! 1613: ("PARALLEL: Couldn't allocate memory for symbolic\n" ! 1614: "-------- name for NT firmware data: %d\n", ! 1615: config->ControllersFound - 1) ! 1616: ); ! 1617: ExFreePool(controller->ObjectDirectory.Buffer); ! 1618: ExFreePool(controller->NtNameForPort.Buffer); ! 1619: ExFreePool(controller); ! 1620: return STATUS_SUCCESS; ! 1621: ! 1622: } else { ! 1623: ! 1624: controller->SymbolicLinkName.MaximumLength = ! 1625: Temp.Length+symbolicNumberString.Length+sizeof(WCHAR); ! 1626: ! 1627: RtlZeroMemory( ! 1628: controller->SymbolicLinkName.Buffer, ! 1629: controller->SymbolicLinkName.MaximumLength ! 1630: ); ! 1631: ! 1632: RtlAppendUnicodeStringToString( ! 1633: &controller->SymbolicLinkName, ! 1634: &Temp ! 1635: ); ! 1636: ! 1637: RtlAppendUnicodeStringToString( ! 1638: &controller->SymbolicLinkName, ! 1639: &symbolicNumberString ! 1640: ); ! 1641: ! 1642: } ! 1643: ! 1644: InsertTailList( ! 1645: &config->ConfigList, ! 1646: &controller->ConfigList ! 1647: ); ! 1648: ! 1649: } ! 1650: ! 1651: } ! 1652: ! 1653: } else { ! 1654: ! 1655: ParLogError( ! 1656: config->DriverObject, ! 1657: NULL, ! 1658: ParPhysicalZero, ! 1659: ParPhysicalZero, ! 1660: 0, ! 1661: 0, ! 1662: 0, ! 1663: 13, ! 1664: STATUS_SUCCESS, ! 1665: PAR_NOT_ENOUGH_CONFIG_INFO ! 1666: ); ! 1667: ExFreePool(controller); ! 1668: ! 1669: } ! 1670: ! 1671: return STATUS_SUCCESS; ! 1672: } ! 1673: ! 1674: VOID ! 1675: ParGetConfigInfo( ! 1676: IN PDRIVER_OBJECT DriverObject, ! 1677: IN PUNICODE_STRING RegistryPath, ! 1678: OUT PLIST_ENTRY ConfigList ! 1679: ) ! 1680: ! 1681: /*++ ! 1682: ! 1683: Routine Description: ! 1684: ! 1685: This routine will "return" a list of configuration ! 1686: records for the parallel ports to initialize. ! 1687: ! 1688: It will first query the firmware data. It will then ! 1689: look for "user" specified parallel ports in the registry. ! 1690: It will place the user specified parallel ports in the ! 1691: the passed in list. ! 1692: ! 1693: After it finds all of the user specified ports, it will ! 1694: attempt to add the firmware parallel ports into the passed ! 1695: in lists. The insert in the list code detects conflicts ! 1696: and rejects a new port. In this way we can prevent ! 1697: firmware found ports from overiding information ! 1698: specified by the "user". Note, this means if the user ! 1699: specified data is incorrect in its use of the interrupt ! 1700: (which should *always* be correct from the firmware) ! 1701: that port likely will not work. But, then, we "trust" ! 1702: the user. ! 1703: ! 1704: ! 1705: Arguments: ! 1706: ! 1707: DriverObject - Not used. ! 1708: ! 1709: RegistryPath - Path to this drivers service node in ! 1710: the current control set. ! 1711: ! 1712: ConfigList - Listhead (which will be intialized) for a list ! 1713: of configuration records for ports to control. ! 1714: ! 1715: Return Value: ! 1716: ! 1717: None. ! 1718: ! 1719: --*/ ! 1720: ! 1721: { ! 1722: ! 1723: // ! 1724: // A structure that we pass to the firmware query routine ! 1725: // as "context". This context will contain the number of ! 1726: // ports already found as well as default names and the ! 1727: // listhead of the configuration list. ! 1728: // ! 1729: PARALLEL_FIRMWARE_DATA firmware; ! 1730: ! 1731: // ! 1732: // This will point to the structure that is used by RtlQueryRegistryValues ! 1733: // to "direct" its search and retrieval of values. ! 1734: // ! 1735: PRTL_QUERY_REGISTRY_TABLE parameters = NULL; ! 1736: ! 1737: // ! 1738: // We'll have to query the registry to determine what kind of ! 1739: // bus the system is using. Then when the user specifies the ! 1740: // address of a port, the user doesn't have to tell us the ! 1741: // the bus type (unless they really want to). When we determine ! 1742: // the default bus on the system, we'll know whether the interrupt ! 1743: // is latched or level sensitive. ! 1744: // ! 1745: INTERFACE_TYPE interfaceType; ! 1746: ULONG defaultInterfaceType; ! 1747: ! 1748: // ! 1749: // Default values for user data. ! 1750: // ! 1751: ULONG maxUlong = MAXULONG; ! 1752: ULONG zero = 0; ! 1753: ULONG defaultInterruptMode; ! 1754: ULONG defaultAddressSpace = CM_RESOURCE_PORT_IO; ! 1755: ! 1756: // ! 1757: // Where user data from the registry will be placed. ! 1758: // ! 1759: PHYSICAL_ADDRESS userPort; ! 1760: ULONG userVector; ! 1761: ULONG userLevel; ! 1762: ULONG userBusNumber; ! 1763: ULONG userInterfaceType; ! 1764: ULONG userAddressSpace; ! 1765: ULONG userInterruptMode; ! 1766: ULONG disablePort; ! 1767: UNICODE_STRING userSymbolicLink; ! 1768: ! 1769: UNICODE_STRING parametersPath; ! 1770: OBJECT_ATTRIBUTES parametersAttributes; ! 1771: HANDLE parametersKey; ! 1772: PKEY_BASIC_INFORMATION userSubKey = NULL; ! 1773: ULONG i; ! 1774: ! 1775: InitializeListHead(ConfigList); ! 1776: ! 1777: RtlZeroMemory( ! 1778: &firmware, ! 1779: sizeof(PARALLEL_FIRMWARE_DATA) ! 1780: ); ! 1781: ! 1782: firmware.DriverObject = DriverObject; ! 1783: ! 1784: // ! 1785: // Initialize the controllers found so far with the ! 1786: // values in configuration database that the io system ! 1787: // maintains ! 1788: // ! 1789: ! 1790: firmware.ControllersFound = IoGetConfigurationInformation()->ParallelCount; ! 1791: InitializeListHead(&firmware.ConfigList); ! 1792: RtlInitUnicodeString( ! 1793: &firmware.Directory, ! 1794: DEFAULT_DIRECTORY ! 1795: ); ! 1796: RtlInitUnicodeString( ! 1797: &firmware.NtNameSuffix, ! 1798: DEFAULT_NT_SUFFIX ! 1799: ); ! 1800: RtlInitUnicodeString( ! 1801: &firmware.DirectorySymbolicName, ! 1802: DEFAULT_PARALLEL_NAME ! 1803: ); ! 1804: ! 1805: // ! 1806: // First we query the hardware registry for all of ! 1807: // the firmware defined ports. We loop over all of ! 1808: // the busses. ! 1809: // ! 1810: ! 1811: for ( ! 1812: interfaceType = 0; ! 1813: interfaceType < MaximumInterfaceType; ! 1814: interfaceType++ ! 1815: ) { ! 1816: ! 1817: CONFIGURATION_TYPE sc = ParallelController; ! 1818: ! 1819: IoQueryDeviceDescription( ! 1820: &interfaceType, ! 1821: NULL, ! 1822: &sc, ! 1823: NULL, ! 1824: NULL, ! 1825: NULL, ! 1826: ParConfigCallBack, ! 1827: &firmware ! 1828: ); ! 1829: ! 1830: } ! 1831: ! 1832: // ! 1833: // Query the registry one more time. This time we ! 1834: // look for the first bus on the system (that isn't ! 1835: // the internal bus - we assume that the firmware ! 1836: // code knows about those ports). We will use that ! 1837: // as the default bus if no bustype or bus number ! 1838: // is specified in the "user" configuration records. ! 1839: // ! 1840: ! 1841: defaultInterfaceType = (ULONG)Isa; ! 1842: defaultInterruptMode = CM_RESOURCE_INTERRUPT_LATCHED; ! 1843: ! 1844: for ( ! 1845: interfaceType = 0; ! 1846: interfaceType < MaximumInterfaceType; ! 1847: interfaceType++ ! 1848: ) { ! 1849: ! 1850: ULONG busZero = 0; ! 1851: BOOLEAN foundOne = FALSE; ! 1852: ! 1853: if (interfaceType != Internal) { ! 1854: ! 1855: IoQueryDeviceDescription( ! 1856: &interfaceType, ! 1857: &busZero, ! 1858: NULL, ! 1859: NULL, ! 1860: NULL, ! 1861: NULL, ! 1862: ParItemCallBack, ! 1863: &foundOne ! 1864: ); ! 1865: ! 1866: if (foundOne) { ! 1867: ! 1868: defaultInterfaceType = (ULONG)interfaceType; ! 1869: if (defaultInterfaceType == MicroChannel) { ! 1870: ! 1871: defaultInterruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; ! 1872: ! 1873: } ! 1874: ! 1875: break; ! 1876: ! 1877: } ! 1878: ! 1879: } ! 1880: ! 1881: } ! 1882: ! 1883: // ! 1884: // Gonna get the user data now. Allocate the ! 1885: // structures that we will be using throughout ! 1886: // the search for user data. We will deallocate ! 1887: // them before we leave this routine. ! 1888: // ! 1889: ! 1890: userSymbolicLink.Buffer = NULL; ! 1891: parametersPath.Buffer = NULL; ! 1892: ! 1893: // ! 1894: // Allocate the rtl query table. ! 1895: // ! 1896: ! 1897: parameters = ExAllocatePool( ! 1898: PagedPool, ! 1899: sizeof(RTL_QUERY_REGISTRY_TABLE)*15 ! 1900: ); ! 1901: ! 1902: if (!parameters) { ! 1903: ! 1904: ParLogError( ! 1905: DriverObject, ! 1906: NULL, ! 1907: ParPhysicalZero, ! 1908: ParPhysicalZero, ! 1909: 0, ! 1910: 0, ! 1911: 0, ! 1912: 14, ! 1913: STATUS_SUCCESS, ! 1914: PAR_INSUFFICIENT_RESOURCES ! 1915: ); ! 1916: ParDump( ! 1917: PARERRORS, ! 1918: ("PARALLEL: Couldn't allocate table for rtl query\n" ! 1919: "-------- to parameters for %wZ", ! 1920: RegistryPath) ! 1921: ); ! 1922: ! 1923: goto DoFirmwareAdd; ! 1924: ! 1925: } ! 1926: ! 1927: RtlZeroMemory( ! 1928: parameters, ! 1929: sizeof(RTL_QUERY_REGISTRY_TABLE)*15 ! 1930: ); ! 1931: ! 1932: // ! 1933: // Allocate the place where the users symbolic link name ! 1934: // for the port will go. ! 1935: // ! 1936: ! 1937: // ! 1938: // We will initially allocate space for 257 wchars. ! 1939: // we will then set the maximum size to 256 ! 1940: // This way the rtl routine could return a 256 ! 1941: // WCHAR wide string with no null terminator. ! 1942: // We'll remember that the buffer is one WCHAR ! 1943: // longer then it says it is so that we can always ! 1944: // have a NULL terminator at the end. ! 1945: // ! 1946: ! 1947: RtlInitUnicodeString( ! 1948: &userSymbolicLink, ! 1949: NULL ! 1950: ); ! 1951: userSymbolicLink.MaximumLength = sizeof(WCHAR)*256; ! 1952: userSymbolicLink.Buffer = ExAllocatePool( ! 1953: PagedPool, ! 1954: sizeof(WCHAR)*257 ! 1955: ); ! 1956: ! 1957: if (!userSymbolicLink.Buffer) { ! 1958: ! 1959: ParLogError( ! 1960: DriverObject, ! 1961: NULL, ! 1962: ParPhysicalZero, ! 1963: ParPhysicalZero, ! 1964: 0, ! 1965: 0, ! 1966: 0, ! 1967: 15, ! 1968: STATUS_SUCCESS, ! 1969: PAR_INSUFFICIENT_RESOURCES ! 1970: ); ! 1971: ParDump( ! 1972: PARERRORS, ! 1973: ("PARALLEL: Couldn't allocate buffer for the symbolic link\n" ! 1974: "-------- for parameters items in %wZ", ! 1975: RegistryPath) ! 1976: ); ! 1977: ! 1978: goto DoFirmwareAdd; ! 1979: ! 1980: } ! 1981: ! 1982: // ! 1983: // Form a path to our drivers Parameters subkey. ! 1984: // ! 1985: ! 1986: RtlInitUnicodeString( ! 1987: ¶metersPath, ! 1988: NULL ! 1989: ); ! 1990: ! 1991: parametersPath.MaximumLength = RegistryPath->Length + ! 1992: sizeof(L"\\") + ! 1993: sizeof(L"Parameters"); ! 1994: ! 1995: parametersPath.Buffer = ExAllocatePool( ! 1996: PagedPool, ! 1997: parametersPath.MaximumLength ! 1998: ); ! 1999: ! 2000: if (!parametersPath.Buffer) { ! 2001: ! 2002: ParLogError( ! 2003: DriverObject, ! 2004: NULL, ! 2005: ParPhysicalZero, ! 2006: ParPhysicalZero, ! 2007: 0, ! 2008: 0, ! 2009: 0, ! 2010: 16, ! 2011: STATUS_SUCCESS, ! 2012: PAR_INSUFFICIENT_RESOURCES ! 2013: ); ! 2014: ParDump( ! 2015: PARERRORS, ! 2016: ("PARALLEL: Couldn't allocate string for path\n" ! 2017: "-------- to parameters for %wZ", ! 2018: RegistryPath) ! 2019: ); ! 2020: ! 2021: goto DoFirmwareAdd; ! 2022: ! 2023: } ! 2024: ! 2025: // ! 2026: // Form the parameters path. ! 2027: // ! 2028: ! 2029: RtlZeroMemory( ! 2030: parametersPath.Buffer, ! 2031: parametersPath.MaximumLength ! 2032: ); ! 2033: RtlAppendUnicodeStringToString( ! 2034: ¶metersPath, ! 2035: RegistryPath ! 2036: ); ! 2037: RtlAppendUnicodeToString( ! 2038: ¶metersPath, ! 2039: L"\\" ! 2040: ); ! 2041: RtlAppendUnicodeToString( ! 2042: ¶metersPath, ! 2043: L"Parameters" ! 2044: ); ! 2045: ! 2046: userSubKey = ExAllocatePool( ! 2047: PagedPool, ! 2048: sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*256) ! 2049: ); ! 2050: ! 2051: if (!userSubKey) { ! 2052: ! 2053: ParLogError( ! 2054: DriverObject, ! 2055: NULL, ! 2056: ParPhysicalZero, ! 2057: ParPhysicalZero, ! 2058: 0, ! 2059: 0, ! 2060: 0, ! 2061: 17, ! 2062: STATUS_SUCCESS, ! 2063: PAR_INSUFFICIENT_RESOURCES ! 2064: ); ! 2065: ParDump( ! 2066: PARERRORS, ! 2067: ("PARALLEL: Couldn't allocate memory basic information\n" ! 2068: "-------- structure to enumerate subkeys for %wZ", ! 2069: ¶metersPath) ! 2070: ); ! 2071: ! 2072: goto DoFirmwareAdd; ! 2073: ! 2074: } ! 2075: ! 2076: // ! 2077: // Open the key given by our registry path & Parameters. ! 2078: // ! 2079: // Note: The reason we are opening up the key by hand, and ! 2080: // then enumerating all of the subkeys is so we don't have ! 2081: // to architect what the names of the devices have to be and ! 2082: // how many of them there could be. We just try to get ! 2083: // as many as there are. ! 2084: // ! 2085: ! 2086: InitializeObjectAttributes( ! 2087: ¶metersAttributes, ! 2088: ¶metersPath, ! 2089: OBJ_CASE_INSENSITIVE, ! 2090: NULL, ! 2091: NULL ! 2092: ); ! 2093: ! 2094: if (!NT_SUCCESS(ZwOpenKey( ! 2095: ¶metersKey, ! 2096: MAXIMUM_ALLOWED, ! 2097: ¶metersAttributes ! 2098: ))) { ! 2099: ! 2100: ParLogError( ! 2101: DriverObject, ! 2102: NULL, ! 2103: ParPhysicalZero, ! 2104: ParPhysicalZero, ! 2105: 0, ! 2106: 0, ! 2107: 0, ! 2108: 18, ! 2109: STATUS_SUCCESS, ! 2110: PAR_NO_PARAMETERS_INFO ! 2111: ); ! 2112: ParDump( ! 2113: PARERRORS, ! 2114: ("PARALLEL: Couldn't open the drivers Parameters key %wZ\n", ! 2115: RegistryPath) ! 2116: ); ! 2117: goto DoFirmwareAdd; ! 2118: ! 2119: } ! 2120: ! 2121: // ! 2122: // Gather all of the "user specified" information from ! 2123: // the registry. ! 2124: // ! 2125: ! 2126: parameters[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; ! 2127: ! 2128: parameters[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | ! 2129: RTL_QUERY_REGISTRY_DIRECT; ! 2130: parameters[1].Name = L"PortAddress"; ! 2131: parameters[1].EntryContext = &userPort.LowPart; ! 2132: ! 2133: parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2134: parameters[2].Name = L"Interrupt"; ! 2135: parameters[2].EntryContext = &userVector; ! 2136: parameters[2].DefaultType = REG_DWORD; ! 2137: parameters[2].DefaultData = &maxUlong; ! 2138: parameters[2].DefaultLength = sizeof(ULONG); ! 2139: ! 2140: parameters[3].Flags = RTL_QUERY_REGISTRY_REQUIRED | ! 2141: RTL_QUERY_REGISTRY_DIRECT; ! 2142: parameters[3].Name = firmware.Directory.Buffer; ! 2143: parameters[3].EntryContext = &userSymbolicLink; ! 2144: ! 2145: parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2146: parameters[4].Name = L"BusNumber"; ! 2147: parameters[4].EntryContext = &userBusNumber; ! 2148: parameters[4].DefaultType = REG_DWORD; ! 2149: parameters[4].DefaultData = &zero; ! 2150: parameters[4].DefaultLength = sizeof(ULONG); ! 2151: ! 2152: parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2153: parameters[5].Name = L"BusType"; ! 2154: parameters[5].EntryContext = &userInterfaceType; ! 2155: parameters[5].DefaultType = REG_DWORD; ! 2156: parameters[5].DefaultData = &defaultInterfaceType; ! 2157: parameters[5].DefaultLength = sizeof(ULONG); ! 2158: ! 2159: parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2160: parameters[6].Name = L"InterruptMode"; ! 2161: parameters[6].EntryContext = &userInterruptMode; ! 2162: parameters[6].DefaultType = REG_DWORD; ! 2163: parameters[6].DefaultData = &defaultInterruptMode; ! 2164: parameters[6].DefaultLength = sizeof(ULONG); ! 2165: ! 2166: parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2167: parameters[7].Name = L"AddressSpace"; ! 2168: parameters[7].EntryContext = &userAddressSpace; ! 2169: parameters[7].DefaultType = REG_DWORD; ! 2170: parameters[7].DefaultData = &defaultAddressSpace; ! 2171: parameters[7].DefaultLength = sizeof(ULONG); ! 2172: ! 2173: parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2174: parameters[8].Name = L"InterruptLevel"; ! 2175: parameters[8].EntryContext = &userLevel; ! 2176: parameters[8].DefaultType = REG_DWORD; ! 2177: parameters[8].DefaultData = &zero; ! 2178: parameters[8].DefaultLength = sizeof(ULONG); ! 2179: ! 2180: parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT; ! 2181: parameters[9].Name = L"DisablePort"; ! 2182: parameters[9].EntryContext = &disablePort; ! 2183: parameters[9].DefaultType = REG_DWORD; ! 2184: parameters[9].DefaultData = &zero; ! 2185: parameters[9].DefaultLength = sizeof(ULONG); ! 2186: ! 2187: i = 0; ! 2188: while (TRUE) { ! 2189: ! 2190: NTSTATUS status; ! 2191: ULONG actuallyReturned; ! 2192: ! 2193: // ! 2194: // We lie about the length of the buffer, so that we can ! 2195: // MAKE SURE that the name it returns can be padded with ! 2196: // a NULL. ! 2197: // ! 2198: ! 2199: status = ZwEnumerateKey( ! 2200: parametersKey, ! 2201: i, ! 2202: KeyBasicInformation, ! 2203: userSubKey, ! 2204: sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*255), ! 2205: &actuallyReturned ! 2206: ); ! 2207: ! 2208: if (status == STATUS_NO_MORE_ENTRIES) { ! 2209: ! 2210: break; ! 2211: } ! 2212: ! 2213: if (status == STATUS_BUFFER_OVERFLOW) { ! 2214: ! 2215: ParLogError( ! 2216: DriverObject, ! 2217: NULL, ! 2218: ParPhysicalZero, ! 2219: ParPhysicalZero, ! 2220: 0, ! 2221: 0, ! 2222: 0, ! 2223: 19, ! 2224: STATUS_SUCCESS, ! 2225: PAR_UNABLE_TO_ACCESS_CONFIG ! 2226: ); ! 2227: ParDump( ! 2228: PARERRORS, ! 2229: ("PARALLEL: Overflowed the enumerate buffer\n" ! 2230: "-------- for subkey #%d of %wZ\n", ! 2231: i,parametersPath) ! 2232: ); ! 2233: i++; ! 2234: continue; ! 2235: ! 2236: } ! 2237: ! 2238: if (!NT_SUCCESS(status)) { ! 2239: ! 2240: ParLogError( ! 2241: DriverObject, ! 2242: NULL, ! 2243: ParPhysicalZero, ! 2244: ParPhysicalZero, ! 2245: 0, ! 2246: 0, ! 2247: 0, ! 2248: 20, ! 2249: status, ! 2250: PAR_UNABLE_TO_ACCESS_CONFIG ! 2251: ); ! 2252: ParDump( ! 2253: PARERRORS, ! 2254: ("PARALLEL: Bad status returned: %x \n" ! 2255: "-------- on enumeration for subkey # %d of %wZ\n", ! 2256: status,i,parametersPath) ! 2257: ); ! 2258: i++; ! 2259: continue; ! 2260: ! 2261: } ! 2262: ! 2263: // ! 2264: // Pad the name returned with a null. ! 2265: // ! 2266: ! 2267: RtlZeroMemory( ! 2268: ((PUCHAR)(&userSubKey->Name[0]))+userSubKey->NameLength, ! 2269: sizeof(WCHAR) ! 2270: ); ! 2271: ! 2272: parameters[0].Name = &userSubKey->Name[0]; ! 2273: ! 2274: // ! 2275: // Make sure that the physical addresses start ! 2276: // out clean. ! 2277: // ! 2278: RtlZeroMemory( ! 2279: &userPort, ! 2280: sizeof(userPort) ! 2281: ); ! 2282: ! 2283: status = RtlQueryRegistryValues( ! 2284: RTL_REGISTRY_ABSOLUTE, ! 2285: parametersPath.Buffer, ! 2286: parameters, ! 2287: NULL, ! 2288: NULL ! 2289: ); ! 2290: ! 2291: if (NT_SUCCESS(status)) { ! 2292: ! 2293: PCONFIG_DATA newConfig; ! 2294: ! 2295: // ! 2296: // Well! Some supposedly valid information was found! ! 2297: // ! 2298: // We'll see about that. ! 2299: // ! 2300: // We don't want to cause the hal to have a bad day, ! 2301: // so let's check the interface type and bus number. ! 2302: // ! 2303: // We only need to check the registry if they aren't ! 2304: // equal to the defaults. ! 2305: // ! 2306: ! 2307: if ((userBusNumber != 0) || ! 2308: (userInterfaceType != defaultInterfaceType)) { ! 2309: ! 2310: BOOLEAN foundIt = FALSE; ! 2311: if (userInterfaceType >= MaximumInterfaceType) { ! 2312: ! 2313: // ! 2314: // Ehhhh! Lose Game. ! 2315: // ! 2316: ! 2317: ParLogError( ! 2318: DriverObject, ! 2319: NULL, ! 2320: userPort, ! 2321: ParPhysicalZero, ! 2322: 0, ! 2323: 0, ! 2324: 0, ! 2325: 21, ! 2326: STATUS_SUCCESS, ! 2327: PAR_UNKNOWN_BUS ! 2328: ); ! 2329: ParDump( ! 2330: PARERRORS, ! 2331: ("PARALLEL: Invalid Bus type %ws\n", ! 2332: parameters[0].Name) ! 2333: ); ! 2334: i++; ! 2335: continue; ! 2336: ! 2337: } ! 2338: ! 2339: IoQueryDeviceDescription( ! 2340: (INTERFACE_TYPE *)&userInterfaceType, ! 2341: &userBusNumber, ! 2342: NULL, ! 2343: NULL, ! 2344: NULL, ! 2345: NULL, ! 2346: ParItemCallBack, ! 2347: &foundIt ! 2348: ); ! 2349: ! 2350: if (!foundIt) { ! 2351: ! 2352: ParLogError( ! 2353: DriverObject, ! 2354: NULL, ! 2355: userPort, ! 2356: ParPhysicalZero, ! 2357: 0, ! 2358: 0, ! 2359: 0, ! 2360: 22, ! 2361: STATUS_SUCCESS, ! 2362: PAR_BUS_NOT_PRESENT ! 2363: ); ! 2364: ParDump( ! 2365: PARERRORS, ! 2366: ("PARALLEL: There aren't that many of those\n" ! 2367: "-------- busses on this system,%ws\n", ! 2368: parameters[0].Name) ! 2369: ); ! 2370: i++; ! 2371: continue; ! 2372: ! 2373: } ! 2374: ! 2375: } ! 2376: ! 2377: if ((userInterfaceType == MicroChannel) && ! 2378: (userInterruptMode == CM_RESOURCE_INTERRUPT_LATCHED)) { ! 2379: ! 2380: ParLogError( ! 2381: DriverObject, ! 2382: NULL, ! 2383: userPort, ! 2384: ParPhysicalZero, ! 2385: 0, ! 2386: 0, ! 2387: 0, ! 2388: 23, ! 2389: STATUS_SUCCESS, ! 2390: PAR_BUS_INTERRUPT_CONFLICT ! 2391: ); ! 2392: ParDump( ! 2393: PARERRORS, ! 2394: ("PARALLEL: Latched interrupts and MicroChannel\n" ! 2395: "-------- busses don't mix,%ws\n", ! 2396: parameters[0].Name) ! 2397: ); ! 2398: i++; ! 2399: continue; ! 2400: ! 2401: } ! 2402: ! 2403: // ! 2404: // Well ok, I guess we can take the data. ! 2405: // There be other tests later on to make ! 2406: // sure it doesn't have any other kinds ! 2407: // of conflicts. ! 2408: // ! 2409: ! 2410: // ! 2411: // Allocate the config record. ! 2412: // ! 2413: ! 2414: newConfig = ExAllocatePool( ! 2415: PagedPool, ! 2416: sizeof(CONFIG_DATA) ! 2417: ); ! 2418: ! 2419: if (!newConfig) { ! 2420: ! 2421: ParLogError( ! 2422: DriverObject, ! 2423: NULL, ! 2424: userPort, ! 2425: ParPhysicalZero, ! 2426: 0, ! 2427: 0, ! 2428: 0, ! 2429: 24, ! 2430: STATUS_SUCCESS, ! 2431: PAR_INSUFFICIENT_RESOURCES ! 2432: ); ! 2433: ParDump( ! 2434: PARERRORS, ! 2435: ("PARALLEL: Couldn't allocate memory for the\n" ! 2436: "-------- user configuration record\n" ! 2437: "-------- for %ws\n", ! 2438: parameters[0].Name) ! 2439: ); ! 2440: ! 2441: i++; ! 2442: continue; ! 2443: ! 2444: } ! 2445: ! 2446: RtlZeroMemory( ! 2447: newConfig, ! 2448: sizeof(CONFIG_DATA) ! 2449: ); ! 2450: ! 2451: // ! 2452: // Save off a copy of the object directory name. ! 2453: // ! 2454: ! 2455: // ! 2456: // Init the destination. ! 2457: // ! 2458: RtlInitUnicodeString( ! 2459: &newConfig->ObjectDirectory, ! 2460: DEFAULT_DIRECTORY ! 2461: ); ! 2462: newConfig->ObjectDirectory.MaximumLength += sizeof(WCHAR); ! 2463: ! 2464: // ! 2465: // Now allocate that much. ! 2466: // ! 2467: ! 2468: newConfig->ObjectDirectory.Buffer = ! 2469: ExAllocatePool( ! 2470: PagedPool, ! 2471: newConfig->ObjectDirectory.MaximumLength ! 2472: ); ! 2473: ! 2474: if (!newConfig->ObjectDirectory.Buffer) { ! 2475: ! 2476: ParLogError( ! 2477: DriverObject, ! 2478: NULL, ! 2479: userPort, ! 2480: ParPhysicalZero, ! 2481: 0, ! 2482: 0, ! 2483: 0, ! 2484: 25, ! 2485: STATUS_SUCCESS, ! 2486: PAR_INSUFFICIENT_RESOURCES ! 2487: ); ! 2488: ParDump( ! 2489: PARERRORS, ! 2490: ("PARALLEL: Couldn't allocate memory for object\n" ! 2491: "-------- directory for NT user data for: %ws\n", ! 2492: parameters[0].Name) ! 2493: ); ! 2494: ExFreePool(newConfig); ! 2495: i++; ! 2496: continue; ! 2497: ! 2498: } else { ! 2499: ! 2500: // ! 2501: // Zero fill it. ! 2502: // ! 2503: ! 2504: RtlZeroMemory( ! 2505: newConfig->ObjectDirectory.Buffer, ! 2506: newConfig->ObjectDirectory.MaximumLength ! 2507: ); ! 2508: ! 2509: newConfig->ObjectDirectory.Length = 0; ! 2510: RtlAppendUnicodeToString( ! 2511: &newConfig->ObjectDirectory, ! 2512: DEFAULT_DIRECTORY ! 2513: ); ! 2514: ! 2515: } ! 2516: ! 2517: // ! 2518: // Init the destination. ! 2519: // ! 2520: ! 2521: RtlInitUnicodeString( ! 2522: &newConfig->NtNameForPort, ! 2523: &userSubKey->Name[0] ! 2524: ); ! 2525: ! 2526: // ! 2527: // Allocate the space for the name. ! 2528: // ! 2529: ! 2530: newConfig->NtNameForPort.Length = 0; ! 2531: newConfig->NtNameForPort.MaximumLength += sizeof(WCHAR); ! 2532: newConfig->NtNameForPort.Buffer = ! 2533: ExAllocatePool( ! 2534: PagedPool, ! 2535: newConfig->NtNameForPort.MaximumLength ! 2536: ); ! 2537: ! 2538: if (!newConfig->NtNameForPort.Buffer) { ! 2539: ! 2540: ParLogError( ! 2541: DriverObject, ! 2542: NULL, ! 2543: userPort, ! 2544: ParPhysicalZero, ! 2545: 0, ! 2546: 0, ! 2547: 0, ! 2548: 26, ! 2549: STATUS_SUCCESS, ! 2550: PAR_INSUFFICIENT_RESOURCES ! 2551: ); ! 2552: ParDump( ! 2553: PARERRORS, ! 2554: ("PARALLEL: Couldn't allocate memory for NT\n" ! 2555: "-------- name for NT user data name: %ws\n", ! 2556: parameters[0].Name) ! 2557: ); ! 2558: ExFreePool(newConfig->ObjectDirectory.Buffer); ! 2559: ExFreePool(newConfig); ! 2560: i++; ! 2561: continue; ! 2562: ! 2563: } else { ! 2564: ! 2565: RtlZeroMemory( ! 2566: newConfig->NtNameForPort.Buffer, ! 2567: newConfig->NtNameForPort.MaximumLength ! 2568: ); ! 2569: ! 2570: RtlAppendUnicodeToString( ! 2571: &newConfig->NtNameForPort, ! 2572: &userSubKey->Name[0] ! 2573: ); ! 2574: ! 2575: } ! 2576: ! 2577: newConfig->SymbolicLinkName = userSymbolicLink; ! 2578: newConfig->SymbolicLinkName.MaximumLength += sizeof(WCHAR); ! 2579: ! 2580: newConfig->SymbolicLinkName.Buffer = ! 2581: ExAllocatePool( ! 2582: PagedPool, ! 2583: newConfig->SymbolicLinkName.MaximumLength ! 2584: ); ! 2585: ! 2586: if (!newConfig->SymbolicLinkName.Buffer) { ! 2587: ! 2588: ParLogError( ! 2589: DriverObject, ! 2590: NULL, ! 2591: userPort, ! 2592: ParPhysicalZero, ! 2593: 0, ! 2594: 0, ! 2595: 0, ! 2596: 27, ! 2597: STATUS_SUCCESS, ! 2598: PAR_INSUFFICIENT_RESOURCES ! 2599: ); ! 2600: ParDump( ! 2601: PARERRORS, ! 2602: ("PARALLEL: Couldn't allocate memory for symbolic\n" ! 2603: "-------- name from user data\n" ! 2604: "-------- %ws\n", ! 2605: parameters[0].Name) ! 2606: ); ! 2607: ExFreePool(newConfig->ObjectDirectory.Buffer); ! 2608: ExFreePool(newConfig->NtNameForPort.Buffer); ! 2609: ExFreePool(newConfig); ! 2610: i++; ! 2611: continue; ! 2612: ! 2613: } else { ! 2614: ! 2615: RtlZeroMemory( ! 2616: newConfig->SymbolicLinkName.Buffer, ! 2617: newConfig->SymbolicLinkName.MaximumLength ! 2618: ); ! 2619: ! 2620: newConfig->SymbolicLinkName.Length = 0; ! 2621: RtlAppendUnicodeStringToString( ! 2622: &newConfig->SymbolicLinkName, ! 2623: &userSymbolicLink ! 2624: ); ! 2625: ! 2626: } ! 2627: ! 2628: InitializeListHead(&newConfig->ConfigList); ! 2629: newConfig->Controller = userPort; ! 2630: newConfig->SpanOfController = PARALLEL_REGISTER_SPAN; ! 2631: newConfig->BusNumber = userBusNumber; ! 2632: newConfig->AddressSpace = userAddressSpace; ! 2633: newConfig->InterruptMode = userInterruptMode; ! 2634: newConfig->InterfaceType = userInterfaceType; ! 2635: newConfig->OriginalVector = userVector; ! 2636: newConfig->DisablePort = disablePort; ! 2637: if (!userLevel) { ! 2638: newConfig->OriginalIrql = userVector; ! 2639: } else { ! 2640: newConfig->OriginalIrql = userLevel; ! 2641: } ! 2642: ParDump( ! 2643: PARCONFIG, ! 2644: ("PARALLEL: 'user registry info - userPort: %x\n", ! 2645: userPort.LowPart) ! 2646: ); ! 2647: ParDump( ! 2648: PARCONFIG, ! 2649: ("PARALLEL: 'user registry info - userBusNumber: %d\n", ! 2650: userBusNumber) ! 2651: ); ! 2652: ParDump( ! 2653: PARCONFIG, ! 2654: ("PARALLEL: 'user registry info - userAddressSpace: %d\n", ! 2655: userAddressSpace) ! 2656: ); ! 2657: ParDump( ! 2658: PARCONFIG, ! 2659: ("PARALLEL: 'user registry info - userInterruptMode: %d\n", ! 2660: userInterruptMode) ! 2661: ); ! 2662: ParDump( ! 2663: PARCONFIG, ! 2664: ("PARALLEL: 'user registry info - userInterfaceType: %d\n", ! 2665: userInterfaceType) ! 2666: ); ! 2667: ParDump( ! 2668: PARCONFIG, ! 2669: ("PARALLEL: 'user registry info - userVector: %d\n", ! 2670: userVector) ! 2671: ); ! 2672: ParDump( ! 2673: PARCONFIG, ! 2674: ("PARALLEL: 'user registry info - userLevel: %d\n", ! 2675: userLevel) ! 2676: ); ! 2677: ! 2678: if (!ParPutInConfigList( ! 2679: DriverObject, ! 2680: ConfigList, ! 2681: newConfig ! 2682: )) { ! 2683: ! 2684: // ! 2685: // Dispose of this configuration record. ! 2686: // ! 2687: ! 2688: ParDump( ! 2689: PARERRORS, ! 2690: ("PARALLEL: Conflict detected amoungst user data %ws\n", ! 2691: parameters[0].Name) ! 2692: ); ! 2693: ! 2694: ExFreePool(newConfig->ObjectDirectory.Buffer); ! 2695: ExFreePool(newConfig->NtNameForPort.Buffer); ! 2696: ExFreePool(newConfig->SymbolicLinkName.Buffer); ! 2697: ExFreePool(newConfig); ! 2698: ! 2699: } ! 2700: ! 2701: i++; ! 2702: ! 2703: } else { ! 2704: ! 2705: ParLogError( ! 2706: DriverObject, ! 2707: NULL, ! 2708: ParPhysicalZero, ! 2709: ParPhysicalZero, ! 2710: 0, ! 2711: 0, ! 2712: 0, ! 2713: 28, ! 2714: STATUS_SUCCESS, ! 2715: PAR_INVALID_USER_CONFIG ! 2716: ); ! 2717: ParDump( ! 2718: PARERRORS, ! 2719: ("PARALLEL: Bad status returned: %x \n" ! 2720: "-------- for the value entries of\n" ! 2721: "-------- %ws\n", ! 2722: status,parameters[0].Name) ! 2723: ); ! 2724: ! 2725: i++; ! 2726: ! 2727: } ! 2728: ! 2729: } ! 2730: ! 2731: ZwClose(parametersKey); ! 2732: ! 2733: DoFirmwareAdd:; ! 2734: ! 2735: // ! 2736: // All done with the user specified information. Now try ! 2737: // to add the firmware specified data to the configuration. ! 2738: // If a conflict is detected then we simply dispose of that ! 2739: // firmware collected data. ! 2740: // ! 2741: ! 2742: while (!IsListEmpty(&firmware.ConfigList)) { ! 2743: ! 2744: PLIST_ENTRY head; ! 2745: PCONFIG_DATA firmwareData; ! 2746: ! 2747: head = RemoveHeadList(&firmware.ConfigList); ! 2748: ! 2749: firmwareData = CONTAINING_RECORD( ! 2750: head, ! 2751: CONFIG_DATA, ! 2752: ConfigList ! 2753: ); ! 2754: ! 2755: if (!ParPutInConfigList( ! 2756: DriverObject, ! 2757: ConfigList, ! 2758: firmwareData ! 2759: )) { ! 2760: ! 2761: // ! 2762: // Dispose of this configuration record. ! 2763: // ! 2764: ! 2765: ParLogError( ! 2766: DriverObject, ! 2767: NULL, ! 2768: firmwareData->Controller, ! 2769: ParPhysicalZero, ! 2770: 0, ! 2771: 0, ! 2772: 0, ! 2773: 29, ! 2774: STATUS_SUCCESS, ! 2775: PAR_USER_OVERRIDE ! 2776: ); ! 2777: ParDump( ! 2778: PARERRORS, ! 2779: ("PARALLEL: Conflict detected with user data for firmware port %wZ\n" ! 2780: "-------- User data will overides firmware data\n", ! 2781: &firmwareData->NtNameForPort) ! 2782: ); ! 2783: ExFreePool(firmwareData->ObjectDirectory.Buffer); ! 2784: ExFreePool(firmwareData->NtNameForPort.Buffer); ! 2785: ExFreePool(firmwareData->SymbolicLinkName.Buffer); ! 2786: ExFreePool(firmwareData); ! 2787: ! 2788: } ! 2789: ! 2790: } ! 2791: ! 2792: if (userSubKey) { ! 2793: ! 2794: ExFreePool(userSubKey); ! 2795: ! 2796: } ! 2797: ! 2798: if (userSymbolicLink.Buffer) { ! 2799: ! 2800: ExFreePool(userSymbolicLink.Buffer); ! 2801: ! 2802: } ! 2803: ! 2804: if (parametersPath.Buffer) { ! 2805: ! 2806: ExFreePool(parametersPath.Buffer); ! 2807: ! 2808: } ! 2809: ! 2810: if (parameters) { ! 2811: ! 2812: ExFreePool(parameters); ! 2813: ! 2814: } ! 2815: } ! 2816: ! 2817: BOOLEAN ! 2818: ParPutInConfigList( ! 2819: IN PDRIVER_OBJECT DriverObject, ! 2820: IN OUT PLIST_ENTRY ConfigList, ! 2821: IN PCONFIG_DATA New ! 2822: ) ! 2823: ! 2824: /*++ ! 2825: ! 2826: Routine Description: ! 2827: ! 2828: Given a new config record and a config list, this routine ! 2829: will perform a check to make sure that the new record doesn't ! 2830: conflict with old records. ! 2831: ! 2832: If everything checks out it will insert the new config record ! 2833: into the config list. ! 2834: ! 2835: Arguments: ! 2836: ! 2837: DriverObject - The driver we are attempting to get configuration ! 2838: information for. ! 2839: ! 2840: ConfigList - Listhead for a list of configuration records for ! 2841: ports to control. ! 2842: ! 2843: New = Pointer to new configuration record to add. ! 2844: ! 2845: Return Value: ! 2846: ! 2847: True if the record was added to the config list, false otherwise. ! 2848: ! 2849: --*/ ! 2850: ! 2851: { ! 2852: ! 2853: PHYSICAL_ADDRESS parPhysicalMax; ! 2854: PHYSICAL_ADDRESS parPhysicalZero; ! 2855: ! 2856: parPhysicalMax.LowPart = (ULONG)~0; ! 2857: parPhysicalMax.HighPart = ~0; ! 2858: ! 2859: ParDump( ! 2860: PARCONFIG, ! 2861: ("PARALLEL: Attempting to add %wZ\n" ! 2862: "-------- to the config list\n" ! 2863: "-------- PortAddress is %x\n" ! 2864: "-------- BusNumber is %d\n" ! 2865: "-------- BusType is %d\n" ! 2866: "-------- AddressSpace is %d\n", ! 2867: &New->NtNameForPort, ! 2868: New->Controller.LowPart, ! 2869: New->BusNumber, ! 2870: New->InterfaceType, ! 2871: New->AddressSpace ! 2872: ) ! 2873: ); ! 2874: ! 2875: // ! 2876: // We don't support any boards whose memory wraps around ! 2877: // the physical address space. ! 2878: // ! 2879: ! 2880: if (ParMemCompare( ! 2881: New->Controller, ! 2882: New->SpanOfController, ! 2883: parPhysicalMax, ! 2884: (ULONG)0 ! 2885: ) != AddressesAreDisjoint) { ! 2886: ! 2887: ParLogError( ! 2888: DriverObject, ! 2889: NULL, ! 2890: New->Controller, ! 2891: ParPhysicalZero, ! 2892: 0, ! 2893: 0, ! 2894: 0, ! 2895: 30, ! 2896: STATUS_SUCCESS, ! 2897: PAR_DEVICE_TOO_HIGH ! 2898: ); ! 2899: ParDump( ! 2900: PARERRORS, ! 2901: ("PARALLEL: Error in config record for %wZ\n" ! 2902: "-------- registers rap around physical memory\n", ! 2903: &New->NtNameForPort) ! 2904: ); ! 2905: return FALSE; ! 2906: ! 2907: } ! 2908: ! 2909: // ! 2910: // Go through the list looking for previous devices ! 2911: // with the same address. ! 2912: // ! 2913: ! 2914: if (!IsListEmpty(ConfigList)) { ! 2915: ! 2916: PLIST_ENTRY CurrentConfigListEntry = ConfigList->Flink; ! 2917: ! 2918: do { ! 2919: ! 2920: PCONFIG_DATA OldConfig = CONTAINING_RECORD( ! 2921: CurrentConfigListEntry, ! 2922: CONFIG_DATA, ! 2923: ConfigList ! 2924: ); ! 2925: ! 2926: // ! 2927: // We only care about ports that are on the same bus. ! 2928: // ! 2929: ! 2930: if ((OldConfig->InterfaceType == New->InterfaceType) && ! 2931: (OldConfig->BusNumber == New->BusNumber)) { ! 2932: ! 2933: ParDump( ! 2934: PARCONFIG, ! 2935: ("PARALLEL: Comparing it to %wZ\n" ! 2936: "-------- already in the config list\n" ! 2937: "-------- PortAddress is %x\n" ! 2938: "-------- BusNumber is %d\n" ! 2939: "-------- BusType is %d\n" ! 2940: "-------- AddressSpace is %d\n", ! 2941: &OldConfig->NtNameForPort, ! 2942: OldConfig->Controller.LowPart, ! 2943: OldConfig->BusNumber, ! 2944: OldConfig->InterfaceType, ! 2945: OldConfig->AddressSpace ! 2946: ) ! 2947: ); ! 2948: ! 2949: if (ParMemCompare( ! 2950: New->Controller, ! 2951: New->SpanOfController, ! 2952: OldConfig->Controller, ! 2953: OldConfig->SpanOfController ! 2954: ) != AddressesAreDisjoint) { ! 2955: ! 2956: ParLogError( ! 2957: DriverObject, ! 2958: NULL, ! 2959: New->Controller, ! 2960: OldConfig->Controller, ! 2961: 0, ! 2962: 0, ! 2963: 0, ! 2964: 31, ! 2965: STATUS_SUCCESS, ! 2966: PAR_CONTROL_OVERLAP ! 2967: ); ! 2968: return FALSE; ! 2969: ! 2970: } ! 2971: ! 2972: } ! 2973: ! 2974: CurrentConfigListEntry = CurrentConfigListEntry->Flink; ! 2975: ! 2976: } while (CurrentConfigListEntry != ConfigList); ! 2977: ! 2978: } ! 2979: ! 2980: InsertTailList( ! 2981: ConfigList, ! 2982: &New->ConfigList ! 2983: ); ! 2984: ! 2985: return TRUE; ! 2986: ! 2987: } ! 2988: ! 2989: PVOID ! 2990: ParGetMappedAddress( ! 2991: IN INTERFACE_TYPE BusType, ! 2992: IN ULONG BusNumber, ! 2993: PHYSICAL_ADDRESS IoAddress, ! 2994: ULONG NumberOfBytes, ! 2995: ULONG AddressSpace, ! 2996: PBOOLEAN MappedAddress ! 2997: ) ! 2998: ! 2999: /*++ ! 3000: ! 3001: Routine Description: ! 3002: ! 3003: This routine maps an IO address to system address space. ! 3004: ! 3005: Arguments: ! 3006: ! 3007: BusType - what type of bus - eisa, mca, isa ! 3008: IoBusNumber - which IO bus (for machines with multiple buses). ! 3009: IoAddress - base device address to be mapped. ! 3010: NumberOfBytes - number of bytes for which address is valid. ! 3011: AddressSpace - Denotes whether the address is in io space or memory. ! 3012: MappedAddress - indicates whether the address was mapped. ! 3013: This only has meaning if the address returned ! 3014: is non-null. ! 3015: ! 3016: Return Value: ! 3017: ! 3018: Mapped address ! 3019: ! 3020: --*/ ! 3021: ! 3022: { ! 3023: PHYSICAL_ADDRESS cardAddress; ! 3024: PVOID address; ! 3025: ! 3026: HalTranslateBusAddress( ! 3027: BusType, ! 3028: BusNumber, ! 3029: IoAddress, ! 3030: &AddressSpace, ! 3031: &cardAddress ! 3032: ); ! 3033: ! 3034: // ! 3035: // Map the device base address into the virtual address space ! 3036: // if the address is in memory space. ! 3037: // ! 3038: ! 3039: if (!AddressSpace) { ! 3040: ! 3041: address = MmMapIoSpace( ! 3042: cardAddress, ! 3043: NumberOfBytes, ! 3044: FALSE ! 3045: ); ! 3046: ! 3047: *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE)); ! 3048: ! 3049: } else { ! 3050: ! 3051: address = (PVOID)cardAddress.LowPart; ! 3052: *MappedAddress = FALSE; ! 3053: ! 3054: } ! 3055: ! 3056: return address; ! 3057: ! 3058: } ! 3059: ! 3060: VOID ! 3061: ParSetupExternalNaming( ! 3062: IN PPAR_DEVICE_EXTENSION Extension ! 3063: ) ! 3064: ! 3065: /*++ ! 3066: ! 3067: Routine Description: ! 3068: ! 3069: This routine will be used to create a symbolic link ! 3070: to the driver name in the given object directory. ! 3071: ! 3072: It will also create an entry in the device map for ! 3073: this device if the symbolic link was created. ! 3074: ! 3075: Arguments: ! 3076: ! 3077: Extension - Pointer to the device extension. ! 3078: ! 3079: Return Value: ! 3080: ! 3081: None. ! 3082: ! 3083: --*/ ! 3084: ! 3085: { ! 3086: ! 3087: UNICODE_STRING fullLinkName; ! 3088: ! 3089: // ! 3090: // Form the full symbolic link name we wish to create. ! 3091: // ! 3092: ! 3093: RtlInitUnicodeString( ! 3094: &fullLinkName, ! 3095: NULL ! 3096: ); ! 3097: ! 3098: // ! 3099: // Allocate some pool for the name. ! 3100: // ! 3101: ! 3102: fullLinkName.MaximumLength = (sizeof(L"\\")*2) + ! 3103: Extension->ObjectDirectory.Length+ ! 3104: Extension->SymbolicLinkName.Length+ ! 3105: sizeof(WCHAR); ! 3106: ! 3107: ! 3108: ! 3109: fullLinkName.Buffer = ExAllocatePool( ! 3110: PagedPool, ! 3111: fullLinkName.MaximumLength ! 3112: ); ! 3113: ! 3114: if (!fullLinkName.Buffer) { ! 3115: ! 3116: // ! 3117: // Couldn't allocate space for the name. Just go on ! 3118: // to the device map stuff. ! 3119: // ! 3120: ! 3121: ParLogError( ! 3122: Extension->DeviceObject->DriverObject, ! 3123: Extension->DeviceObject, ! 3124: Extension->OriginalController, ! 3125: ParPhysicalZero, ! 3126: 0, ! 3127: 0, ! 3128: 0, ! 3129: 32, ! 3130: STATUS_SUCCESS, ! 3131: PAR_INSUFFICIENT_RESOURCES ! 3132: ); ! 3133: ParDump( ! 3134: PARERRORS, ! 3135: ("PARALLEL: Couldn't allocate space for the symbolic \n" ! 3136: "-------- name for creating the link\n" ! 3137: "-------- for port %wZ\n", ! 3138: &Extension->DeviceName) ! 3139: ); ! 3140: ! 3141: } else { ! 3142: ! 3143: NTSTATUS status; ! 3144: RtlZeroMemory( ! 3145: fullLinkName.Buffer, ! 3146: fullLinkName.MaximumLength ! 3147: ); ! 3148: ! 3149: RtlAppendUnicodeToString( ! 3150: &fullLinkName, ! 3151: L"\\" ! 3152: ); ! 3153: ! 3154: RtlAppendUnicodeStringToString( ! 3155: &fullLinkName, ! 3156: &Extension->ObjectDirectory ! 3157: ); ! 3158: ! 3159: RtlAppendUnicodeToString( ! 3160: &fullLinkName, ! 3161: L"\\" ! 3162: ); ! 3163: ! 3164: RtlAppendUnicodeStringToString( ! 3165: &fullLinkName, ! 3166: &Extension->SymbolicLinkName ! 3167: ); ! 3168: ! 3169: status = IoCreateUnprotectedSymbolicLink( ! 3170: &fullLinkName, ! 3171: &Extension->DeviceName ! 3172: ); ! 3173: ! 3174: if (!NT_SUCCESS(status)) { ! 3175: ! 3176: // ! 3177: // Oh well, couldn't create the symbolic link. ! 3178: // ! 3179: ! 3180: ParDump( ! 3181: PARERRORS, ! 3182: ("PARALLEL: Couldn't create the symbolic link\n" ! 3183: "-------- for port %wZ\n", ! 3184: &Extension->DeviceName) ! 3185: ); ! 3186: ParLogError( ! 3187: Extension->DeviceObject->DriverObject, ! 3188: Extension->DeviceObject, ! 3189: Extension->OriginalController, ! 3190: ParPhysicalZero, ! 3191: 0, ! 3192: 0, ! 3193: 0, ! 3194: 33, ! 3195: status, ! 3196: PAR_NO_SYMLINK_CREATED ! 3197: ); ! 3198: ! 3199: } else { ! 3200: ! 3201: Extension->CreatedSymbolicLink = TRUE; ! 3202: ! 3203: status = RtlWriteRegistryValue( ! 3204: RTL_REGISTRY_DEVICEMAP, ! 3205: L"PARALLEL PORTS", ! 3206: Extension->NtNameForPort.Buffer, ! 3207: REG_SZ, ! 3208: Extension->SymbolicLinkName.Buffer, ! 3209: Extension->SymbolicLinkName.Length+sizeof(WCHAR) ! 3210: ); ! 3211: ! 3212: if (!NT_SUCCESS(status)) { ! 3213: ! 3214: // ! 3215: // Oh well, it didn't work. Just go to cleanup. ! 3216: // ! 3217: ! 3218: ParDump( ! 3219: PARERRORS, ! 3220: ("PARALLEL: Couldn't create the device map entry\n" ! 3221: "-------- for port %wZ\n", ! 3222: &Extension->DeviceName) ! 3223: ); ! 3224: ParLogError( ! 3225: Extension->DeviceObject->DriverObject, ! 3226: Extension->DeviceObject, ! 3227: Extension->OriginalController, ! 3228: ParPhysicalZero, ! 3229: 0, ! 3230: 0, ! 3231: 0, ! 3232: 34, ! 3233: status, ! 3234: PAR_NO_DEVICE_MAP_CREATED ! 3235: ); ! 3236: ! 3237: } ! 3238: ! 3239: } ! 3240: ! 3241: ExFreePool(fullLinkName.Buffer); ! 3242: ! 3243: } ! 3244: ! 3245: } ! 3246: ! 3247: PAR_MEM_COMPARES ! 3248: ParMemCompare( ! 3249: IN PHYSICAL_ADDRESS A, ! 3250: IN ULONG SpanOfA, ! 3251: IN PHYSICAL_ADDRESS B, ! 3252: IN ULONG SpanOfB ! 3253: ) ! 3254: ! 3255: /*++ ! 3256: ! 3257: Routine Description: ! 3258: ! 3259: Compare two phsical address. ! 3260: ! 3261: Arguments: ! 3262: ! 3263: A - One half of the comparison. ! 3264: ! 3265: SpanOfA - In units of bytes, the span of A. ! 3266: ! 3267: B - One half of the comparison. ! 3268: ! 3269: SpanOfB - In units of bytes, the span of B. ! 3270: ! 3271: ! 3272: Return Value: ! 3273: ! 3274: The result of the comparison. ! 3275: ! 3276: --*/ ! 3277: ! 3278: { ! 3279: ! 3280: LARGE_INTEGER a; ! 3281: LARGE_INTEGER b; ! 3282: ! 3283: LARGE_INTEGER lower; ! 3284: ULONG lowerSpan; ! 3285: LARGE_INTEGER higher; ! 3286: ! 3287: a.LowPart = A.LowPart; ! 3288: a.HighPart = A.HighPart; ! 3289: b.LowPart = B.LowPart; ! 3290: b.HighPart = B.HighPart; ! 3291: ! 3292: if (RtlLargeIntegerEqualTo( ! 3293: a, ! 3294: b ! 3295: )) { ! 3296: ! 3297: return AddressesAreEqual; ! 3298: ! 3299: } ! 3300: ! 3301: if (RtlLargeIntegerGreaterThan( ! 3302: a, ! 3303: b ! 3304: )) { ! 3305: ! 3306: higher = a; ! 3307: lower = b; ! 3308: lowerSpan = SpanOfB; ! 3309: ! 3310: } else { ! 3311: ! 3312: higher = b; ! 3313: lower = a; ! 3314: lowerSpan = SpanOfA; ! 3315: ! 3316: } ! 3317: ! 3318: if (RtlLargeIntegerGreaterThanOrEqualTo( ! 3319: RtlLargeIntegerSubtract( ! 3320: higher, ! 3321: lower ! 3322: ), ! 3323: RtlConvertUlongToLargeInteger(lowerSpan) ! 3324: )) { ! 3325: ! 3326: return AddressesAreDisjoint; ! 3327: ! 3328: } ! 3329: ! 3330: return AddressesOverlap; ! 3331: ! 3332: } ! 3333: ! 3334: VOID ! 3335: ParLogError( ! 3336: IN PDRIVER_OBJECT DriverObject, ! 3337: IN PDEVICE_OBJECT DeviceObject OPTIONAL, ! 3338: IN PHYSICAL_ADDRESS P1, ! 3339: IN PHYSICAL_ADDRESS P2, ! 3340: IN ULONG SequenceNumber, ! 3341: IN UCHAR MajorFunctionCode, ! 3342: IN UCHAR RetryCount, ! 3343: IN ULONG UniqueErrorValue, ! 3344: IN NTSTATUS FinalStatus, ! 3345: IN NTSTATUS SpecificIOStatus ! 3346: ) ! 3347: ! 3348: /*++ ! 3349: ! 3350: Routine Description: ! 3351: ! 3352: This routine allocates an error log entry, copies the supplied data ! 3353: to it, and requests that it be written to the error log file. ! 3354: ! 3355: Arguments: ! 3356: ! 3357: DriverObject - A pointer to the driver object for the device. ! 3358: ! 3359: DeviceObject - A pointer to the device object associated with the ! 3360: device that had the error, early in initialization, one may not ! 3361: yet exist. ! 3362: ! 3363: P1,P2 - If phyical addresses for the controller ports involved ! 3364: with the error are available, put them through as dump data. ! 3365: ! 3366: SequenceNumber - A ulong value that is unique to an IRP over the ! 3367: life of the irp in this driver - 0 generally means an error not ! 3368: associated with an irp. ! 3369: ! 3370: MajorFunctionCode - If there is an error associated with the irp, ! 3371: this is the major function code of that irp. ! 3372: ! 3373: RetryCount - The number of times a particular operation has been ! 3374: retried. ! 3375: ! 3376: UniqueErrorValue - A unique long word that identifies the particular ! 3377: call to this function. ! 3378: ! 3379: FinalStatus - The final status given to the irp that was associated ! 3380: with this error. If this log entry is being made during one of ! 3381: the retries this value will be STATUS_SUCCESS. ! 3382: ! 3383: SpecificIOStatus - The IO status for a particular error. ! 3384: ! 3385: Return Value: ! 3386: ! 3387: None. ! 3388: ! 3389: --*/ ! 3390: ! 3391: { ! 3392: PIO_ERROR_LOG_PACKET errorLogEntry; ! 3393: ! 3394: PVOID objectToUse; ! 3395: SHORT dumpToAllocate = 0; ! 3396: ! 3397: if (ARGUMENT_PRESENT(DeviceObject)) { ! 3398: ! 3399: objectToUse = DeviceObject; ! 3400: ! 3401: } else { ! 3402: ! 3403: objectToUse = DriverObject; ! 3404: ! 3405: } ! 3406: ! 3407: if (ParMemCompare( ! 3408: P1, ! 3409: (ULONG)1, ! 3410: ParPhysicalZero, ! 3411: (ULONG)1 ! 3412: ) != AddressesAreEqual) { ! 3413: ! 3414: dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS); ! 3415: ! 3416: } ! 3417: ! 3418: if (ParMemCompare( ! 3419: P2, ! 3420: (ULONG)1, ! 3421: ParPhysicalZero, ! 3422: (ULONG)1 ! 3423: ) != AddressesAreEqual) { ! 3424: ! 3425: dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS); ! 3426: ! 3427: } ! 3428: ! 3429: errorLogEntry = IoAllocateErrorLogEntry( ! 3430: objectToUse, ! 3431: (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + dumpToAllocate) ! 3432: ); ! 3433: ! 3434: if ( errorLogEntry != NULL ) { ! 3435: ! 3436: errorLogEntry->ErrorCode = SpecificIOStatus; ! 3437: errorLogEntry->SequenceNumber = SequenceNumber; ! 3438: errorLogEntry->MajorFunctionCode = MajorFunctionCode; ! 3439: errorLogEntry->RetryCount = RetryCount; ! 3440: errorLogEntry->UniqueErrorValue = UniqueErrorValue; ! 3441: errorLogEntry->FinalStatus = FinalStatus; ! 3442: errorLogEntry->DumpDataSize = dumpToAllocate; ! 3443: ! 3444: if (dumpToAllocate) { ! 3445: ! 3446: RtlCopyMemory( ! 3447: &errorLogEntry->DumpData[0], ! 3448: &P1, ! 3449: sizeof(PHYSICAL_ADDRESS) ! 3450: ); ! 3451: ! 3452: if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) { ! 3453: ! 3454: RtlCopyMemory( ! 3455: ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS), ! 3456: &P2, ! 3457: sizeof(PHYSICAL_ADDRESS) ! 3458: ); ! 3459: ! 3460: } ! 3461: ! 3462: } ! 3463: ! 3464: ! 3465: ! 3466: IoWriteErrorLogEntry(errorLogEntry); ! 3467: ! 3468: } ! 3469: ! 3470: } ! 3471: ! 3472: VOID ! 3473: ParReportResourcesDevice( ! 3474: IN PPAR_DEVICE_EXTENSION Extension, ! 3475: IN BOOLEAN ClaimInterrupt, ! 3476: OUT BOOLEAN *ConflictDetected ! 3477: ) ! 3478: ! 3479: /*++ ! 3480: ! 3481: Routine Description: ! 3482: ! 3483: This routine reports the resources used for a device that ! 3484: is "ready" to run. If some conflict was detected, it doesn't ! 3485: matter, the reources are reported. ! 3486: ! 3487: Arguments: ! 3488: ! 3489: Extension - The device extension of the device we are reporting ! 3490: resources for. ! 3491: ! 3492: ClaimInterrupts - If this was true then we should try to ! 3493: claim the interrupt that goes with this ! 3494: device ! 3495: ! 3496: ConflictDetected - Pointer to a boolean that we will pass ! 3497: to the resource reporting code. ! 3498: ! 3499: Return Value: ! 3500: ! 3501: None. ! 3502: ! 3503: --*/ ! 3504: ! 3505: { ! 3506: ! 3507: PCM_RESOURCE_LIST resourceList; ! 3508: ULONG countOfPartials = 1; ! 3509: ULONG sizeOfResourceList; ! 3510: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial; ! 3511: UNICODE_STRING className; ! 3512: ! 3513: ParDump( ! 3514: PARCONFIG, ! 3515: ("PARALLEL: In ParReportResourcesDevice\n" ! 3516: "-------- for extension %x of port %wZ\n", ! 3517: Extension,&Extension->DeviceName) ! 3518: ); ! 3519: ! 3520: // ! 3521: // The resource list for a device will consist of ! 3522: // ! 3523: // The resource list record itself with a count ! 3524: // of one for the single "built in" full resource ! 3525: // descriptor. ! 3526: // ! 3527: // The built-in full resource descriptor will contain ! 3528: // the bus type and busnumber and the built in partial ! 3529: // resource list. ! 3530: // ! 3531: // The built in partial resource list will have a count of 1 or 2: ! 3532: // ! 3533: // 1) The base register physical address and it's span. ! 3534: // ! 3535: // 2) If the device is using an interrupt then it will ! 3536: // report that resource. ! 3537: // ! 3538: // ! 3539: ! 3540: if (ClaimInterrupt) { ! 3541: ! 3542: countOfPartials = 2; ! 3543: ! 3544: } ! 3545: ! 3546: sizeOfResourceList = sizeof(CM_RESOURCE_LIST) + ! 3547: (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)* ! 3548: (countOfPartials-1)); ! 3549: ! 3550: resourceList = ExAllocatePool( ! 3551: PagedPool, ! 3552: sizeOfResourceList ! 3553: ); ! 3554: ! 3555: if (!resourceList) { ! 3556: ! 3557: // ! 3558: // Oh well, can't allocate the memory. Act as though ! 3559: // we succeeded. ! 3560: // ! 3561: ! 3562: ParLogError( ! 3563: Extension->DeviceObject->DriverObject, ! 3564: Extension->DeviceObject, ! 3565: Extension->OriginalController, ! 3566: ParPhysicalZero, ! 3567: 0, ! 3568: 0, ! 3569: 0, ! 3570: 35, ! 3571: STATUS_SUCCESS, ! 3572: PAR_INSUFFICIENT_RESOURCES ! 3573: ); ! 3574: return; ! 3575: ! 3576: } ! 3577: ! 3578: RtlZeroMemory( ! 3579: resourceList, ! 3580: sizeOfResourceList ! 3581: ); ! 3582: ! 3583: resourceList->Count = 1; ! 3584: ! 3585: resourceList->List[0].InterfaceType = Extension->InterfaceType; ! 3586: resourceList->List[0].BusNumber = Extension->BusNumber; ! 3587: resourceList->List[0].PartialResourceList.Count = countOfPartials; ! 3588: partial = &resourceList->List[0].PartialResourceList.PartialDescriptors[0]; ! 3589: ! 3590: // ! 3591: // Account for the space used by the controller. ! 3592: // ! 3593: ! 3594: partial->Type = CmResourceTypePort; ! 3595: partial->ShareDisposition = CmResourceShareDeviceExclusive; ! 3596: partial->Flags = (USHORT)Extension->AddressSpace; ! 3597: partial->u.Port.Start = Extension->OriginalController; ! 3598: partial->u.Port.Length = Extension->SpanOfController; ! 3599: ! 3600: partial++; ! 3601: ! 3602: if (ClaimInterrupt) { ! 3603: ! 3604: // ! 3605: // Report the interrupt information. ! 3606: // ! 3607: ! 3608: partial->Type = CmResourceTypeInterrupt; ! 3609: ! 3610: if (Extension->InterruptShareable) { ! 3611: ! 3612: partial->ShareDisposition = CmResourceShareShared; ! 3613: ! 3614: } else { ! 3615: ! 3616: partial->ShareDisposition = CmResourceShareDeviceExclusive; ! 3617: ! 3618: } ! 3619: ! 3620: if (Extension->InterruptMode == Latched) { ! 3621: ! 3622: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED; ! 3623: ! 3624: } else { ! 3625: ! 3626: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; ! 3627: ! 3628: } ! 3629: ! 3630: partial->u.Interrupt.Vector = Extension->OriginalVector; ! 3631: partial->u.Interrupt.Level = Extension->OriginalIrql; ! 3632: ! 3633: } ! 3634: ! 3635: RtlInitUnicodeString( ! 3636: &className, ! 3637: L"LOADED PARALLEL DRIVER RESOURCES" ! 3638: ); ! 3639: ! 3640: IoReportResourceUsage( ! 3641: &className, ! 3642: Extension->DeviceObject->DriverObject, ! 3643: NULL, ! 3644: 0, ! 3645: Extension->DeviceObject, ! 3646: resourceList, ! 3647: sizeOfResourceList, ! 3648: FALSE, ! 3649: ConflictDetected ! 3650: ); ! 3651: ! 3652: ExFreePool(resourceList); ! 3653: ! 3654: } ! 3655: ! 3656: VOID ! 3657: ParUnload( ! 3658: IN PDRIVER_OBJECT DriverObject ! 3659: ) ! 3660: ! 3661: /*++ ! 3662: ! 3663: Routine Description: ! 3664: ! 3665: This routine cleans up all of the memory associated with ! 3666: any of the devices belonging to the driver. It will ! 3667: loop through the device list. ! 3668: ! 3669: Arguments: ! 3670: ! 3671: DriverObject - Pointer to the driver object controling all of the ! 3672: devices. ! 3673: ! 3674: Return Value: ! 3675: ! 3676: None. ! 3677: ! 3678: --*/ ! 3679: ! 3680: { ! 3681: ! 3682: PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject; ! 3683: ! 3684: ParDump( ! 3685: PARUNLOAD, ! 3686: ("PARALLEL: In ParUnload\n") ! 3687: ); ! 3688: ! 3689: while (currentDevice) { ! 3690: ! 3691: // ! 3692: // Disable the device from interrupting. ! 3693: // ! 3694: ! 3695: StoreControl( ! 3696: ((PPAR_DEVICE_EXTENSION)currentDevice->DeviceExtension)->Controller, ! 3697: PAR_CONTROL_WR_CONTROL ! 3698: ); ! 3699: ParUnReportResourcesDevice(currentDevice->DeviceExtension); ! 3700: ParCleanupDevice(currentDevice->DeviceExtension); ! 3701: IoDeleteDevice(currentDevice); ! 3702: IoGetConfigurationInformation()->ParallelCount--; ! 3703: ! 3704: currentDevice = DriverObject->DeviceObject; ! 3705: ! 3706: } ! 3707: ! 3708: } ! 3709: ! 3710: VOID ! 3711: ParCleanupDevice( ! 3712: IN PPAR_DEVICE_EXTENSION Extension ! 3713: ) ! 3714: ! 3715: /*++ ! 3716: ! 3717: Routine Description: ! 3718: ! 3719: This routine will deallocate all of the memory used for ! 3720: a particular device. It will also disconnect any resources ! 3721: if need be. ! 3722: ! 3723: Arguments: ! 3724: ! 3725: Extension - Pointer to the device extension which is getting ! 3726: rid of all it's resources. ! 3727: ! 3728: Return Value: ! 3729: ! 3730: None. ! 3731: ! 3732: --*/ ! 3733: ! 3734: { ! 3735: ! 3736: ParDump( ! 3737: PARUNLOAD, ! 3738: ("PARALLEL: in ParCleanupDevice for extension: %x\n",Extension) ! 3739: ); ! 3740: ! 3741: if (Extension) { ! 3742: ! 3743: // ! 3744: // Stop the timer, we don't need it. ! 3745: // ! 3746: IoStopTimer(Extension->DeviceObject); ! 3747: ! 3748: // ! 3749: // Disconnect the interrupt object so that some spurious ! 3750: // interrupt doesn't cause us to dereference some memory we've ! 3751: // already given up. ! 3752: // ! 3753: ! 3754: if (!Extension->UsingATimer) { ! 3755: ! 3756: if (Extension->Interrupt) { ! 3757: ! 3758: ParDump( ! 3759: PARUNLOAD, ! 3760: ("PARALLEL: Extension has interrupt %x\n",Extension) ! 3761: ); ! 3762: IoDisconnectInterrupt(Extension->Interrupt); ! 3763: ! 3764: } ! 3765: ! 3766: } ! 3767: ! 3768: // ! 3769: // Get rid of all external naming as well as removing ! 3770: // the device map entry. ! 3771: // ! 3772: ! 3773: ParCleanupExternalNaming(Extension); ! 3774: ! 3775: // ! 3776: // Delallocate the memory for the various names. ! 3777: // NOTE: If we have an extension - Then we must ! 3778: // have a device name stored away. Which is *not* ! 3779: // true for the other names. ! 3780: // ! 3781: ! 3782: ExFreePool(Extension->DeviceName.Buffer); ! 3783: ! 3784: if (Extension->ObjectDirectory.Buffer) { ! 3785: ! 3786: ExFreePool(Extension->ObjectDirectory.Buffer); ! 3787: ! 3788: } ! 3789: ! 3790: if (Extension->NtNameForPort.Buffer) { ! 3791: ! 3792: ExFreePool(Extension->NtNameForPort.Buffer); ! 3793: ! 3794: } ! 3795: ! 3796: if (Extension->SymbolicLinkName.Buffer) { ! 3797: ! 3798: ExFreePool(Extension->SymbolicLinkName.Buffer); ! 3799: ! 3800: } ! 3801: ! 3802: // ! 3803: // If necessary, unmap the device registers. ! 3804: // ! 3805: ! 3806: if (Extension->UnMapRegisters) { ! 3807: ! 3808: MmUnmapIoSpace( ! 3809: Extension->Controller, ! 3810: Extension->SpanOfController ! 3811: ); ! 3812: ! 3813: } ! 3814: ! 3815: } ! 3816: ! 3817: } ! 3818: ! 3819: VOID ! 3820: ParCleanupExternalNaming( ! 3821: IN PPAR_DEVICE_EXTENSION Extension ! 3822: ) ! 3823: ! 3824: /*++ ! 3825: ! 3826: Routine Description: ! 3827: ! 3828: This routine will be used to delete a symbolic link ! 3829: to the driver name in the given object directory. ! 3830: ! 3831: It will also delete an entry in the device map for ! 3832: this device. ! 3833: ! 3834: Arguments: ! 3835: ! 3836: Extension - Pointer to the device extension. ! 3837: ! 3838: Return Value: ! 3839: ! 3840: None. ! 3841: ! 3842: --*/ ! 3843: ! 3844: { ! 3845: ! 3846: UNICODE_STRING fullLinkName; ! 3847: ! 3848: ParDump( ! 3849: PARUNLOAD, ! 3850: ("PARALLEL: In ParCleanupExternalNaming for\n" ! 3851: "-------- extension: %x of port %wZ\n", ! 3852: Extension,&Extension->DeviceName) ! 3853: ); ! 3854: ! 3855: // ! 3856: // We're cleaning up here. One reason we're cleaning up ! 3857: // is that we couldn't allocate space for the directory ! 3858: // name or the symbolic link. ! 3859: // ! 3860: ! 3861: if (Extension->ObjectDirectory.Buffer && ! 3862: Extension->SymbolicLinkName.Buffer && ! 3863: Extension->CreatedSymbolicLink) { ! 3864: ! 3865: // ! 3866: // Form the full symbolic link name we wish to create. ! 3867: // ! 3868: ! 3869: RtlInitUnicodeString( ! 3870: &fullLinkName, ! 3871: NULL ! 3872: ); ! 3873: ! 3874: // ! 3875: // Allocate some pool for the name. ! 3876: // ! 3877: ! 3878: fullLinkName.MaximumLength = (sizeof(L"\\")*2) + ! 3879: Extension->ObjectDirectory.Length+ ! 3880: Extension->SymbolicLinkName.Length+ ! 3881: sizeof(WCHAR); ! 3882: ! 3883: fullLinkName.Buffer = ExAllocatePool( ! 3884: PagedPool, ! 3885: fullLinkName.MaximumLength ! 3886: ); ! 3887: ! 3888: if (!fullLinkName.Buffer) { ! 3889: ! 3890: // ! 3891: // Couldn't allocate space for the name. Just go on ! 3892: // to the device map stuff. ! 3893: // ! 3894: ! 3895: ParLogError( ! 3896: Extension->DeviceObject->DriverObject, ! 3897: Extension->DeviceObject, ! 3898: Extension->OriginalController, ! 3899: ParPhysicalZero, ! 3900: 0, ! 3901: 0, ! 3902: 0, ! 3903: 36, ! 3904: STATUS_SUCCESS, ! 3905: PAR_INSUFFICIENT_RESOURCES ! 3906: ); ! 3907: ParDump( ! 3908: PARERRORS, ! 3909: ("PARALLEL: Couldn't allocate space for the symbolic \n" ! 3910: "-------- name for creating the link\n" ! 3911: "-------- for port %wZ on cleanup\n", ! 3912: &Extension->DeviceName) ! 3913: ); ! 3914: ! 3915: } else { ! 3916: ! 3917: RtlZeroMemory( ! 3918: fullLinkName.Buffer, ! 3919: fullLinkName.MaximumLength ! 3920: ); ! 3921: ! 3922: RtlAppendUnicodeToString( ! 3923: &fullLinkName, ! 3924: L"\\" ! 3925: ); ! 3926: ! 3927: RtlAppendUnicodeStringToString( ! 3928: &fullLinkName, ! 3929: &Extension->ObjectDirectory ! 3930: ); ! 3931: ! 3932: RtlAppendUnicodeToString( ! 3933: &fullLinkName, ! 3934: L"\\" ! 3935: ); ! 3936: ! 3937: RtlAppendUnicodeStringToString( ! 3938: &fullLinkName, ! 3939: &Extension->SymbolicLinkName ! 3940: ); ! 3941: ! 3942: IoDeleteSymbolicLink(&fullLinkName); ! 3943: ! 3944: ExFreePool(fullLinkName.Buffer); ! 3945: ! 3946: } ! 3947: ! 3948: // ! 3949: // We're cleaning up here. One reason we're cleaning up ! 3950: // is that we couldn't allocate space for the NtNameOfPort. ! 3951: // ! 3952: ! 3953: if (Extension->NtNameForPort.Buffer) { ! 3954: ! 3955: NTSTATUS status; ! 3956: ! 3957: status = RtlDeleteRegistryValue( ! 3958: RTL_REGISTRY_DEVICEMAP, ! 3959: L"PARALLEL PORTS", ! 3960: Extension->NtNameForPort.Buffer ! 3961: ); ! 3962: ! 3963: if (!NT_SUCCESS(status)) { ! 3964: ! 3965: ParLogError( ! 3966: Extension->DeviceObject->DriverObject, ! 3967: Extension->DeviceObject, ! 3968: Extension->OriginalController, ! 3969: ParPhysicalZero, ! 3970: 0, ! 3971: 0, ! 3972: 0, ! 3973: 37, ! 3974: status, ! 3975: PAR_NO_DEVICE_MAP_DELETED ! 3976: ); ! 3977: ParDump( ! 3978: PARERRORS, ! 3979: ("PARALLEL: Couldn't delete value entry %wZ\n", ! 3980: &Extension->DeviceName) ! 3981: ); ! 3982: ! 3983: } ! 3984: ! 3985: } ! 3986: ! 3987: } ! 3988: ! 3989: } ! 3990: ! 3991: VOID ! 3992: ParUnReportResourcesDevice( ! 3993: IN PPAR_DEVICE_EXTENSION Extension ! 3994: ) ! 3995: ! 3996: /*++ ! 3997: ! 3998: Routine Description: ! 3999: ! 4000: Purge the resources for this particular device. ! 4001: ! 4002: Arguments: ! 4003: ! 4004: Extension - The device extension of the device we are *un*reporting ! 4005: resources for. ! 4006: ! 4007: Return Value: ! 4008: ! 4009: None. ! 4010: ! 4011: --*/ ! 4012: ! 4013: { ! 4014: ! 4015: CM_RESOURCE_LIST resourceList; ! 4016: ULONG sizeOfResourceList = 0; ! 4017: UNICODE_STRING className; ! 4018: BOOLEAN junkBoolean; ! 4019: ! 4020: ParDump( ! 4021: PARUNLOAD, ! 4022: ("PARALLEL: In ParUnreportResourcesDevice\n" ! 4023: "-------- for extension %x of port %wZ\n", ! 4024: Extension,&Extension->DeviceName) ! 4025: ); ! 4026: RtlZeroMemory( ! 4027: &resourceList, ! 4028: sizeof(CM_RESOURCE_LIST) ! 4029: ); ! 4030: ! 4031: resourceList.Count = 0; ! 4032: ! 4033: RtlInitUnicodeString( ! 4034: &className, ! 4035: L"LOADED PARALLEL DRIVER RESOURCES" ! 4036: ); ! 4037: ! 4038: IoReportResourceUsage( ! 4039: &className, ! 4040: Extension->DeviceObject->DriverObject, ! 4041: NULL, ! 4042: 0, ! 4043: Extension->DeviceObject, ! 4044: &resourceList, ! 4045: sizeof(CM_RESOURCE_LIST), ! 4046: FALSE, ! 4047: &junkBoolean ! 4048: ); ! 4049: ! 4050: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.