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

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

unix.superglobalmegacorp.com

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