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

unix.superglobalmegacorp.com

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