Annotation of ntddk/src/scsi/qic117/q117i_nt.c, revision 1.1

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1993 - Colorado Memory Systems, Inc.
        !             4: All Rights Reserved
        !             5: 
        !             6: Module Name:
        !             7: 
        !             8:     q117i_nt.c
        !             9: 
        !            10: Abstract:
        !            11: 
        !            12:     NT device driver entry point,  NT interface routines,
        !            13:     and thread for low-level irp functions.
        !            14: 
        !            15: Revision History:
        !            16: 
        !            17: 
        !            18: 
        !            19: 
        !            20: --*/
        !            21: 
        !            22: #include "ntddk.h"                        // various NT definitions
        !            23: #include "ntdddisk.h"                    // disk device driver I/O control codes
        !            24: #include "common.h"
        !            25: #include "drvtask.h"                    // this driver's data declarations
        !            26: #include "mt1defs.h"                    // this driver's data declarations
        !            27: #include "mt1strc.h"                    // this driver's data declarations
        !            28: #include "q117data.h"               // this driver's data declarations
        !            29: #include "hilevel.h"
        !            30: 
        !            31: //
        !            32: // This is the actual definition of FloppyDebugLevel.
        !            33: // Note that it is only defined if this is a "debug"
        !            34: // build.
        !            35: //
        !            36: #if DBG
        !            37: // extern ULONG QIC117DebugLevel = QIC117DBGP | QIC117WARN | QIC117INFO |
        !            38: //                                QIC117SHOWTD | QIC117SHOWQD |
        !            39: //                                QIC117SHOWPOLL | QIC117STOP |
        !            40: //                                QIC117MAKEBAD | QIC117SHOWBAD |
        !            41: //                                QIC117DRVSTAT;
        !            42: 
        !            43: extern ULONG QIC117DebugLevel = 0x00000000;
        !            44: //extern ULONG QIC117DebugLevel =  QIC117SHOWTD | QIC117DBGP | QIC117WARN | QIC117INFO;
        !            45: 
        !            46: #endif
        !            47: 
        !            48: #ifdef ALLOC_PRAGMA
        !            49: #pragma alloc_text(init,DriverEntry)
        !            50: #endif
        !            51: 
        !            52: 
        !            53: NTSTATUS
        !            54: DriverEntry(
        !            55:    IN OUT PDRIVER_OBJECT DriverObject,
        !            56:    IN PUNICODE_STRING RegistryPath
        !            57:    )
        !            58: 
        !            59: /*++
        !            60: 
        !            61: Routine Description:
        !            62: 
        !            63:    This routine is the driver's entry point, called by the I/O system
        !            64:    to load the driver. This routine can be called any number of times,
        !            65:    as long as the IO system and the configuration manager conspire to
        !            66:    give it an unmanaged controller to support at each call.    It could
        !            67:    also be called a single time and given all of the controllers at
        !            68:    once.
        !            69: 
        !            70:    It initializes the passed-in driver object, calls the configuration
        !            71:    manager to learn about the devices that it is to support, and for
        !            72:    each controller to be supported it calls a routine to initialize the
        !            73:    controller (and all drives attached to it).
        !            74: 
        !            75: Arguments:
        !            76: 
        !            77:    DriverObject - a pointer to the object that represents this device
        !            78:    driver.
        !            79: 
        !            80: Return Value:
        !            81: 
        !            82:    If we successfully initialize at least one drive, STATUS_SUCCESS is
        !            83:    returned.
        !            84: 
        !            85:    If we don't (because the configuration manager returns an error, or
        !            86:    the configuration manager says that there are no controllers or
        !            87:    drives to support, or no controllers or drives can be successfully
        !            88:    initialized), then the last error encountered is propogated.
        !            89: 
        !            90: --*/
        !            91: 
        !            92: {
        !            93:    PCONFIG_DATA configData;            // pointer to config mgr's returned data
        !            94:    NTSTATUS ntStatus;
        !            95:    UCHAR controllerNumber;
        !            96:    BOOLEAN partlySuccessful = FALSE;   // TRUE if any controller init'd properly
        !            97: 
        !            98:    UNREFERENCED_PARAMETER(RegistryPath);
        !            99:    CheckedDump(QIC117INFO,( "DriverEntry...\n" ));
        !           100: 
        !           101:    //
        !           102:    // Ask configuration manager for information on the hardware that
        !           103:    // we're supposed to support.
        !           104:    //
        !           105: 
        !           106: #if DBG
        !           107: 
        !           108: //    DbgBreakPoint();
        !           109: 
        !           110: #endif
        !           111: 
        !           112:    ntStatus = Q117iGetConfigurationInformation( &configData );
        !           113: 
        !           114:    //
        !           115:    // If Q117iGetConfigurationInformation() failed, just exit and propogate
        !           116:    // the error.   If it said that there are no controllers to support,
        !           117:    // return an error.
        !           118:    // Otherwise, try to init the controllers.  If at least one succeeds,
        !           119:    // return STATUS_SUCCESS, otherwise return the last error.
        !           120:    //
        !           121: 
        !           122:    configData->FloppyTapeCount = 0;
        !           123: 
        !           124:    if ( NT_SUCCESS( ntStatus ) ) {
        !           125: 
        !           126:       //
        !           127:       // Call Q117iInitializeController() for each controller (and its
        !           128:       // attached drives) that we're supposed to support.
        !           129:       //
        !           130:       // Return success if we successfully initialize at least one
        !           131:       // device; propogate error otherwise.   Set an error first in
        !           132:       // case there aren't any controllers.
        !           133:       //
        !           134: 
        !           135:       ntStatus = STATUS_NO_SUCH_DEVICE;
        !           136: 
        !           137:       for ( controllerNumber = 0;
        !           138:                controllerNumber < configData->NumberOfControllers;
        !           139:                controllerNumber++ ) {
        !           140: 
        !           141:             ntStatus = Q117iInitializeController(
        !           142:                configData,
        !           143:                controllerNumber,
        !           144:                DriverObject,
        !           145:                RegistryPath );
        !           146: 
        !           147:             if ( NT_SUCCESS( ntStatus ) ) {
        !           148: 
        !           149:                partlySuccessful = TRUE;
        !           150:             }
        !           151:       }
        !           152: 
        !           153:       if ( partlySuccessful ) {
        !           154: 
        !           155:             ntStatus = STATUS_SUCCESS;
        !           156: 
        !           157:             //
        !           158:             // Initialize the driver object with this driver's entry points.
        !           159:             //
        !           160: 
        !           161:             DriverObject->MajorFunction[IRP_MJ_READ] =
        !           162:                q117Read;
        !           163:             DriverObject->MajorFunction[IRP_MJ_WRITE] =
        !           164:                q117Write;
        !           165:             DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
        !           166:                q117DeviceControl;
        !           167:             DriverObject->MajorFunction[IRP_MJ_CREATE] =
        !           168:                q117Create;
        !           169:             DriverObject->MajorFunction[IRP_MJ_CLOSE] =
        !           170:                q117Close;
        !           171:             //DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
        !           172:             //    q117Cleanup;
        !           173:             DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
        !           174:                Q117iTapeDispatchInternalDeviceControl;
        !           175:       }
        !           176:    }
        !           177: 
        !           178:    //
        !           179:    // NOTE: FUTURE delete configdata, if config mgr design calls for it
        !           180:    //
        !           181: 
        !           182: #if DBG
        !           183: 
        !           184:    if ( !NT_SUCCESS( ntStatus ) ) {
        !           185: 
        !           186:       CheckedDump((QIC117INFO | QIC117DBGP),( "q117i: exiting with error %lx\n", ntStatus ));
        !           187:    }
        !           188: 
        !           189: #endif
        !           190: 
        !           191:    if (configData) {
        !           192: 
        !           193:       ExFreePool(configData);
        !           194: 
        !           195:    }
        !           196: 
        !           197:    return ntStatus;
        !           198: }
        !           199: 
        !           200: NTSTATUS
        !           201: Q117iTapeDispatchInternalDeviceControl(
        !           202:    IN PDEVICE_OBJECT DeviceObject,
        !           203:    IN OUT PIRP Irp
        !           204:    )
        !           205: 
        !           206: /*++
        !           207: 
        !           208: Routine Description:
        !           209: 
        !           210:    This routine is called by the I/O system to perform a device I/O
        !           211:    control function.
        !           212: 
        !           213: Arguments:
        !           214: 
        !           215:    DeviceObject - a pointer to the object that represents the device
        !           216:    that I/O is to be done on.
        !           217: 
        !           218:    Irp - a pointer to the I/O Request Packet for this request.
        !           219: 
        !           220: Return Value:
        !           221: 
        !           222:    STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
        !           223:    STATUS_INVALID_DEVICE_REQUEST otherwise.
        !           224: 
        !           225: --*/
        !           226: 
        !           227: {
        !           228:    PIO_STACK_LOCATION irpSp;
        !           229:    NTSTATUS ntStatus;
        !           230:    PTAPE_EXTENSION tapeExtension;
        !           231: 
        !           232:    tapeExtension = DeviceObject->DeviceExtension;
        !           233: 
        !           234:    irpSp = IoGetCurrentIrpStackLocation( Irp );
        !           235: 
        !           236: 
        !           237:    switch( irpSp->Parameters.DeviceIoControl.IoControlCode) {
        !           238: 
        !           239:    case IOCTL_QIC117_CLEAR_QUEUE:
        !           240: 
        !           241:    (VOID) KeResetEvent( &tapeExtension->QControllerData->ClearQueueEvent );
        !           242: 
        !           243:    tapeExtension->QControllerData->ClearQueue = TRUE;
        !           244:    tapeExtension->QControllerData->AbortRequested = TRUE;
        !           245: 
        !           246:             IoMarkIrpPending( Irp );
        !           247: 
        !           248:       (VOID) ExInterlockedInsertTailList(
        !           249:             &tapeExtension->QControllerData->ListEntry,
        !           250:             &Irp->Tail.Overlay.ListEntry,
        !           251:             &tapeExtension->QControllerData->ListSpinLock );
        !           252: 
        !           253:       (VOID) KeReleaseSemaphore(
        !           254:             &tapeExtension->QControllerData->RequestSemaphore,
        !           255:             (KPRIORITY) 0,
        !           256:             1,
        !           257:             FALSE );
        !           258: 
        !           259: 
        !           260:    (VOID) KeWaitForSingleObject(
        !           261:             (PVOID) &tapeExtension->QControllerData->ClearQueueEvent,
        !           262:             Suspended,
        !           263:             KernelMode,
        !           264:             FALSE,
        !           265:             (PLARGE_INTEGER) NULL );
        !           266: 
        !           267:    tapeExtension->QControllerData->ClearQueue = FALSE;
        !           268:       ntStatus = STATUS_SUCCESS;
        !           269: 
        !           270:       break;
        !           271: 
        !           272:    case IOCTL_QIC117_DRIVE_REQUEST:
        !           273: 
        !           274:             IoMarkIrpPending( Irp );
        !           275: 
        !           276:       (VOID) ExInterlockedInsertTailList(
        !           277:             &tapeExtension->QControllerData->ListEntry,
        !           278:             &Irp->Tail.Overlay.ListEntry,
        !           279:             &tapeExtension->QControllerData->ListSpinLock );
        !           280: 
        !           281:       (VOID) KeReleaseSemaphore(
        !           282:             &tapeExtension->QControllerData->RequestSemaphore,
        !           283:             (KPRIORITY) 0,
        !           284:             1,
        !           285:             FALSE );
        !           286: 
        !           287:       ntStatus = STATUS_PENDING;
        !           288:       break;
        !           289: 
        !           290:    default:
        !           291:       CheckedDump(QIC117DBGP,("q117i: invalid device request %x\n",
        !           292:       irpSp->Parameters.DeviceIoControl.IoControlCode ));
        !           293: 
        !           294:       ntStatus = STATUS_INVALID_DEVICE_REQUEST;
        !           295: 
        !           296:    }
        !           297: 
        !           298:    return ntStatus;
        !           299: }
        !           300: 
        !           301: BOOLEAN
        !           302: Q117iTapeInterruptService(
        !           303:    IN PKINTERRUPT Interrupt,
        !           304:    IN OUT PVOID Context
        !           305:    )
        !           306: 
        !           307: /*++
        !           308: 
        !           309: Routine Description:
        !           310: 
        !           311:    This routine is called at DIRQL by the system when the controller
        !           312:    interrupts.
        !           313: 
        !           314: Arguments:
        !           315: 
        !           316:    Interrupt - a pointer to the interrupt object.
        !           317: 
        !           318:    Context - a pointer to our controller data area for the controller
        !           319:    that interrupted.   (This was set up by the call to
        !           320:    IoConnectInterrupt).
        !           321: 
        !           322: Return Value:
        !           323: 
        !           324:    Normally returns TRUE, but will return FALSE if this interrupt was
        !           325:    not expected.
        !           326: 
        !           327: --*/
        !           328: 
        !           329: {
        !           330:     PTAPE_CONTROLLER_DATA controllerData;
        !           331:     PDEVICE_OBJECT currentDeviceObject;
        !           332:     SHORT i;
        !           333:     UCHAR statusByte;
        !           334:     BOOLEAN controllerStateError = FALSE;
        !           335: 
        !           336:     UNREFERENCED_PARAMETER( Interrupt );
        !           337: 
        !           338:     KeStallExecutionProcessor(10);
        !           339: 
        !           340:     controllerData = (PTAPE_CONTROLLER_DATA) Context;
        !           341: 
        !           342:     //
        !           343:     // CurrentDeviceObject is set to the device object that is
        !           344:     // expecting an interrupt.
        !           345:     //
        !           346: 
        !           347:     currentDeviceObject = controllerData->CurrentDeviceObject;
        !           348: 
        !           349:     if (currentDeviceObject == NULL &&
        !           350:         !controllerData->CurrentInterrupt) {
        !           351: 
        !           352:         return FALSE;
        !           353: 
        !           354:     } else {
        !           355: 
        !           356:                        controllerData->CurrentDeviceObject = NULL;
        !           357: 
        !           358:                        if ( controllerData->CommandHasResultPhase ) {
        !           359: 
        !           360:                                 //
        !           361:                                 // Result phase of previous command.    (Note that we can't trust
        !           362:                                 // the CMD_BUSY bit in the status register to tell us whether
        !           363:                                 // there's result bytes or not; it's sometimes wrong).
        !           364:                                 // By reading the first result byte, we reset the interrupt.
        !           365:                                 // The other result bytes will be read by a thread.
        !           366:                                 // Note that we want to do this even if the interrupt is
        !           367:                                 // unexpected, to make sure the interrupt is dismissed.
        !           368:                                 //
        !           369: 
        !           370:                                 if ( ( READ_CONTROLLER( &controllerData->FDC_Addr->MSDSR.msr )
        !           371:                                          & (MSR_RQM | MSR_DIO) ) == (MSR_RQM | MSR_DIO) ) {
        !           372: 
        !           373:                                          controllerData->FifoByte =
        !           374:                                                        READ_CONTROLLER( &controllerData->FDC_Addr->dr );
        !           375: 
        !           376:                                 } else {
        !           377: 
        !           378:                                          //
        !           379:                                          // Should never get here.   If we do, DON'T wake up the thread;
        !           380:                                          // let it time out and reset the controller, or let another
        !           381:                                          // interrupt handle this.
        !           382:                                          //
        !           383: 
        !           384:                                          CheckedDump(QIC117DBGP,( "q117i: controller not ready to be read in ISR\n" ));
        !           385: 
        !           386:                                          controllerStateError = TRUE;
        !           387: 
        !           388:                                 }
        !           389: 
        !           390:                        } else {
        !           391: 
        !           392:                                 //
        !           393:                                 // Previous command doesn't have a result phase. To read how it
        !           394:                                 // completed, issue a sense interrupt command.  Don't read
        !           395:                                 // the result bytes from the sense interrupt; that is the
        !           396:                                 // responsibility of the calling thread.
        !           397:                                 // Note that we want to do this even if the interrupt is
        !           398:                                 // unexpected, to make sure the interrupt is dismissed.
        !           399:                                 //
        !           400: 
        !           401:                                 i = FDC_MSR_RETRIES;
        !           402: 
        !           403:                                 do {
        !           404: 
        !           405:                                          if ((READ_CONTROLLER(&controllerData->FDC_Addr->MSDSR.msr) & (MSR_RQM | MSR_DIO)) == MSR_RQM) {
        !           406: 
        !           407:                                                                 break;
        !           408: 
        !           409:                                          }
        !           410: 
        !           411:                                          KeStallExecutionProcessor( 12 );
        !           412: 
        !           413:                                 } while (--i > 0);
        !           414: 
        !           415:                                 if (i != 0) {
        !           416: 
        !           417:                                          WRITE_CONTROLLER(
        !           418:                                          &controllerData->FDC_Addr->dr,
        !           419:                                          FDC_SNS_INT );
        !           420: 
        !           421:                                          KeStallExecutionProcessor( 12 );
        !           422: 
        !           423:                                          //
        !           424:                                          // Wait for the controller to ACK the SenseInterrupt command, by
        !           425:                                          // showing busy.    On very fast machines we can end up running
        !           426:                                          // driver's system-thread before the controller has had time to
        !           427:                                          // set the busy bit.
        !           428:                                          //
        !           429: 
        !           430:                                          for (i = FDC_MSR_RETRIES; i; i--) {
        !           431: 
        !           432:                                                        if (READ_CONTROLLER(&controllerData->FDC_Addr->MSDSR.msr) & MSR_CB)
        !           433:                                                                          break;
        !           434: 
        !           435:                                                        KeStallExecutionProcessor( 12 );
        !           436: 
        !           437:                                          }
        !           438: 
        !           439:                                          // Need to optimize the previous section
        !           440: 
        !           441:                                          if ( currentDeviceObject == NULL ) {
        !           442: 
        !           443:                                                        //
        !           444:                                                        // This is an unexpected interrupt, so nobody's going to
        !           445:                                                        // read the result bytes.   Read them now.
        !           446:                                                        //
        !           447: 
        !           448:                                                        READ_CONTROLLER( &controllerData->FDC_Addr->dr );
        !           449:                                                        READ_CONTROLLER( &controllerData->FDC_Addr->dr );
        !           450: 
        !           451:                                          }
        !           452: 
        !           453:                                 } else {
        !           454: 
        !           455:                                          //
        !           456:                                          // Shouldn't get here.  If we do, DON'T wake up the thread;
        !           457:                                          // let it time out and reset the controller, or let another
        !           458:                                          // interrupt take care of it.
        !           459:                                          //
        !           460: 
        !           461:                                          CheckedDump(QIC117DBGP,( "q117i: no result, but can't write SenseIntr\n" ));
        !           462: 
        !           463:                                          controllerStateError = TRUE;
        !           464:                                 }
        !           465: 
        !           466:                        }
        !           467: 
        !           468:                        //
        !           469:                        // We've written to the controller, and we're about to leave.   On
        !           470:                        // machines with levelsensitive interrupts, we'll get another interrupt
        !           471:                        // if we RETURN before the port is flushed. To make sure that doesn't
        !           472:                        // happen, we'll do a read here.
        !           473:                        //
        !           474: 
        !           475:                        statusByte = READ_CONTROLLER( &controllerData->FDC_Addr->MSDSR.msr );
        !           476: 
        !           477:                        //
        !           478:                        // Let the interrupt settle.
        !           479:                        //
        !           480: 
        !           481:                        KeStallExecutionProcessor(10);
        !           482: 
        !           483:                        if ( currentDeviceObject == NULL ) {
        !           484: 
        !           485:                                 //
        !           486:                                 // We didn't expect this interrupt. We've dismissed it just
        !           487:                                 // in case, but now return FALSE withOUT waking up the thread.
        !           488:                                 //
        !           489: 
        !           490:                                 CheckedDump(QIC117DBGP,( "q117i: unexpected interrupt\n" ));
        !           491: 
        !           492:                                 return FALSE;
        !           493: 
        !           494:                        }
        !           495: 
        !           496:                        if ( !controllerStateError ) {
        !           497: 
        !           498:                                 //
        !           499:                                 // Request a DPC for execution later to get the remainder of the
        !           500:                                 // floppy state.
        !           501:                                 //
        !           502: 
        !           503:                                 IoRequestDpc(
        !           504:                                 currentDeviceObject,
        !           505:                                 currentDeviceObject->CurrentIrp,
        !           506:                                 (PVOID) NULL );
        !           507: 
        !           508:                        }
        !           509: 
        !           510:                        return TRUE;
        !           511: 
        !           512:     }
        !           513: 
        !           514: }
        !           515: 
        !           516: VOID
        !           517: Q117iTapeDeferredProcedure(
        !           518:    IN PKDPC Dpc,
        !           519:    IN PVOID DeferredContext,
        !           520:    IN PVOID SystemArgument1,
        !           521:    IN PVOID SystemArgument2
        !           522:    )
        !           523: 
        !           524: /*++
        !           525: 
        !           526: Routine Description:
        !           527: 
        !           528:    This routine is called at DISPATCH_LEVEL by the system at the
        !           529:    request of Q117iTapeInterruptService(). It simply sets the interrupt
        !           530:    event, which wakes up the floppy thread.
        !           531: 
        !           532: Arguments:
        !           533: 
        !           534:    Dpc - a pointer to the DPC object used to invoke this routine.
        !           535: 
        !           536:    DeferredContext - a pointer to the device object associated with this
        !           537:    DPC.
        !           538: 
        !           539:    SystemArgument1 - unused.
        !           540: 
        !           541:    SystemArgument2 - unused.
        !           542: 
        !           543: Return Value:
        !           544: 
        !           545:    None.
        !           546: 
        !           547: --*/
        !           548: 
        !           549: {
        !           550:     PDEVICE_OBJECT deviceObject;
        !           551:     PTAPE_EXTENSION tapeExtension;
        !           552:     union format_header hdrData;      // sector id data
        !           553:     FDC_STATUS fStat;                 // FDC status response
        !           554:     SHORT statLength;                 // length of FDC status response
        !           555:     ULONG  *hdrPtr;                   // pointer to sector id data for format
        !           556:     PHYSICAL_ADDRESS val;
        !           557:     struct seek_cmd seek;
        !           558:     struct fdc_result result;
        !           559:     SHORT i;
        !           560: 
        !           561:    UNREFERENCED_PARAMETER( Dpc );
        !           562:    UNREFERENCED_PARAMETER( SystemArgument1 );
        !           563:    UNREFERENCED_PARAMETER( SystemArgument2 );
        !           564: 
        !           565:    deviceObject = (PDEVICE_OBJECT) DeferredContext;
        !           566:    tapeExtension = deviceObject->DeviceExtension;
        !           567: 
        !           568: 
        !           569:     if (!tapeExtension->QControllerData->StartFormatMode) {
        !           570: 
        !           571:         (VOID) KeSetEvent(
        !           572:                                &tapeExtension->QControllerData->InterruptEvent,
        !           573:                                (KPRIORITY) 0,
        !           574:                                FALSE );
        !           575: 
        !           576:          } else {
        !           577: 
        !           578:                        //
        !           579:                        // Format all of the segments on the tape track.  Whenever a boundary
        !           580:                        // condition is reached (e.g. sectors > sectors per floppy track)
        !           581:                        // update the sector id information as necessary.
        !           582:                        //
        !           583: 
        !           584:                        if (tapeExtension->FmtOp.Segments == (SHORT)tapeExtension->TapeParms.SegTtrack) {
        !           585: 
        !           586:                                 IoFlushAdapterBuffers(
        !           587:                                          tapeExtension->QControllerData->AdapterObject,
        !           588:                                          tapeExtension->FmtOp.MdlAddress,
        !           589:                                          tapeExtension->QControllerData->MapRegisterBase,
        !           590:                                          (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
        !           591:                                                        + tapeExtension->RdWrOp.BytesTransferredSoFar ),
        !           592:                                          tapeExtension->RdWrOp.TotalBytesOfTransfer,
        !           593:                                          DMA_READ );
        !           594: 
        !           595:                                 if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
        !           596:                                                                          tapeExtension,
        !           597:                                                                          (CHAR *)&fStat,
        !           598:                                                                          &statLength)) == NoErr) {
        !           599: 
        !           600:                                          if (fStat.ST0 & ST0_IC) {
        !           601: 
        !           602:                                                        tapeExtension->FmtOp.retval = TimeOut;
        !           603: 
        !           604:                      (VOID) KeSetEvent(
        !           605:                                             &tapeExtension->QControllerData->InterruptEvent,
        !           606:                                             (KPRIORITY) 0,
        !           607:                                             FALSE );
        !           608: 
        !           609:                                          }
        !           610: 
        !           611:                                 }
        !           612: 
        !           613:                                 tapeExtension->QControllerData->StartFormatMode = FALSE;
        !           614: 
        !           615:                                 if (tapeExtension->QControllerData->FDC_Pcn < 128) {
        !           616: 
        !           617:                                          seek.NCN = tapeExtension->QControllerData->FDC_Pcn + Report_Status;
        !           618: 
        !           619:                                 } else {
        !           620: 
        !           621:                                          seek.NCN = tapeExtension->QControllerData->FDC_Pcn - Report_Status;
        !           622: 
        !           623:                                 }
        !           624: 
        !           625:                                 seek.cmd = 0x0f;
        !           626:                                 seek.drive = (UCHAR)tapeExtension->DriveParms.DriveSelect;
        !           627:                                 tapeExtension->FmtOp.NCN = seek.NCN;
        !           628: 
        !           629:                       tapeExtension->QControllerData->CurrentDeviceObject =
        !           630:                                     tapeExtension->QDeviceObject;
        !           631: 
        !           632:                                 if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
        !           633:                                                                          tapeExtension,
        !           634:                                                                          (CHAR *)&seek,
        !           635:                                                                          sizeof(seek),
        !           636:                                                                          FALSE)) == NoErr) {
        !           637: 
        !           638:                                          tapeExtension->QControllerData->EndFormatMode = TRUE;
        !           639: 
        !           640:                                 } else {
        !           641: 
        !           642:                                          //
        !           643:                                          // Request a DPC for execution later to get the remainder of the
        !           644:                                          // floppy state.
        !           645:                                          //
        !           646: 
        !           647:                  (VOID) KeSetEvent(
        !           648:                                         &tapeExtension->QControllerData->InterruptEvent,
        !           649:                                         (KPRIORITY) 0,
        !           650:                                         FALSE );
        !           651: 
        !           652:                                 }
        !           653: 
        !           654:                        } else if (tapeExtension->FmtOp.Segments == 0) {
        !           655: 
        !           656:                                  if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
        !           657:                                                                                                                         tapeExtension,
        !           658:                                                                                                                         (CHAR *)&result,
        !           659:                                                                                                                         (SHORT *)&statLength)) == NoErr) {
        !           660: 
        !           661:                                                if ( !(result.ST0 & ST0_IC)) {
        !           662: 
        !           663:                                                         //
        !           664:                                                         // If we timed out, then we did the sense interrupt status
        !           665:                                                         // without clearing the interrupt from the interrupt controller.
        !           666:                                                         // Since the FDC did not indicate an error, we assume that we
        !           667:                                                         // missed the interrupt and send the EOI. Only needed for an
        !           668:                                                         // 82072.
        !           669:                                                         //
        !           670: 
        !           671:                                                         if (tapeExtension->QControllerData->InterfaceType != MicroChannel) {
        !           672: 
        !           673:                                                                  if (result.ST0 !=
        !           674:                                                                                (UCHAR)(tapeExtension->DriveParms.DriveSelect | ST0_SE)) {
        !           675: 
        !           676:                                                                                tapeExtension->FmtOp.retval = NECFlt;
        !           677: 
        !           678:                                                                  }
        !           679:                                                         }
        !           680: 
        !           681:                                                         if (tapeExtension->FmtOp.NCN != result.PCN) {
        !           682: 
        !           683:                                                                  tapeExtension->FmtOp.retval = CmdFlt;
        !           684: 
        !           685:                                                         }
        !           686: 
        !           687:                                                         tapeExtension->QControllerData->FDC_Pcn = result.PCN;
        !           688: 
        !           689:                                                } else {
        !           690: 
        !           691:                                                         tapeExtension->FmtOp.retval = NECFlt;
        !           692: 
        !           693:                                                }
        !           694: 
        !           695:                                  }
        !           696: 
        !           697:                                 if (tapeExtension->FmtOp.retval == NoErr) {
        !           698: 
        !           699:                                          hdrPtr = tapeExtension->FmtOp.HdrPtr;
        !           700:                                          hdrData.hdr_struct.C = tapeExtension->FmtOp.Cylinder;
        !           701:                                          hdrData.hdr_struct.H = tapeExtension->FmtOp.Head;
        !           702:                                          hdrData.hdr_struct.N = FMT_BPS;
        !           703: 
        !           704:                                          for (i = 0; i < tapeExtension->TapeParms.FsectSeg; i++) {
        !           705: 
        !           706:                                                        hdrData.hdr_struct.R = tapeExtension->FmtOp.Sector++;
        !           707:                                                        *hdrPtr = hdrData.hdr_all;
        !           708:                                                        ++hdrPtr;
        !           709: 
        !           710:                                          }
        !           711: 
        !           712:                                          //
        !           713:                                          // Start the format by programming the DMA, starting the tape, and
        !           714:                                          // starting the floppy controller.
        !           715:                                          //
        !           716:                                          // Map the transfer through the DMA hardware.
        !           717:                                          //
        !           718: 
        !           719:                                          tapeExtension->RdWrOp.BytesTransferredSoFar = 0l;
        !           720:                                          tapeExtension->RdWrOp.TotalBytesOfTransfer =
        !           721:                                                        tapeExtension->TapeParms.FsectSeg * sizeof(ULONG);
        !           722: 
        !           723:                                          KeFlushIoBuffers( tapeExtension->FmtOp.MdlAddress, !DMA_READ, TRUE );
        !           724: 
        !           725:                                          val = IoMapTransfer(
        !           726:                                                        tapeExtension->QControllerData->AdapterObject,
        !           727:                                                        tapeExtension->FmtOp.MdlAddress,
        !           728:                                                        tapeExtension->QControllerData->MapRegisterBase,
        !           729:                                                        (PVOID)( (ULONG) MmGetMdlVirtualAddress(tapeExtension->FmtOp.MdlAddress)
        !           730:                                                                 + tapeExtension->RdWrOp.BytesTransferredSoFar ),
        !           731:                                                        &tapeExtension->RdWrOp.TotalBytesOfTransfer,
        !           732:                                                        DMA_READ );
        !           733: 
        !           734:                                  tapeExtension->QControllerData->CurrentDeviceObject =
        !           735:                                              tapeExtension->QDeviceObject;
        !           736: 
        !           737:                                          if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
        !           738:                                                                                                                                 tapeExtension,
        !           739:                                                                                                                                 (CHAR *)&tapeExtension->QControllerData->FmtCmd,
        !           740:                                                                                                                                 sizeof(FORMAT_CMD),
        !           741:                                                                                                                                 TRUE)) != NoErr) {
        !           742: 
        !           743:                                                        IoFlushAdapterBuffers(
        !           744:                                                                 tapeExtension->QControllerData->AdapterObject,
        !           745:                                                                 tapeExtension->FmtOp.MdlAddress,
        !           746:                                                                 tapeExtension->QControllerData->MapRegisterBase,
        !           747:                                                                 (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
        !           748:                                                                          + tapeExtension->RdWrOp.BytesTransferredSoFar ),
        !           749:                                                                 tapeExtension->RdWrOp.TotalBytesOfTransfer,
        !           750:                                                                 DMA_READ );
        !           751: 
        !           752:                      (VOID) KeSetEvent(
        !           753:                                             &tapeExtension->QControllerData->InterruptEvent,
        !           754:                                             (KPRIORITY) 0,
        !           755:                                             FALSE );
        !           756: 
        !           757:                                          }
        !           758: 
        !           759:                                          tapeExtension->FmtOp.Segments++;
        !           760:                                                  
        !           761:                                 } else {
        !           762: 
        !           763:                  (VOID) KeSetEvent(
        !           764:                                         &tapeExtension->QControllerData->InterruptEvent,
        !           765:                                         (KPRIORITY) 0,
        !           766:                                         FALSE );
        !           767: 
        !           768:                                 }
        !           769: 
        !           770: 
        !           771:                        } else {
        !           772: 
        !           773:                                 IoFlushAdapterBuffers(
        !           774:                                          tapeExtension->QControllerData->AdapterObject,
        !           775:                                          tapeExtension->FmtOp.MdlAddress,
        !           776:                                          tapeExtension->QControllerData->MapRegisterBase,
        !           777:                                          (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
        !           778:                                                        + tapeExtension->RdWrOp.BytesTransferredSoFar ),
        !           779:                                          tapeExtension->RdWrOp.TotalBytesOfTransfer,
        !           780:                                          DMA_READ );
        !           781: 
        !           782:                                 if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
        !           783:                                                                          tapeExtension,
        !           784:                                                                          (CHAR *)&fStat,
        !           785:                                                                          &statLength)) == NoErr) {
        !           786: 
        !           787:                                          if (fStat.ST0 & ST0_IC) {
        !           788: 
        !           789:                                                        tapeExtension->FmtOp.retval = TimeOut;
        !           790: 
        !           791:                                          }
        !           792:                                 }
        !           793: 
        !           794:                                 if (tapeExtension->FmtOp.retval != NoErr) {
        !           795: 
        !           796:                  (VOID) KeSetEvent(
        !           797:                                         &tapeExtension->QControllerData->InterruptEvent,
        !           798:                                         (KPRIORITY) 0,
        !           799:                                         FALSE );
        !           800: 
        !           801:                                 }
        !           802: 
        !           803:                                 if (tapeExtension->FmtOp.Sector > tapeExtension->TapeParms.FsectFtrack) {
        !           804: 
        !           805:                                          tapeExtension->FmtOp.Sector = 1;
        !           806:                                          tapeExtension->FmtOp.Cylinder++;
        !           807: 
        !           808:                                          if (tapeExtension->FmtOp.Cylinder ==
        !           809:                                                        (UCHAR)tapeExtension->TapeParms.FtrackFside) {
        !           810: 
        !           811:                                                        tapeExtension->FmtOp.Cylinder = 0;
        !           812:                                                        tapeExtension->FmtOp.Head++;
        !           813: 
        !           814:                                          }
        !           815:                                 }
        !           816: 
        !           817:                                 //
        !           818:                                 // Set up the sector id information for this segment.
        !           819:                                 //
        !           820: 
        !           821: 
        !           822:                                 hdrPtr = tapeExtension->FmtOp.HdrPtr;
        !           823:                                 hdrData.hdr_struct.C = tapeExtension->FmtOp.Cylinder;
        !           824:                                 hdrData.hdr_struct.H = tapeExtension->FmtOp.Head;
        !           825:                                 hdrData.hdr_struct.N = FMT_BPS;
        !           826: 
        !           827:                                 for (i = 0; i < tapeExtension->TapeParms.FsectSeg; i++) {
        !           828: 
        !           829:                                          hdrData.hdr_struct.R = tapeExtension->FmtOp.Sector++;
        !           830:                                          *hdrPtr = hdrData.hdr_all;
        !           831:                                          ++hdrPtr;
        !           832: 
        !           833:                                 }
        !           834: 
        !           835:                                 //
        !           836:                                 // Start the format by programming the DMA, starting the tape, and
        !           837:                                 // starting the floppy controller.
        !           838:                                 //
        !           839:                                 // Map the transfer through the DMA hardware.
        !           840:                                 //
        !           841: 
        !           842:                                 tapeExtension->RdWrOp.BytesTransferredSoFar = 0l;
        !           843:                                 tapeExtension->RdWrOp.TotalBytesOfTransfer =
        !           844:                                          tapeExtension->TapeParms.FsectSeg * sizeof(ULONG);
        !           845: 
        !           846:                                 KeFlushIoBuffers( tapeExtension->FmtOp.MdlAddress, !DMA_READ, TRUE );
        !           847: 
        !           848:                                 val = IoMapTransfer(
        !           849:                                          tapeExtension->QControllerData->AdapterObject,
        !           850:                                          tapeExtension->FmtOp.MdlAddress,
        !           851:                                          tapeExtension->QControllerData->MapRegisterBase,
        !           852:                                          (PVOID)( (ULONG) MmGetMdlVirtualAddress(tapeExtension->FmtOp.MdlAddress)
        !           853:                                                        + tapeExtension->RdWrOp.BytesTransferredSoFar ),
        !           854:                                          &tapeExtension->RdWrOp.TotalBytesOfTransfer,
        !           855:                                          DMA_READ );
        !           856: 
        !           857:                                 tapeExtension->QControllerData->CurrentDeviceObject =
        !           858:                                     tapeExtension->QDeviceObject;
        !           859: 
        !           860:                                 if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
        !           861:                                                                 tapeExtension,
        !           862:                                                                 (CHAR *)&tapeExtension->QControllerData->FmtCmd,
        !           863:                                                                 sizeof(FORMAT_CMD),
        !           864:                                                                 TRUE)) != NoErr) {
        !           865: 
        !           866:                                          IoFlushAdapterBuffers(
        !           867:                                                        tapeExtension->QControllerData->AdapterObject,
        !           868:                                                        tapeExtension->FmtOp.MdlAddress,
        !           869:                                                        tapeExtension->QControllerData->MapRegisterBase,
        !           870:                                                        (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
        !           871:                                                                 + tapeExtension->RdWrOp.BytesTransferredSoFar ),
        !           872:                                                        tapeExtension->RdWrOp.TotalBytesOfTransfer,
        !           873:                                                        DMA_READ );
        !           874: 
        !           875:                  (VOID) KeSetEvent(
        !           876:                                         &tapeExtension->QControllerData->InterruptEvent,
        !           877:                                         (KPRIORITY) 0,
        !           878:                                         FALSE );
        !           879: 
        !           880:                                 }      
        !           881: 
        !           882:                                 tapeExtension->FmtOp.Segments++;
        !           883:                                         
        !           884:                        }
        !           885: 
        !           886:          }
        !           887: 
        !           888: }
        !           889: 
        !           890: VOID
        !           891: Q117iTapeUnloadDriver(
        !           892:    IN PDRIVER_OBJECT DriverObject
        !           893:    )
        !           894: 
        !           895: /*++
        !           896: 
        !           897: Routine Description:
        !           898: 
        !           899:    This routine is called by the system to remove the driver from memory.
        !           900: 
        !           901:    When this routine is called, there is no I/O being done to this device.
        !           902:    The driver object is passed in, and from this the driver can find and
        !           903:    delete all of its device objects, extensions, etc.
        !           904: 
        !           905: Arguments:
        !           906: 
        !           907:    DriverObject - a pointer to the object associated with this device
        !           908:    driver.
        !           909: 
        !           910: Return Value:
        !           911: 
        !           912:    None.
        !           913: 
        !           914: --*/
        !           915: 
        !           916: {
        !           917:    UNREFERENCED_PARAMETER( DriverObject );
        !           918: 
        !           919: //  signal Q117iTapeThread() to unload itself
        !           920: //  disable interrupts from controller(s?)
        !           921: //  delete everything that's been allocated
        !           922: }
        !           923: 
        !           924: VOID
        !           925: Q117iTapeThread(
        !           926:    PTAPE_CONTROLLER_DATA ControllerData
        !           927:    )
        !           928: 
        !           929: /*++
        !           930: 
        !           931: Routine Description:
        !           932: 
        !           933:    This is the code executed by the system thread created when the
        !           934:    floppy driver initializes.  This thread loops forever (or until a
        !           935:    flag is set telling the thread to kill itself) processing packets
        !           936:    put into the queue by the dispatch routines.
        !           937: 
        !           938:    For each packet, this thread calls appropriate routines to process
        !           939:    the request, and then calls FlFinishOperation() to complete the
        !           940:    packet.
        !           941: 
        !           942: Arguments:
        !           943: 
        !           944:    ControllerData - a pointer to our data area for the controller being
        !           945:    supported (there is one thread per controller).
        !           946: 
        !           947: Return Value:
        !           948: 
        !           949:    None.
        !           950: 
        !           951: --*/
        !           952: 
        !           953: {
        !           954:    PIRP irp;
        !           955:    PIO_STACK_LOCATION irpSp;
        !           956:    PLIST_ENTRY request;
        !           957:    NTSTATUS ntStatus = 0;
        !           958: 
        !           959:    //
        !           960:    // Set thread priority to lowest realtime level.
        !           961:    //
        !           962: 
        !           963:    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
        !           964: 
        !           965:    do {
        !           966: 
        !           967:       //
        !           968:       // Wait for a request from the dispatch routines.
        !           969:       // KeWaitForSingleObject won't return error here - this thread
        !           970:       // isn't alertable and won't take APCs, and we're not passing in
        !           971:       // a timeout.
        !           972:       //
        !           973: 
        !           974:       (VOID) KeWaitForSingleObject(
        !           975:             (PVOID) &ControllerData->RequestSemaphore,
        !           976:             UserRequest,
        !           977:             KernelMode,
        !           978:             FALSE,
        !           979:             (PLARGE_INTEGER) NULL );
        !           980: 
        !           981:       if ( ControllerData->UnloadingDriver ) {
        !           982: 
        !           983:             CheckedDump(QIC117INFO,( "q117i: Thread asked to kill itself\n" ));
        !           984: 
        !           985:             PsTerminateSystemThread( STATUS_SUCCESS );
        !           986:       }
        !           987: 
        !           988:       while ( !IsListEmpty( &( ControllerData->ListEntry ) ) ) {
        !           989: 
        !           990:             //
        !           991:             // Get the request from the queue. We know there is one,
        !           992:             // because of the check above.
        !           993:             //
        !           994: 
        !           995:                request = ExInterlockedRemoveHeadList(
        !           996:                &ControllerData->ListEntry,
        !           997:                &ControllerData->ListSpinLock );
        !           998: 
        !           999: 
        !          1000:             ControllerData->QueueEmpty =
        !          1001:                   IsListEmpty( &( ControllerData->ListEntry ) );
        !          1002: 
        !          1003:             irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );
        !          1004: 
        !          1005:             irpSp = IoGetCurrentIrpStackLocation( irp );
        !          1006: 
        !          1007:             if ( ControllerData->ClearQueue ||
        !          1008:                irpSp->Parameters.DeviceIoControl.IoControlCode ==
        !          1009:                IOCTL_QIC117_CLEAR_QUEUE) {
        !          1010: 
        !          1011:                if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_QIC117_CLEAR_QUEUE) {
        !          1012: 
        !          1013:                   CheckedDump(QIC117INFO,("Q117i: processing IOCTL_QIC117_CLEAR_QUEUE : TRUE\n"));
        !          1014: 
        !          1015:                   irp->IoStatus.Status = Q117iClearIO( irp );
        !          1016: 
        !          1017:                   // NOTE: This is temporary until we ca find how to
        !          1018:                   // correctly free the Mdl using the io subsytem.
        !          1019:                   if (irp->MdlAddress != NULL) {
        !          1020:                         IoFreeMdl(irp->MdlAddress);
        !          1021:                         irp->MdlAddress = NULL;
        !          1022:                   }
        !          1023: 
        !          1024:                   IoCompleteRequest( irp, IO_DISK_INCREMENT );
        !          1025: 
        !          1026:                   (VOID) KeSetEvent(
        !          1027:                         &ControllerData->ClearQueueEvent,
        !          1028:                         (KPRIORITY) 0,
        !          1029:                         FALSE );
        !          1030: 
        !          1031:                } else {
        !          1032: 
        !          1033:                   CheckedDump(QIC117INFO,("Q117i: processing IOCTL_QIC117_DRIVE_REQUEST : TRUE\n"));
        !          1034: 
        !          1035:                   irp->IoStatus.Status = STATUS_CANCELLED;
        !          1036: 
        !          1037:                   // NOTE: This is temporary until we ca find how to
        !          1038:                   // correctly free the Mdl using the io subsytem.
        !          1039:                   if (irp->MdlAddress != NULL) {
        !          1040:                         IoFreeMdl(irp->MdlAddress);
        !          1041:                         irp->MdlAddress = NULL;
        !          1042:                   }
        !          1043: 
        !          1044:                   IoCompleteRequest( irp, IO_DISK_INCREMENT );
        !          1045: 
        !          1046:                }
        !          1047: 
        !          1048:             } else {
        !          1049: 
        !          1050:                irp->IoStatus.Status = Q117iProcessItem( irp );
        !          1051: 
        !          1052:                // NOTE: This is temporary until we ca find how to
        !          1053:                // correctly free the Mdl using the io subsytem.
        !          1054:                if (irp->MdlAddress != NULL) {
        !          1055:                   IoFreeMdl(irp->MdlAddress);
        !          1056:                   irp->MdlAddress = NULL;
        !          1057:                }
        !          1058: 
        !          1059:                IoCompleteRequest( irp, IO_DISK_INCREMENT );
        !          1060: 
        !          1061:             }
        !          1062: 
        !          1063:       }                                   //while there's packets to process
        !          1064: 
        !          1065:    } while ( TRUE );
        !          1066: }
        !          1067: 
        !          1068: IO_ALLOCATION_ACTION
        !          1069: Q117iTapeAllocateAdapterChannel(
        !          1070:    IN PDEVICE_OBJECT DeviceObject,
        !          1071:    IN PIRP Irp,
        !          1072:    IN PVOID MapRegisterBase,
        !          1073:    IN PVOID Context
        !          1074:    )
        !          1075: 
        !          1076: /*++
        !          1077: 
        !          1078: Routine Description:
        !          1079: 
        !          1080:    This DPC is called whenever the floppy thread is trying to allocate
        !          1081:    the adapter channel (like before doing a read or write).    It saves
        !          1082:    the MapRegisterBase in the controller data area, and sets the
        !          1083:    AllocateAdapterChannelEvent to awaken the thread.
        !          1084: 
        !          1085: Arguments:
        !          1086: 
        !          1087:    DeviceObject - unused.
        !          1088: 
        !          1089:    Irp - unused.
        !          1090: 
        !          1091:    MapRegisterBase - the base of the map registers that can be used
        !          1092:    for this transfer.
        !          1093: 
        !          1094:    Context - a pointer to our controller data area.
        !          1095: 
        !          1096: Return Value:
        !          1097: 
        !          1098:    Returns Allocation Action 'KeepObject' which means that the adapter
        !          1099:    object will be held for now (to be released explicitly later).
        !          1100: 
        !          1101: --*/
        !          1102: {
        !          1103:    PTAPE_CONTROLLER_DATA controllerData = (PTAPE_CONTROLLER_DATA) Context;
        !          1104: 
        !          1105:    UNREFERENCED_PARAMETER( DeviceObject );
        !          1106:    UNREFERENCED_PARAMETER( Irp );
        !          1107: 
        !          1108:    controllerData->MapRegisterBase = MapRegisterBase;
        !          1109: 
        !          1110:    (VOID) KeSetEvent(
        !          1111:       &controllerData->AllocateAdapterChannelEvent,
        !          1112:       0L,
        !          1113:       FALSE );
        !          1114: 
        !          1115:    return KeepObject;
        !          1116: }
        !          1117: 
        !          1118: NTSTATUS
        !          1119: Q117iConfigCallBack(
        !          1120:    IN PVOID Context,
        !          1121:    IN PUNICODE_STRING PathName,
        !          1122:    IN INTERFACE_TYPE BusType,
        !          1123:    IN ULONG BusNumber,
        !          1124:    IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
        !          1125:    IN CONFIGURATION_TYPE ControllerType,
        !          1126:    IN ULONG ControllerNumber,
        !          1127:    IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
        !          1128:    IN CONFIGURATION_TYPE PeripheralType,
        !          1129:    IN ULONG PeripheralNumber,
        !          1130:    IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
        !          1131:    )
        !          1132: 
        !          1133: /*++
        !          1134: 
        !          1135: Routine Description:
        !          1136: 
        !          1137:    This routine is used to acquire all of the configuration
        !          1138:    information for each floppy disk controller and the
        !          1139:    peripheral driver attached to that controller.
        !          1140: 
        !          1141: Arguments:
        !          1142: 
        !          1143:    Context - Pointer to the confuration information we are building
        !          1144:                up.
        !          1145: 
        !          1146:    PathName - unicode registry path.   Not Used.
        !          1147: 
        !          1148:    BusType - Internal, Isa, ...
        !          1149: 
        !          1150:    BusNumber - Which bus if we are on a multibus system.
        !          1151: 
        !          1152:    BusInformation - Configuration information about the bus. Not Used.
        !          1153: 
        !          1154:    ControllerType - Should always be DiskController.
        !          1155: 
        !          1156:    ControllerNumber - Which controller if there is more than one
        !          1157:                         controller in the system.
        !          1158: 
        !          1159:    ControllerInformation - Array of pointers to the three pieces of
        !          1160:                            registry information.
        !          1161: 
        !          1162:    PeripheralType - Should always be FloppyDiskPeripheral.
        !          1163: 
        !          1164:    PeripheralNumber - Which floppy if this controller is maintaining
        !          1165:                         more than one.
        !          1166: 
        !          1167:    PeripheralInformation - Array of pointers to the three pieces of
        !          1168:                            registry information.
        !          1169: 
        !          1170: Return Value:
        !          1171: 
        !          1172:    STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
        !          1173:    if it couldn't map the base csr or acquire the adapter object, or
        !          1174:    all of the resource information couldn't be acquired.
        !          1175: 
        !          1176: --*/
        !          1177: 
        !          1178: {
        !          1179: 
        !          1180:    //
        !          1181:    // So we don't have to typecast the context.
        !          1182:    //
        !          1183:    PCONFIG_DATA config = Context;
        !          1184: 
        !          1185:    //
        !          1186:    // Simple iteration variable.
        !          1187:    //
        !          1188:    ULONG i;
        !          1189: 
        !          1190:    //
        !          1191:    // This boolean will be used to denote whether we've seen this
        !          1192:    // controller before.
        !          1193:    //
        !          1194:    BOOLEAN newController;
        !          1195: 
        !          1196:    //
        !          1197:    // This will be used to denote whether we even have room
        !          1198:    // for a new controller.
        !          1199:    //
        !          1200:    BOOLEAN outOfRoom;
        !          1201: 
        !          1202:    //
        !          1203:    // Iteration variable that will end up indexing to where
        !          1204:    // the controller information should be placed.
        !          1205:    //
        !          1206:    ULONG ControllerSlot;
        !          1207: 
        !          1208:    //
        !          1209:    // Short hand for referencing the particular controller config
        !          1210:    // information that we are building up.
        !          1211:    //
        !          1212:    PCONFIG_CONTROLLER_DATA controller;
        !          1213: 
        !          1214:    PCM_FULL_RESOURCE_DESCRIPTOR peripheralData = (PCM_FULL_RESOURCE_DESCRIPTOR)
        !          1215:       (((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
        !          1216:       PeripheralInformation[IoQueryDeviceConfigurationData]->DataOffset);
        !          1217: 
        !          1218:    //
        !          1219:    // These three boolean will tell us whether we got all the
        !          1220:    // information that we needed.
        !          1221:    //
        !          1222:    BOOLEAN foundPort = FALSE;
        !          1223:    BOOLEAN foundInterrupt = FALSE;
        !          1224:    BOOLEAN foundDma = FALSE;
        !          1225: 
        !          1226:    ASSERT(ControllerType == DiskController);
        !          1227:    ASSERT(PeripheralType == FloppyDiskPeripheral);
        !          1228: 
        !          1229:    //
        !          1230:    // Loop through the "slots" that we have for a new controller.
        !          1231:    // Determine if this is a controller that we've already seen,
        !          1232:    // or a new controller.
        !          1233:    //
        !          1234: 
        !          1235:    outOfRoom = TRUE;
        !          1236:    for (
        !          1237:       ControllerSlot = 0;
        !          1238:       ControllerSlot < MAXIMUM_CONTROLLERS_PER_MACHINE;
        !          1239:       ControllerSlot++
        !          1240:       ) {
        !          1241: 
        !          1242:       if (config->Controller[ControllerSlot].ActualControllerNumber == -1) {
        !          1243: 
        !          1244:             newController = TRUE;
        !          1245:             outOfRoom = FALSE;
        !          1246:             config->Controller[ControllerSlot].ActualControllerNumber =
        !          1247:                ControllerNumber;
        !          1248:             config->NumberOfControllers++;
        !          1249:             break;
        !          1250: 
        !          1251:       } else if (config->Controller[ControllerSlot].ActualControllerNumber
        !          1252:                   == (LONG)ControllerNumber) {
        !          1253: 
        !          1254:             newController = FALSE;
        !          1255:             outOfRoom = FALSE;
        !          1256:             break;
        !          1257: 
        !          1258:       }
        !          1259: 
        !          1260:    }
        !          1261: 
        !          1262:    if (outOfRoom) {
        !          1263: 
        !          1264:       //
        !          1265:       // Just return and ignore the controller.
        !          1266:       //
        !          1267: 
        !          1268:       return STATUS_SUCCESS;
        !          1269: 
        !          1270:    }
        !          1271: 
        !          1272:    controller = &config->Controller[ControllerSlot];
        !          1273: 
        !          1274:    if (newController) {
        !          1275: 
        !          1276:       PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
        !          1277:             (PCM_FULL_RESOURCE_DESCRIPTOR)
        !          1278:             (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
        !          1279:             ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
        !          1280: 
        !          1281:       //
        !          1282:       // We have the pointer. Save off the interface type and
        !          1283:       // the busnumber for use when we call the Hal and the
        !          1284:       // Io System.
        !          1285:       //
        !          1286: 
        !          1287:       controller->InterfaceType = BusType;
        !          1288:       controller->BusNumber = BusNumber;
        !          1289:       controller->SharableVector = TRUE;
        !          1290:       controller->SaveFloatState = FALSE;
        !          1291: 
        !          1292:       //
        !          1293:       // We need to get the following information out of the partial
        !          1294:       // resource descriptors.
        !          1295:       //
        !          1296:       // The irql and vector.
        !          1297:       //
        !          1298:       // The dma channel.
        !          1299:       //
        !          1300:       // The base address and span covered by the floppy controllers
        !          1301:       // registers.
        !          1302:       //
        !          1303:       // It is not defined how these appear in the partial resource
        !          1304:       // lists, so we will just loop over all of them.    If we find
        !          1305:       // something we don't recognize, we drop that information on
        !          1306:       // the floor.   When we have finished going through all the
        !          1307:       // partial information, we validate that we got the above
        !          1308:       // three.
        !          1309:       //
        !          1310: 
        !          1311:       CheckedDump(QIC117INFO,("Q117i: adding controller: %x slot: %x\n",ControllerNumber,ControllerSlot));
        !          1312: 
        !          1313:       for (
        !          1314:             i = 0;
        !          1315:             i < controllerData->PartialResourceList.Count;
        !          1316:             i++
        !          1317:             ) {
        !          1318: 
        !          1319:             PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
        !          1320:                &controllerData->PartialResourceList.PartialDescriptors[i];
        !          1321: 
        !          1322:             switch (partial->Type) {
        !          1323: 
        !          1324:                case CmResourceTypePort: {
        !          1325: 
        !          1326:                   BOOLEAN inIoSpace =
        !          1327: #ifdef i386
        !          1328:                               TRUE;
        !          1329: #else
        !          1330:                               FALSE;
        !          1331: #endif
        !          1332: 
        !          1333:                   foundPort = TRUE;
        !          1334: 
        !          1335:                   //
        !          1336:                   // Save of the pointer to the partial so
        !          1337:                   // that we can later use it to report resources
        !          1338:                   // and we can also use this later in the routine
        !          1339:                   // to make sure that we got all of our resources.
        !          1340:                   //
        !          1341: 
        !          1342:                   controller->SpanOfControllerAddress =
        !          1343:                         partial->u.Port.Length;
        !          1344:                   controller->OriginalBaseAddress =
        !          1345:                         partial->u.Port.Start;
        !          1346:                   controller->ControllerBaseAddress = (PTAPE_ADDRESS)
        !          1347:                         Q117iGetControllerBase(
        !          1348:                            BusType,
        !          1349:                            BusNumber,
        !          1350:                            partial->u.Port.Start,
        !          1351:                            controller->SpanOfControllerAddress,
        !          1352:                            inIoSpace,
        !          1353:                            &controller->MappedAddress
        !          1354:                            );
        !          1355: 
        !          1356:                   if (!controller->ControllerBaseAddress) {
        !          1357: 
        !          1358:                         return STATUS_INSUFFICIENT_RESOURCES;
        !          1359: 
        !          1360:                   }
        !          1361: 
        !          1362:                   break;
        !          1363:                }
        !          1364:                case CmResourceTypeInterrupt: {
        !          1365: 
        !          1366:                   foundInterrupt = TRUE;
        !          1367:                   if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
        !          1368: 
        !          1369:                         controller->InterruptMode = Latched;
        !          1370: 
        !          1371:                   } else {
        !          1372: 
        !          1373:                         controller->InterruptMode = LevelSensitive;
        !          1374: 
        !          1375:                   }
        !          1376: 
        !          1377:                   controller->OriginalIrql =  partial->u.Interrupt.Level;
        !          1378:                   controller->OriginalVector = partial->u.Interrupt.Vector;
        !          1379:                   controller->ControllerVector =
        !          1380:                         HalGetInterruptVector(
        !          1381:                            BusType,
        !          1382:                            BusNumber,
        !          1383:                            partial->u.Interrupt.Level,
        !          1384:                            partial->u.Interrupt.Vector,
        !          1385:                            &controller->ControllerIrql,
        !          1386:                            &controller->ProcessorMask
        !          1387:                            );
        !          1388: 
        !          1389:                   break;
        !          1390:                }
        !          1391:                case CmResourceTypeDma: {
        !          1392: 
        !          1393:                   DEVICE_DESCRIPTION deviceDesc;
        !          1394: 
        !          1395:                   RtlZeroMemory(&deviceDesc,sizeof(deviceDesc));
        !          1396:                   foundDma = TRUE;
        !          1397: 
        !          1398:                   controller->OriginalDmaChannel = partial->u.Dma.Channel;
        !          1399: 
        !          1400:                   deviceDesc.Version = DEVICE_DESCRIPTION_VERSION;
        !          1401:                   deviceDesc.DmaWidth = Width8Bits;
        !          1402:                   deviceDesc.DemandMode = TRUE;
        !          1403:                   deviceDesc.MaximumLength = 32l*1024l;
        !          1404:                   deviceDesc.AutoInitialize = FALSE;
        !          1405:                   deviceDesc.ScatterGather = FALSE;
        !          1406:                   deviceDesc.DmaChannel = partial->u.Dma.Channel;
        !          1407:                   deviceDesc.InterfaceType = BusType;
        !          1408:                   deviceDesc.DmaSpeed = TypeA;
        !          1409:                   controller->NumberOfMapRegisters = BYTES_TO_PAGES(32l*1024l);
        !          1410:                   controller->AdapterObject =
        !          1411:                         HalGetAdapter(
        !          1412:                            &deviceDesc,
        !          1413:                            &controller->NumberOfMapRegisters
        !          1414:                            );
        !          1415: 
        !          1416:                   CheckedDump(QIC117INFO,( "Q117i: Bus Type = %d\n",
        !          1417:                         BusType ));
        !          1418:                   CheckedDump(QIC117INFO,( "Q117i: Number of map registers = %d\n",
        !          1419:                         controller->NumberOfMapRegisters ));
        !          1420: 
        !          1421:                   if (!controller->AdapterObject) {
        !          1422: 
        !          1423:                         return STATUS_INSUFFICIENT_RESOURCES;
        !          1424: 
        !          1425:                   }
        !          1426: 
        !          1427:                   break;
        !          1428: 
        !          1429:                }
        !          1430:                default: {
        !          1431: 
        !          1432:                   break;
        !          1433: 
        !          1434:                }
        !          1435: 
        !          1436:             }
        !          1437: 
        !          1438:       }
        !          1439: 
        !          1440:       //
        !          1441:       // If we didn't get all the information then we return
        !          1442:       // insufficient resources.
        !          1443:       //
        !          1444: 
        !          1445:       if ((!foundPort) ||
        !          1446:             (!foundInterrupt) ||
        !          1447:             (!foundDma)) {
        !          1448: 
        !          1449:             return STATUS_INSUFFICIENT_RESOURCES;
        !          1450: 
        !          1451:       }
        !          1452:       controller->NumberOfTapeDrives++;
        !          1453:       controller->OkToUseThisController = TRUE;
        !          1454: 
        !          1455:    }
        !          1456: 
        !          1457: 
        !          1458:    return STATUS_SUCCESS;
        !          1459: }
        !          1460: 
        !          1461: NTSTATUS
        !          1462: Q117iGetConfigurationInformation(
        !          1463:    OUT PCONFIG_DATA *ConfigData
        !          1464:    )
        !          1465: 
        !          1466: /*++
        !          1467: 
        !          1468: Routine Description:
        !          1469: 
        !          1470:    This routine is called by DriverEntry() to get information about the
        !          1471:    devices to be supported from configuration mangement and/or the
        !          1472:    hardware architecture layer (HAL).
        !          1473: 
        !          1474: Arguments:
        !          1475: 
        !          1476:    ConfigData - a pointer to the pointer to a data structure that
        !          1477:    describes the controllers and the drives attached to them
        !          1478: 
        !          1479: Return Value:
        !          1480: 
        !          1481:    Returns STATUS_SUCCESS unless there is no drive 0 or we didn't get
        !          1482:    any configuration information.
        !          1483:    NOTE: FUTURE return values may change when config mgr is finished.
        !          1484: 
        !          1485: --*/
        !          1486: 
        !          1487: {
        !          1488:    INTERFACE_TYPE InterfaceType;
        !          1489:    NTSTATUS Status;
        !          1490:    ULONG i;
        !          1491: 
        !          1492:    *ConfigData = ExAllocatePool(
        !          1493:                         PagedPool,
        !          1494:                         sizeof(CONFIG_DATA)
        !          1495:                         );
        !          1496: 
        !          1497:    if (!*ConfigData) {
        !          1498: 
        !          1499:       return STATUS_INSUFFICIENT_RESOURCES;
        !          1500: 
        !          1501:    }
        !          1502: 
        !          1503:    //
        !          1504:    // Zero out the config structure and fill in the actual
        !          1505:    // controller numbers with -1's so that the callback routine
        !          1506:    // can recognize a new controller.
        !          1507:    //
        !          1508: 
        !          1509:    RtlZeroMemory(
        !          1510:       *ConfigData,
        !          1511:       sizeof(CONFIG_DATA)
        !          1512:       );
        !          1513: 
        !          1514:    for (
        !          1515:       i = 0;
        !          1516:       i < MAXIMUM_CONTROLLERS_PER_MACHINE;
        !          1517:       i++
        !          1518:       ) {
        !          1519: 
        !          1520:       (*ConfigData)->Controller[i].ActualControllerNumber = -1;
        !          1521: 
        !          1522:    }
        !          1523: 
        !          1524:    //
        !          1525:    // Go through all of the various bus types looking for
        !          1526:    // disk controllers.    The disk controller sections of the
        !          1527:    // hardware registry only deal with the floppy drives.
        !          1528:    // The callout routine that can get called will then
        !          1529:    // look for information pertaining to a particular
        !          1530:    // device on the controller.
        !          1531:    //
        !          1532: 
        !          1533:    for (
        !          1534:       InterfaceType = 0;
        !          1535:       InterfaceType < MaximumInterfaceType;
        !          1536:       InterfaceType++
        !          1537:       ) {
        !          1538: 
        !          1539:       CONFIGURATION_TYPE Dc = DiskController;
        !          1540:       CONFIGURATION_TYPE Fp = FloppyDiskPeripheral;
        !          1541: 
        !          1542:       Status = IoQueryDeviceDescription(
        !          1543:                      &InterfaceType,
        !          1544:                      NULL,
        !          1545:                      &Dc,
        !          1546:                      NULL,
        !          1547:                      &Fp,
        !          1548:                      NULL,
        !          1549:                      Q117iConfigCallBack,
        !          1550:                      *ConfigData
        !          1551:                      );
        !          1552: 
        !          1553:       if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) {
        !          1554: 
        !          1555:             ExFreePool(*ConfigData);
        !          1556:             *ConfigData = NULL;
        !          1557:             return Status;
        !          1558: 
        !          1559:       }
        !          1560: 
        !          1561:    }
        !          1562: 
        !          1563:    return STATUS_SUCCESS;
        !          1564: }
        !          1565: 
        !          1566: NTSTATUS
        !          1567: Q117iInitializeController(
        !          1568:    IN PCONFIG_DATA ConfigData,
        !          1569:    IN UCHAR ControllerNumber,
        !          1570:    IN PDRIVER_OBJECT DriverObject,
        !          1571:    IN PUNICODE_STRING RegistryPath
        !          1572:    )
        !          1573: 
        !          1574: /*++
        !          1575: 
        !          1576: Routine Description:
        !          1577: 
        !          1578:    This routine is called at initialization time by DriverEntry() -
        !          1579:    once for each controller that the configuration manager tells it we
        !          1580:    have to support.
        !          1581: 
        !          1582:    When this routine is called, the configuration data has already been
        !          1583:    filled in.
        !          1584: 
        !          1585: Arguments:
        !          1586: 
        !          1587:    ConfigData - a pointer to the structure that describes the
        !          1588:    controller and the disks attached to it, as given to us by the
        !          1589:    configuration manager.
        !          1590: 
        !          1591:    ControllerNumber - which controller in ConfigData we are
        !          1592:    initializing.
        !          1593: 
        !          1594:    DriverObject - a pointer to the object that represents this device
        !          1595:    driver.
        !          1596: 
        !          1597: Return Value:
        !          1598: 
        !          1599:    STATUS_SUCCESS if this controller and at least one of its disks were
        !          1600:    initialized; an error otherwise.
        !          1601: 
        !          1602: --*/
        !          1603: 
        !          1604: {
        !          1605:    PTAPE_CONTROLLER_DATA controllerData;
        !          1606:    PVOID threadObject;
        !          1607:    NTSTATUS ntStatus;
        !          1608:    NTSTATUS ntStatus2;
        !          1609:    HANDLE threadHandle = 0;
        !          1610:    BOOLEAN partlySuccessful;
        !          1611:    LARGE_INTEGER timeout;
        !          1612:    UCHAR ntNameBuffer[256];
        !          1613:    STRING ntNameString;
        !          1614:    UNICODE_STRING ntUnicodeString;
        !          1615: 
        !          1616:    CheckedDump(QIC117INFO,( "Q117iInitializeController...\n" ));
        !          1617: 
        !          1618:    //
        !          1619:    // This routine will take attempt to "append" the resources
        !          1620:    // used by this controller into the resource map of the
        !          1621:    // registry.    If there was a conflict with previously "declared"
        !          1622:    // data, then this routine will return false, in which case we
        !          1623:    // will NOT try to initialize this particular controller.
        !          1624:    //
        !          1625: 
        !          1626:    if (!Q117iReportResources(
        !          1627:             DriverObject,
        !          1628:             ConfigData,
        !          1629:             ControllerNumber
        !          1630:             )) {
        !          1631: 
        !          1632:       return STATUS_INSUFFICIENT_RESOURCES;
        !          1633: 
        !          1634:    }
        !          1635: 
        !          1636:    //
        !          1637:    // Allocate and zero-initialize data to describe this controller
        !          1638:    //
        !          1639: 
        !          1640:    controllerData = (PTAPE_CONTROLLER_DATA) ExAllocatePool(
        !          1641:       NonPagedPool,
        !          1642:       sizeof( TAPE_CONTROLLER_DATA ) );
        !          1643: 
        !          1644:    if ( controllerData == NULL ) {
        !          1645: 
        !          1646:       return STATUS_INSUFFICIENT_RESOURCES;
        !          1647:    }
        !          1648: 
        !          1649:    RtlZeroMemory( controllerData, sizeof( TAPE_CONTROLLER_DATA ) );
        !          1650: 
        !          1651:    (VOID) sprintf(
        !          1652:       ntNameBuffer,
        !          1653:       "\\Device\\FloppyControllerEvent%d",
        !          1654:       ControllerNumber );
        !          1655: 
        !          1656:    RtlInitString( &ntNameString, ntNameBuffer );
        !          1657: 
        !          1658:    ntStatus = RtlAnsiStringToUnicodeString(
        !          1659:       &ntUnicodeString,
        !          1660:       &ntNameString,
        !          1661:       TRUE );
        !          1662: 
        !          1663:    controllerData->ControllerEvent = IoCreateSynchronizationEvent(
        !          1664:       &ntUnicodeString,
        !          1665:       &controllerData->ControllerEventHandle);
        !          1666: 
        !          1667:    RtlFreeUnicodeString( &ntUnicodeString );
        !          1668: 
        !          1669:    if ( controllerData->ControllerEvent == NULL ) {
        !          1670:       return STATUS_INSUFFICIENT_RESOURCES;
        !          1671:    }
        !          1672: 
        !          1673:    //
        !          1674:    // Fill in some items that we got from configuration management and
        !          1675:    // the HAL.
        !          1676:    //
        !          1677: 
        !          1678:    controllerData->FDC_Addr = (PTAPE_ADDRESS)
        !          1679:       ConfigData->Controller[ControllerNumber].ControllerBaseAddress;
        !          1680:    controllerData->InterfaceType =
        !          1681:       ConfigData->Controller[ControllerNumber].InterfaceType;
        !          1682:    controllerData->ActualControllerNumber =
        !          1683:       ConfigData->Controller[ControllerNumber].ActualControllerNumber;
        !          1684: 
        !          1685:    controllerData->DriveSelect.Selected = FALSE;
        !          1686:    controllerData->DriveSelect.DeselectByte = dselb;
        !          1687:    controllerData->DriveSelect.SelectByte = selb;
        !          1688: 
        !          1689:    ntStatus = IoConnectInterrupt(
        !          1690:       (PKINTERRUPT *) &controllerData->InterruptObject,
        !          1691:       (PKSERVICE_ROUTINE) Q117iTapeInterruptService,
        !          1692:       (PVOID) controllerData,
        !          1693:       (PKSPIN_LOCK)NULL,
        !          1694:       ConfigData->Controller[ControllerNumber].ControllerVector,
        !          1695:       ConfigData->Controller[ControllerNumber].ControllerIrql,
        !          1696:       ConfigData->Controller[ControllerNumber].ControllerIrql,
        !          1697:       ConfigData->Controller[ControllerNumber].InterruptMode,
        !          1698:       ConfigData->Controller[ControllerNumber].SharableVector,
        !          1699:       ConfigData->Controller[ControllerNumber].ProcessorMask,
        !          1700:       ConfigData->Controller[ControllerNumber].SaveFloatState);
        !          1701: 
        !          1702: 
        !          1703:    if ( NT_SUCCESS( ntStatus ) ) {
        !          1704:       //
        !          1705:       // Initialize the interlocked request queue, including a
        !          1706:       // counting semaphore to indicate items in the queue
        !          1707:       //
        !          1708: 
        !          1709:       KeInitializeSemaphore(
        !          1710:             &controllerData->RequestSemaphore,
        !          1711:             0L,
        !          1712:             MAXLONG );
        !          1713: 
        !          1714:       KeInitializeSpinLock( &controllerData->ListSpinLock );
        !          1715: 
        !          1716:       InitializeListHead( &controllerData->ListEntry );
        !          1717: 
        !          1718:       //
        !          1719:       // Initialize events to signal interrupts and adapter object
        !          1720:       // allocation
        !          1721:       //
        !          1722: 
        !          1723:       KeInitializeEvent(
        !          1724:             &controllerData->InterruptEvent,
        !          1725:             SynchronizationEvent,
        !          1726:             FALSE);
        !          1727: 
        !          1728: 
        !          1729:       KeInitializeEvent(
        !          1730:             &controllerData->AllocateAdapterChannelEvent,
        !          1731:             NotificationEvent,
        !          1732:             FALSE );
        !          1733: 
        !          1734: 
        !          1735:       KeInitializeEvent(
        !          1736:             &controllerData->ClearQueueEvent,
        !          1737:             SynchronizationEvent,
        !          1738:             FALSE);
        !          1739: 
        !          1740: 
        !          1741: 
        !          1742:       //
        !          1743:       // Create a thread with entry point Q117iTapeThread()
        !          1744:       //
        !          1745: 
        !          1746:       ntStatus = PsCreateSystemThread(
        !          1747:             &threadHandle,
        !          1748:             (ACCESS_MASK) 0L,
        !          1749:             (POBJECT_ATTRIBUTES) NULL,
        !          1750:             (HANDLE) 0L,
        !          1751:             (PCLIENT_ID) NULL,
        !          1752:             (PKSTART_ROUTINE) Q117iTapeThread,
        !          1753:             (PVOID) controllerData );
        !          1754: 
        !          1755: #if DBG
        !          1756:       if ( !NT_SUCCESS( ntStatus ) ) {
        !          1757: 
        !          1758:             CheckedDump(QIC117DBGP,( "q117i: error %x creating thread\n", ntStatus ));
        !          1759:       }
        !          1760: #endif
        !          1761: 
        !          1762:       if ( NT_SUCCESS( ntStatus ) ) {
        !          1763: 
        !          1764:             CheckedDump(QIC117INFO,("Q117iThread = %x\n",threadHandle));
        !          1765: 
        !          1766:             //
        !          1767:             // Call Q117iInitializeDrive() for each drive on the
        !          1768:             // controller
        !          1769:             //
        !          1770: 
        !          1771:             ConfigData->Controller[ControllerNumber].NumberOfTapeDrives++;
        !          1772: 
        !          1773:             ntStatus = STATUS_NO_SUCH_DEVICE;
        !          1774:             partlySuccessful = FALSE;
        !          1775: 
        !          1776:             ntStatus = Q117iInitializeDrive(
        !          1777:                ConfigData,
        !          1778:                controllerData,
        !          1779:                ControllerNumber,
        !          1780:                DriverObject,
        !          1781:                RegistryPath );
        !          1782:       }
        !          1783: 
        !          1784:    }
        !          1785: 
        !          1786:    //
        !          1787:    // If we're exiting with an error, clean up first.
        !          1788:    //
        !          1789: 
        !          1790:    if ( !NT_SUCCESS( ntStatus ) ) {
        !          1791: 
        !          1792:       CheckedDump(QIC117DBGP,( "q117i: InitializeController failing\n" ));
        !          1793: 
        !          1794:       //
        !          1795:       // If we created the thread, wake it up and tell it to kill itself.
        !          1796:       // Wait until it's dead.    (Note that since it's a system thread,
        !          1797:       // it has to kill itself - we can't do it).
        !          1798:       //
        !          1799: 
        !          1800:       if ( threadHandle != 0 ) {
        !          1801: 
        !          1802:             controllerData->UnloadingDriver = TRUE;
        !          1803: 
        !          1804:             ntStatus2 = ObReferenceObjectByHandle(
        !          1805:                threadHandle,
        !          1806:                THREAD_ALL_ACCESS,
        !          1807:                NULL,
        !          1808:                KernelMode,
        !          1809:                (PVOID *) &threadObject,
        !          1810:                NULL );
        !          1811: 
        !          1812:             (VOID) KeReleaseSemaphore(
        !          1813:                &controllerData->RequestSemaphore,
        !          1814:                (KPRIORITY) 0,
        !          1815:                1,
        !          1816:                FALSE );
        !          1817: 
        !          1818:             if ( NT_SUCCESS( ntStatus2 ) ) {
        !          1819: 
        !          1820:                //
        !          1821:                // The thread object will be signalled when it dies.
        !          1822:                //
        !          1823: 
        !          1824:                ntStatus2 = KeWaitForSingleObject(
        !          1825:                   (PVOID) threadObject,
        !          1826:                   Suspended,
        !          1827:                   KernelMode,
        !          1828:                   FALSE,
        !          1829:                   (PLARGE_INTEGER) NULL );
        !          1830: 
        !          1831:                ASSERT( ntStatus2 == STATUS_SUCCESS );
        !          1832: 
        !          1833:                ObDereferenceObject( threadObject );
        !          1834: 
        !          1835:             } else {
        !          1836: 
        !          1837:                //
        !          1838:                // We can't get the thread object for some reason; just
        !          1839:                // block for a while to give the thread a chance to run
        !          1840:                // and die.
        !          1841:                //
        !          1842: 
        !          1843:                CheckedDump(QIC117DBGP,( "q117i: couldn't get thread object\n" ));
        !          1844: 
        !          1845: 
        !          1846:                timeout =
        !          1847:                   RtlLargeIntegerNegate(
        !          1848:                   RtlEnlargedIntegerMultiply(
        !          1849:                         10,
        !          1850:                         10l * 1000l
        !          1851:                   )
        !          1852:                );
        !          1853:                (VOID) KeDelayExecutionThread(
        !          1854:                   KernelMode,
        !          1855:                   FALSE,
        !          1856:                   &timeout );
        !          1857:             }
        !          1858:       }
        !          1859: 
        !          1860: 
        !          1861:       if ( controllerData->InterruptObject != NULL ) {
        !          1862: 
        !          1863:           (VOID) KeSetEvent(
        !          1864:                     controllerData->ControllerEvent,
        !          1865:                     (KPRIORITY) 0,
        !          1866:                     FALSE );
        !          1867: 
        !          1868:           IoDisconnectInterrupt( controllerData->InterruptObject );
        !          1869:       }
        !          1870: 
        !          1871:       ExFreePool( controllerData );
        !          1872: 
        !          1873:    }
        !          1874: 
        !          1875:    return ntStatus;
        !          1876: }
        !          1877: 
        !          1878: BOOLEAN
        !          1879: Q117iReportResources(
        !          1880:    IN PDRIVER_OBJECT DriverObject,
        !          1881:    IN PCONFIG_DATA ConfigData,
        !          1882:    IN UCHAR ControllerNumber
        !          1883:    )
        !          1884: 
        !          1885: /*++
        !          1886: 
        !          1887: Routine Description:
        !          1888: 
        !          1889:    This routine will build up a resource list using the
        !          1890:    data for this particular controller as well as all
        !          1891:    previous *successfully* configured controllers.
        !          1892: 
        !          1893:    N.B.  This routine assumes that it called in controller
        !          1894:    number order.
        !          1895: 
        !          1896: Arguments:
        !          1897: 
        !          1898:    DriverObject - a pointer to the object that represents this device
        !          1899:    driver.
        !          1900: 
        !          1901:    ConfigData - a pointer to the structure that describes the
        !          1902:    controller and the disks attached to it, as given to us by the
        !          1903:    configuration manager.
        !          1904: 
        !          1905:    ControllerNumber - which controller in ConfigData we are
        !          1906:    about to try to report.
        !          1907: 
        !          1908: Return Value:
        !          1909: 
        !          1910:    TRUE if no conflict was detected, FALSE otherwise.
        !          1911: 
        !          1912: --*/
        !          1913: 
        !          1914: {
        !          1915: 
        !          1916: 
        !          1917:    ULONG sizeOfResourceList;
        !          1918:    ULONG numberOfFrds;
        !          1919:    LONG i;
        !          1920:    PCM_RESOURCE_LIST resourceList;
        !          1921:    PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;
        !          1922: 
        !          1923:    //
        !          1924:    // Loop through all of the controllers previous to this
        !          1925:    // controller.  If the controllers previous to this one
        !          1926:    // didn't have a conflict, then accumulate the size of the
        !          1927:    // CM_FULL_RESOURCE_DESCRIPTOR associated with it.
        !          1928:    //
        !          1929: 
        !          1930:    for (
        !          1931:       i = 0,numberOfFrds = 0,sizeOfResourceList = 0;
        !          1932:       i <= ControllerNumber;
        !          1933:       i++
        !          1934:       ) {
        !          1935: 
        !          1936:       if (ConfigData->Controller[i].OkToUseThisController) {
        !          1937: 
        !          1938:             sizeOfResourceList += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
        !          1939: 
        !          1940:             //
        !          1941:             // The full resource descriptor already contains one
        !          1942:             // partial.  Make room for three more.
        !          1943:             //
        !          1944:             // It will hold the irq "prd", the controller "csr" "prd" which
        !          1945:             // is actually in two pieces since we don't use one of the
        !          1946:             // registers, and the controller dma "prd".
        !          1947:             //
        !          1948: 
        !          1949:             sizeOfResourceList += 3*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
        !          1950:             numberOfFrds++;
        !          1951: 
        !          1952:       }
        !          1953: 
        !          1954:    }
        !          1955: 
        !          1956:    //
        !          1957:    // Now we increment the length of the resource list by field offset
        !          1958:    // of the first frd.   This will give us the length of what preceeds
        !          1959:    // the first frd in the resource list.
        !          1960:    //
        !          1961: 
        !          1962:    sizeOfResourceList += FIELD_OFFSET(
        !          1963:                               CM_RESOURCE_LIST,
        !          1964:                               List[0]
        !          1965:                               );
        !          1966: 
        !          1967:    resourceList = ExAllocatePool(
        !          1968:                      PagedPool,
        !          1969:                      sizeOfResourceList
        !          1970:                      );
        !          1971: 
        !          1972:    if (!resourceList) {
        !          1973: 
        !          1974:       return FALSE;
        !          1975: 
        !          1976:    }
        !          1977: 
        !          1978:    //
        !          1979:    // Zero out the field
        !          1980:    //
        !          1981: 
        !          1982:    RtlZeroMemory(
        !          1983:       resourceList,
        !          1984:       sizeOfResourceList
        !          1985:       );
        !          1986: 
        !          1987:    resourceList->Count = numberOfFrds;
        !          1988:    nextFrd = &resourceList->List[0];
        !          1989: 
        !          1990:    for (
        !          1991:       i = 0;
        !          1992:       numberOfFrds;
        !          1993:       i++
        !          1994:       ) {
        !          1995: 
        !          1996:       if (ConfigData->Controller[i].OkToUseThisController) {
        !          1997: 
        !          1998:             PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
        !          1999: 
        !          2000:             nextFrd->InterfaceType = ConfigData->Controller[i].InterfaceType;
        !          2001:             nextFrd->BusNumber = ConfigData->Controller[i].BusNumber;
        !          2002: 
        !          2003:             //
        !          2004:             // We are only going to report 4 items no matter what
        !          2005:             // was in the original.
        !          2006:             //
        !          2007: 
        !          2008:             nextFrd->PartialResourceList.Count = 4;
        !          2009: 
        !          2010:             //
        !          2011:             // Now fill in the port data.  We don't wish to share
        !          2012:             // this port range with anyone
        !          2013:             //
        !          2014: 
        !          2015:             partial = &nextFrd->PartialResourceList.PartialDescriptors[0];
        !          2016: 
        !          2017:             partial->Type = CmResourceTypePort;
        !          2018:             partial->ShareDisposition = CmResourceShareShared;
        !          2019:             partial->Flags = 0;
        !          2020:             partial->u.Port.Start =
        !          2021:                ConfigData->Controller[i].OriginalBaseAddress;
        !          2022:             partial->u.Port.Length = 6;
        !          2023: 
        !          2024:             partial++;
        !          2025: 
        !          2026:             partial->Type = CmResourceTypePort;
        !          2027:             partial->ShareDisposition = CmResourceShareShared;
        !          2028:             partial->Flags = 0;
        !          2029:             partial->u.Port.Start = RtlLargeIntegerAdd(
        !          2030:                         ConfigData->Controller[i].OriginalBaseAddress,
        !          2031:                         RtlConvertUlongToLargeInteger((ULONG)7)
        !          2032:                         );
        !          2033:             partial->u.Port.Length = 1;
        !          2034: 
        !          2035:             partial++;
        !          2036: 
        !          2037:             partial->Type = CmResourceTypeDma;
        !          2038:             partial->ShareDisposition = CmResourceShareShared;
        !          2039:             partial->Flags = 0;
        !          2040:             partial->u.Dma.Channel =
        !          2041:                ConfigData->Controller[i].OriginalDmaChannel;
        !          2042: 
        !          2043:             partial++;
        !          2044: 
        !          2045:             //
        !          2046:             // Now fill in the irq stuff.
        !          2047:             //
        !          2048: 
        !          2049:             partial->Type = CmResourceTypeInterrupt;
        !          2050:             partial->ShareDisposition = CmResourceShareShared;
        !          2051:             partial->u.Interrupt.Level =
        !          2052:                ConfigData->Controller[i].OriginalIrql;
        !          2053:             partial->u.Interrupt.Vector =
        !          2054:                ConfigData->Controller[i].OriginalVector;
        !          2055: 
        !          2056:             if (ConfigData->Controller[i].InterruptMode == Latched) {
        !          2057: 
        !          2058:                partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
        !          2059: 
        !          2060:             } else {
        !          2061: 
        !          2062:                partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
        !          2063: 
        !          2064:             }
        !          2065: 
        !          2066:             partial++;
        !          2067: 
        !          2068:             nextFrd = (PVOID)partial;
        !          2069: 
        !          2070:             numberOfFrds--;
        !          2071: 
        !          2072:       }
        !          2073: 
        !          2074:    }
        !          2075: 
        !          2076:    IoReportResourceUsage(
        !          2077:       NULL,
        !          2078:       DriverObject,
        !          2079:       resourceList,
        !          2080:       sizeOfResourceList,
        !          2081:       NULL,
        !          2082:       NULL,
        !          2083:       0,
        !          2084:       FALSE,
        !          2085:       &ConfigData->Controller[ControllerNumber].OkToUseThisController
        !          2086:       );
        !          2087: 
        !          2088:    //
        !          2089:    // The above routine sets the boolean the parameter
        !          2090:    // to TRUE if a conflict was detected.
        !          2091:    //
        !          2092: 
        !          2093:    ConfigData->Controller[ControllerNumber].OkToUseThisController =
        !          2094:       !ConfigData->Controller[ControllerNumber].OkToUseThisController;
        !          2095: 
        !          2096:    ExFreePool(resourceList);
        !          2097: 
        !          2098:    return ConfigData->Controller[ControllerNumber].OkToUseThisController;
        !          2099: 
        !          2100: }
        !          2101: 
        !          2102: NTSTATUS
        !          2103: Q117iInitializeDrive(
        !          2104:    IN PCONFIG_DATA ConfigData,
        !          2105:    IN PTAPE_CONTROLLER_DATA ControllerData,
        !          2106:    IN UCHAR ControllerNum,
        !          2107:    IN PDRIVER_OBJECT DriverObject,
        !          2108:    IN PUNICODE_STRING RegistryPath
        !          2109:    )
        !          2110: 
        !          2111: /*++
        !          2112: 
        !          2113: Routine Description:
        !          2114: 
        !          2115:    This routine is called at initialization time by
        !          2116:    Q117iInitializeController(), once for each disk that we are supporting
        !          2117:    on the controller.
        !          2118: 
        !          2119: Arguments:
        !          2120: 
        !          2121:    ConfigData - a pointer to the structure that describes the
        !          2122:    controller and the disks attached to it, as given to us by the
        !          2123:    configuration manager.
        !          2124: 
        !          2125:    ControllerData - a pointer to our data area for this controller.
        !          2126: 
        !          2127:    ControllerNum - which controller in ConfigData we're working on.
        !          2128: 
        !          2129:    DisketteNum - which logical disk on the current controller we're
        !          2130:    working on.
        !          2131: 
        !          2132:    DisketteUnit - which physical disk on the current controller we're
        !          2133:    working on. Only different from DisketteNum when we're creating a
        !          2134:    secondary device object for a previously initialized drive.
        !          2135: 
        !          2136:    DriverObject - a pointer to the object that represents this device
        !          2137:    driver.
        !          2138: 
        !          2139: Return Value:
        !          2140: 
        !          2141:    STATUS_SUCCESS if this disk is initialized; an error otherwise.
        !          2142: 
        !          2143: --*/
        !          2144: 
        !          2145: {
        !          2146:    UCHAR ntNameBuffer[256];
        !          2147:    STRING ntNameString;
        !          2148:    UNICODE_STRING ntUnicodeString;
        !          2149:    NTSTATUS ntStatus;
        !          2150:    PDEVICE_OBJECT deviceObject = NULL;
        !          2151:    PTAPE_EXTENSION tapeExtension;
        !          2152:    STATUS retval;
        !          2153: 
        !          2154:    CheckedDump(QIC117INFO,( "Q117iInitializeDrive...\n" ));
        !          2155: 
        !          2156:    (VOID) sprintf(
        !          2157:       ntNameBuffer,
        !          2158:       "\\Device\\q117i%d", ConfigData->FloppyTapeCount);
        !          2159: 
        !          2160:    RtlInitString( &ntNameString, ntNameBuffer );
        !          2161: 
        !          2162:    ntStatus = RtlAnsiStringToUnicodeString(
        !          2163:       &ntUnicodeString,
        !          2164:       &ntNameString,
        !          2165:       TRUE );
        !          2166: 
        !          2167:    if ( NT_SUCCESS( ntStatus ) ) {
        !          2168: 
        !          2169:       //
        !          2170:       // Create a device object for this floppy drive.
        !          2171:       //
        !          2172: 
        !          2173:       ntStatus = IoCreateDevice(
        !          2174:             DriverObject,
        !          2175:             sizeof( TAPE_EXTENSION ),
        !          2176:             &ntUnicodeString,
        !          2177:             FILE_DEVICE_TAPE,
        !          2178:             FILE_REMOVABLE_MEDIA,
        !          2179:             FALSE,
        !          2180:             &deviceObject );
        !          2181: 
        !          2182:       RtlFreeUnicodeString(&ntUnicodeString);
        !          2183: 
        !          2184:    }
        !          2185: 
        !          2186: 
        !          2187: 
        !          2188:    if ( NT_SUCCESS( ntStatus ) ) {
        !          2189: 
        !          2190:       IoInitializeDpcRequest( deviceObject, Q117iTapeDeferredProcedure );
        !          2191: 
        !          2192:       tapeExtension = deviceObject->DeviceExtension;
        !          2193:       tapeExtension->SpeedChangeOK = FALSE;
        !          2194:       tapeExtension->PegasusSupported = TRUE;
        !          2195:       tapeExtension->Found = FALSE;
        !          2196:       tapeExtension->NoCart = TRUE;
        !          2197:       tapeExtension->ErrorSequence = 0;
        !          2198:       tapeExtension->TapeNumber = IoGetConfigurationInformation()->TapeCount;
        !          2199:       tapeExtension->DriveParms.Mode = PRIMARY_MODE;
        !          2200:       tapeExtension->DriveParms.Flavor = (UCHAR) UNKNOWN;
        !          2201:       tapeExtension->QDeviceObject = deviceObject;
        !          2202:       tapeExtension->QControllerData = ControllerData;
        !          2203:       tapeExtension->QControllerData->StartFormatMode = FALSE;
        !          2204:       tapeExtension->QControllerData->EndFormatMode = FALSE;
        !          2205:       tapeExtension->QControllerData->ClearQueue = FALSE;
        !          2206:       tapeExtension->QControllerData->AbortRequested = FALSE;
        !          2207:       tapeExtension->QControllerData->AdapterLocked = FALSE;
        !          2208:       tapeExtension->QControllerData->PerpendicularMode = FALSE;
        !          2209:       tapeExtension->XferRate.XferRate = SLOW;
        !          2210:       tapeExtension->XferRate.TapeSlow = TAPE_250Kbps;
        !          2211:       tapeExtension->XferRate.TapeFast = TAPE_500Kbps;
        !          2212:       tapeExtension->XferRate.FDC_Slow = FDC_250Kbps;
        !          2213:       tapeExtension->XferRate.FDC_Fast = FDC_500Kbps;
        !          2214:       tapeExtension->XferRate.SRT_Slow = SRT_250Kbps;
        !          2215:       tapeExtension->XferRate.SRT_Fast = SRT_500Kbps;
        !          2216: 
        !          2217:       tapeExtension->QControllerData->AdapterObject =
        !          2218:             ConfigData->Controller[ControllerNum].AdapterObject;
        !          2219: 
        !          2220:       tapeExtension->QControllerData->NumberOfMapRegisters =
        !          2221:             ConfigData->Controller[ControllerNum].NumberOfMapRegisters;
        !          2222: 
        !          2223:       tapeExtension->QControllerData->TapeExtension = tapeExtension;
        !          2224: 
        !          2225: #if DBG
        !          2226:       tapeExtension->DbgHead = tapeExtension->DbgTail = 0;
        !          2227: #endif
        !          2228: 
        !          2229:       tapeExtension->QControllerData->CurrentInterrupt = TRUE;
        !          2230: 
        !          2231: 
        !          2232:                retval = Q117iDLocateDrv(tapeExtension);
        !          2233: 
        !          2234:       tapeExtension->PersistentNewCart = FALSE;
        !          2235:       ntStatus = Q117iTranslateError( deviceObject, retval );
        !          2236:       tapeExtension->PersistentNewCart = TRUE;
        !          2237: 
        !          2238:       tapeExtension->QControllerData->CurrentInterrupt = FALSE;
        !          2239:    }
        !          2240: 
        !          2241:    //
        !          2242:    // Initialize the filer level tape device
        !          2243:    //
        !          2244: 
        !          2245:    if ( NT_SUCCESS( ntStatus ) ) {
        !          2246: 
        !          2247:       ntStatus = q117Initialize(
        !          2248:                         DriverObject,
        !          2249:                         deviceObject,
        !          2250:                         RegistryPath,
        !          2251:                         ConfigData->Controller[ControllerNum].AdapterObject,
        !          2252:                         ConfigData->Controller[ControllerNum].NumberOfMapRegisters
        !          2253:                         );
        !          2254: 
        !          2255:    }
        !          2256: 
        !          2257:    if ( NT_SUCCESS( ntStatus ) ) {
        !          2258: 
        !          2259:       ConfigData->FloppyTapeCount++;
        !          2260: 
        !          2261:    } else {
        !          2262: 
        !          2263:       //
        !          2264:       // If we're failing, clean up and delete the device object.
        !          2265:       //
        !          2266: 
        !          2267:      CheckedDump(QIC117DBGP,( "Q117i: InitializeDrive failing %x\n", ntStatus ));
        !          2268: 
        !          2269:       if ( deviceObject != NULL ) {
        !          2270: 
        !          2271:             IoDeleteDevice( deviceObject );
        !          2272:       }
        !          2273:    }
        !          2274: 
        !          2275:    return ntStatus;
        !          2276: }
        !          2277: 
        !          2278: ULONG
        !          2279: Q117iGetControllerBase(
        !          2280:    IN INTERFACE_TYPE BusType,
        !          2281:    IN ULONG BusNumber,
        !          2282:    PHYSICAL_ADDRESS IoAddress,
        !          2283:    ULONG NumberOfBytes,
        !          2284:    BOOLEAN InIoSpace,
        !          2285:    PBOOLEAN MappedAddress
        !          2286:    )
        !          2287: 
        !          2288: /*++
        !          2289: 
        !          2290: Routine Description:
        !          2291: 
        !          2292:    This routine maps an IO address to system address space.
        !          2293: 
        !          2294: Arguments:
        !          2295: 
        !          2296:    BusType - what type of bus - eisa, mca, isa
        !          2297:    IoBusNumber - which IO bus (for machines with multiple buses).
        !          2298:    IoAddress - base device address to be mapped.
        !          2299:    NumberOfBytes - number of bytes for which address is valid.
        !          2300:    InIoSpace - indicates an IO address.
        !          2301:    MappedAddress - indicates whether the address was mapped.
        !          2302:                   This only has meaning if the address returned
        !          2303:                   is non-null.
        !          2304: 
        !          2305: Return Value:
        !          2306: 
        !          2307:    Mapped address
        !          2308: 
        !          2309: --*/
        !          2310: 
        !          2311: {
        !          2312:    PHYSICAL_ADDRESS cardAddress;
        !          2313:    ULONG addressSpace = InIoSpace;
        !          2314:    ULONG Address;
        !          2315: 
        !          2316:    HalTranslateBusAddress(
        !          2317:             BusType,
        !          2318:             BusNumber,
        !          2319:             IoAddress,
        !          2320:             &addressSpace,
        !          2321:             &cardAddress
        !          2322:             );
        !          2323: 
        !          2324:    //
        !          2325:    // Map the device base address into the virtual address space
        !          2326:    // if the address is in memory space.
        !          2327:    //
        !          2328: 
        !          2329:    if (!addressSpace) {
        !          2330: 
        !          2331:       Address = (ULONG)MmMapIoSpace(
        !          2332:                         cardAddress,
        !          2333:                         NumberOfBytes,
        !          2334:                         FALSE
        !          2335:                         );
        !          2336: 
        !          2337:       *MappedAddress = (BOOLEAN)((Address)?(TRUE):(FALSE));
        !          2338: 
        !          2339: 
        !          2340:    } else {
        !          2341: 
        !          2342:       Address = (ULONG)cardAddress.LowPart;
        !          2343:    }
        !          2344: 
        !          2345:    return Address;
        !          2346: 
        !          2347: }
        !          2348: 

unix.superglobalmegacorp.com

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