Annotation of ntddk/src/comm/oldpar/initunlo.c, revision 1.1

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:             &paramTable[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:                             &paramTable[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:         &parametersPath,
        !          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:         &parametersPath,
        !          2035:         RegistryPath
        !          2036:         );
        !          2037:     RtlAppendUnicodeToString(
        !          2038:         &parametersPath,
        !          2039:         L"\\"
        !          2040:         );
        !          2041:     RtlAppendUnicodeToString(
        !          2042:         &parametersPath,
        !          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:              &parametersPath)
        !          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:         &parametersAttributes,
        !          2088:         &parametersPath,
        !          2089:         OBJ_CASE_INSENSITIVE,
        !          2090:         NULL,
        !          2091:         NULL
        !          2092:         );
        !          2093: 
        !          2094:     if (!NT_SUCCESS(ZwOpenKey(
        !          2095:                        &parametersKey,
        !          2096:                        MAXIMUM_ALLOWED,
        !          2097:                        &parametersAttributes
        !          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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.