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

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1990 Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     pardrvr.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains the code that does the non-initialization work
        !            12:     of the parallel driver.
        !            13: 
        !            14: Environment:
        !            15: 
        !            16:     Kernel mode
        !            17: 
        !            18: Revision History :
        !            19: 
        !            20:     The code is set up to be mostly interrupt driven.  Some printers
        !            21:     won't interrupt when initialized, so the is structured so that
        !            22:     when it starts a request, it will determine if a previous initialize
        !            23:     was done - and if so did it complete correctly.
        !            24: 
        !            25:     In addition, code has been adjusted so that an interrupt can't be
        !            26:     aquired for port, then we will drive the port using a timer dpc
        !            27:     that will attempt to push X characters out while polling the port.
        !            28:     If a port isn't ready after Y microseconds then the timer will be
        !            29:     resubmitted to try again later.
        !            30: 
        !            31: Access to device extension variables
        !            32: 
        !            33:     The access on these variables may be serialized :
        !            34:     TimerCount, Initialized, Initializing, CountBuffer, Command,
        !            35:     CompletingIoControl.
        !            36: 
        !            37:     TimerCount is useful for the management of timeout; when the driver
        !            38:     makes an operation on the controller, it sets a timeout, if the interrupt
        !            39:     genrated by ACK doesn't arrive the timer routine complete the
        !            40:     operation with a failure result.
        !            41:     TimerCount is modified by : InitializeDevice, ManageTimeOut,
        !            42:     InitiateIo, ISR.
        !            43: 
        !            44:     Initialized is true when the device is initialized.
        !            45:     Initialized is modified by : InitializeDevice, ISR, InitiateIo.
        !            46: 
        !            47:     Initializing is TRUE when an initialization of the device is going on.
        !            48:     Initializing is modified by : InitializeDevice, ISR,
        !            49:     ManageTimeOut.
        !            50: 
        !            51:     CountBuffer is != 0 when a writing is going on, it is the number of
        !            52:     characters the driver has still to send to the controller to end the
        !            53:     operation.
        !            54:     CountBuffer is modified by : Initialize, ManageTimeOut, ISR,
        !            55:     StartCriticalFunctions.
        !            56: 
        !            57:     Command is the command the driver is servicing.
        !            58:     Command is modified by : StartCriticalFunctions, ManageIoDevice.
        !            59: 
        !            60:     CompletingIoControl it is useful to synchronize Dpc and TimerRoutine
        !            61:     when IoControl is completing.
        !            62: 
        !            63: --*/
        !            64: 
        !            65: //
        !            66: // Note that we include ntddser that we can use the serials
        !            67: // timeout structure and ioctl to set the timeout for a write.
        !            68: //
        !            69: 
        !            70: #include <stddef.h>
        !            71: #include "ntddk.h"
        !            72: #include "ntddpar.h"
        !            73: #include "ntddser.h"
        !            74: #include "par.h"
        !            75: #include "parlog.h"
        !            76: 
        !            77: static const PHYSICAL_ADDRESS ParPhysicalZero = {0};
        !            78: 
        !            79: #define PAR_INIT_TIMEOUT_VALUE 2
        !            80: 
        !            81: #define VALID_FLAGS PARALLEL_INIT & ( PARALLEL_INIT | PARALLEL_AUTOFEED )
        !            82: 
        !            83: typedef enum _PAR_DPC_ACTION {
        !            84:     ParCompleteWrite,
        !            85:     ParCompleteSetIoctl,
        !            86:     ParUnknownError,
        !            87:     ParPoweredOff,
        !            88:     ParNotConnected,
        !            89:     ParOffline,
        !            90:     ParPaperEmpty,
        !            91:     ParBusy,
        !            92:     ParDebug,
        !            93:     ParCancel
        !            94:     } PAR_DPC_ACTION, *PPAR_ACTION;
        !            95: 
        !            96: typedef struct _CONTROL_AREA {
        !            97:     PPAR_DEVICE_EXTENSION Extension;
        !            98:     UCHAR Status;
        !            99:     UCHAR Control;
        !           100:     PIRP Irp;
        !           101: } CONTROL_AREA, *PCONTROL_AREA;
        !           102: 
        !           103: typedef struct _PAR_SYNCH_COUNT {
        !           104:     PPAR_DEVICE_EXTENSION Extension;
        !           105:     ULONG OldCount;
        !           106: } PAR_SYNCH_COUNT,*PPAR_SYNCH_COUNT;
        !           107: 
        !           108: 
        !           109: //
        !           110: // Declarations for all internal and external routines used by this module
        !           111: //
        !           112: 
        !           113: 
        !           114: 
        !           115: //
        !           116: //Macros definitions
        !           117: //
        !           118: 
        !           119: //
        !           120: // Busy, PE
        !           121: //
        !           122: 
        !           123: #define PAR_PAPER_EMPTY( Status ) ( \
        !           124:             (Status & PAR_STATUS_PE) )
        !           125: 
        !           126: //
        !           127: // Busy, not select, not error
        !           128: //
        !           129: 
        !           130: #define PAR_OFF_LINE( Status ) ( \
        !           131:             (Status & PAR_STATUS_NOT_ERROR) && \
        !           132:             ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
        !           133:             !(Status & PAR_STATUS_SLCT) )
        !           134: 
        !           135: //
        !           136: // error, ack, not busy
        !           137: //
        !           138: 
        !           139: #define PAR_POWERED_OFF( Status ) ( \
        !           140:             ((Status & PAR_STATUS_NOT_ERROR) ^ PAR_STATUS_NOT_ERROR) && \
        !           141:             ((Status & PAR_STATUS_NOT_ACK) ^ PAR_STATUS_NOT_ACK) && \
        !           142:             (Status & PAR_STATUS_NOT_BUSY))
        !           143: 
        !           144: //
        !           145: // not error, not busy, not select
        !           146: //
        !           147: 
        !           148: #define PAR_NOT_CONNECTED( Status ) ( \
        !           149:             (Status & PAR_STATUS_NOT_ERROR) && \
        !           150:             (Status & PAR_STATUS_NOT_BUSY) &&\
        !           151:             !(Status & PAR_STATUS_SLCT) )
        !           152: 
        !           153: //
        !           154: // not error, not busy
        !           155: //
        !           156: 
        !           157: #define PAR_OK(Status) ( \
        !           158:             (Status & PAR_STATUS_NOT_ERROR) && \
        !           159:             ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
        !           160:             (Status & PAR_STATUS_NOT_BUSY) )
        !           161: 
        !           162: //
        !           163: // not error, not busy, selected.
        !           164: //
        !           165: #define PAR_ONLINE(Status) ( \
        !           166:             (Status & PAR_STATUS_NOT_ERROR) && \
        !           167:             (Status & PAR_STATUS_NOT_BUSY) && \
        !           168:             ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
        !           169:             (Status & PAR_STATUS_SLCT) )
        !           170: 
        !           171: //
        !           172: // busy, select, not error
        !           173: //
        !           174: 
        !           175: #define PAR_POWERED_ON(Status) ( \
        !           176:             ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
        !           177:             (Status & PAR_STATUS_SLCT) && \
        !           178:             (Status & PAR_STATUS_NOT_ERROR))
        !           179: 
        !           180: //
        !           181: // busy, not error
        !           182: //
        !           183: 
        !           184: #define PAR_BUSY(Status) (\
        !           185:              (( Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
        !           186:              ( Status & PAR_STATUS_NOT_ERROR ) )
        !           187: 
        !           188: //
        !           189: // selected
        !           190: //
        !           191: 
        !           192: #define PAR_SELECTED(Status) ( \
        !           193:             ( Status & PAR_STATUS_SLCT ) )
        !           194: 
        !           195: //
        !           196: // No cable attached.
        !           197: //
        !           198: #define PAR_NO_CABLE(Status) ( \
        !           199:             ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
        !           200:             (Status & PAR_STATUS_NOT_ACK) &&                          \
        !           201:             (Status & PAR_STATUS_PE) &&                               \
        !           202:             (Status & PAR_STATUS_SLCT) &&                             \
        !           203:             (Status & PAR_STATUS_NOT_ERROR))
        !           204: 
        !           205: //
        !           206: // autofeed
        !           207: //
        !           208: 
        !           209: #define PAR_AUTOFEED( Control ) (\
        !           210:             ( Control & PAR_CONTROL_AUTOFD ) )
        !           211: 
        !           212: 
        !           213: BOOLEAN
        !           214: ParInitializeDevice(
        !           215:     IN PVOID Context
        !           216:     )
        !           217: 
        !           218: /*++
        !           219: 
        !           220: Routine Description:
        !           221: 
        !           222:     This routine is invoked to initialize the parallel port drive.
        !           223:     It performs the following actions:
        !           224: 
        !           225:         o   Sets the timer, because an interrupt is expected on the last
        !           226:             StoreControl
        !           227: 
        !           228:         o   Send INIT to the driver and if the device is online, it sends
        !           229:             SLIN
        !           230: 
        !           231:     This routine is invoked by ParInitialize and InterruptServiceRoutine, and
        !           232:     its execution is synchronized with ISR execution.
        !           233: 
        !           234: Arguments:
        !           235: 
        !           236:     Context - Really the device extension.
        !           237: 
        !           238: Return Value:
        !           239: 
        !           240:     Always FALSE.
        !           241: 
        !           242: --*/
        !           243: 
        !           244: {
        !           245: 
        !           246:     PPAR_DEVICE_EXTENSION extension = Context;
        !           247: 
        !           248:     ParDump(
        !           249:         PARINITDEV,
        !           250:         ("PARALLEL: In ParInitializeDevice - device status is %x\n",
        !           251:           GetStatus(extension->Controller))
        !           252:         );
        !           253: 
        !           254:     if ((!extension->Initialized) ||
        !           255:         ((extension->Command == ParSetInformation) &&
        !           256:          !extension->CompletingIoControl)) {
        !           257: 
        !           258:         UCHAR irqValue = ((extension->UsingATimer)?(0):
        !           259:                                                    (PAR_CONTROL_IRQ_ENB));
        !           260: 
        !           261:         extension->Initializing = TRUE;
        !           262: 
        !           263:         //
        !           264:         // Clear the register.
        !           265:         //
        !           266: 
        !           267:         if (GetControl(extension->Controller) &
        !           268:             PAR_CONTROL_NOT_INIT) {
        !           269: 
        !           270:             StoreControl(
        !           271:                 extension->Controller,
        !           272:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | irqValue)
        !           273:                 );
        !           274:             KeStallExecutionProcessor(60);
        !           275: 
        !           276:         }
        !           277: 
        !           278:         if (extension->AutoFeed) {
        !           279: 
        !           280:             StoreControl(
        !           281:                 extension->Controller,
        !           282:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
        !           283:                         PAR_CONTROL_AUTOFD | irqValue)
        !           284:                 );
        !           285: 
        !           286:         } else {
        !           287: 
        !           288:             StoreControl(
        !           289:                 extension->Controller,
        !           290:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
        !           291:                         irqValue)
        !           292:                 );
        !           293: 
        !           294:         }
        !           295: 
        !           296:         extension->TimerCount = PAR_INIT_TIMEOUT_VALUE;
        !           297: 
        !           298:     }
        !           299: 
        !           300:     return FALSE;
        !           301: 
        !           302: }
        !           303: 
        !           304: VOID
        !           305: ParTimerRoutine(
        !           306:     IN PDEVICE_OBJECT DeviceObject,
        !           307:     IN PVOID Context
        !           308:     )
        !           309: 
        !           310: /*++
        !           311: 
        !           312: Routine Description:
        !           313: 
        !           314:     This is the driver's timer routine.  It is invoked once every second.
        !           315:     The value of the timeout counter is set in the Interrupt Service Routine
        !           316:     (ISR) and decremented by the ParManageTimeOut function, invoked by this
        !           317:     routine.  If the current operation has timed out, then it is the function
        !           318:     of this routine to complete the current packet with an error status and
        !           319:     get the next operation started.
        !           320: 
        !           321:     A timeout may occur under any of the following conditions:
        !           322: 
        !           323:         o   The device is powered off.
        !           324: 
        !           325:         o   The device is disconnected.
        !           326: 
        !           327:         o   The device is off-line.
        !           328: 
        !           329:         o   PE?
        !           330: 
        !           331: Arguments:
        !           332: 
        !           333:     DeviceObject - Pointer to the device object associated with this device.
        !           334: 
        !           335:     Context - Unused context parameter.
        !           336: 
        !           337: Return value:
        !           338: 
        !           339:     None.
        !           340: 
        !           341: --*/
        !           342: 
        !           343: {
        !           344: 
        !           345:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
        !           346: 
        !           347:     UNREFERENCED_PARAMETER(Context);
        !           348: 
        !           349:     //
        !           350:     // the test isn't in a critical region, because it can loose a round
        !           351:     // It is useful to avoid the useless ParSynchronizeExecution call.
        !           352:     //
        !           353: 
        !           354:     if (extension->TimerCount != -1) {
        !           355: 
        !           356:         KIRQL cancelIrql;
        !           357: 
        !           358:         ParDump(
        !           359:             PARTIMEOUT,
        !           360:             ("PARALLEL: In ParTimerRoutine - about to sync with ISR\n")
        !           361:             );
        !           362:         IoAcquireCancelSpinLock(&cancelIrql);
        !           363:         ParSynchronizeExecution(
        !           364:             extension,
        !           365:             ParManageTimeOut,
        !           366:             DeviceObject
        !           367:             );
        !           368:         IoReleaseCancelSpinLock(cancelIrql);
        !           369: 
        !           370: 
        !           371:     }
        !           372: 
        !           373:     if (extension->StormKnocksOutInterrupts) {
        !           374: 
        !           375:         extension->StormKnocksOutInterrupts = FALSE;
        !           376: 
        !           377:         ParLogError(
        !           378:             DeviceObject->DriverObject,
        !           379:             DeviceObject,
        !           380:             extension->OriginalController,
        !           381:             ParPhysicalZero,
        !           382:             0,
        !           383:             0,
        !           384:             0,
        !           385:             41,
        !           386:             STATUS_SUCCESS,
        !           387:             PAR_INTERRUPT_STORM
        !           388:             );
        !           389: 
        !           390:     }
        !           391: 
        !           392: }
        !           393: 
        !           394: BOOLEAN
        !           395: ParManageTimeOut(
        !           396:     IN PVOID Context
        !           397:     )
        !           398: 
        !           399: /*++
        !           400: 
        !           401: Routine Description:
        !           402: 
        !           403:     This routine sets the status of the device in the extension when
        !           404:     an interrupt was expected didn't arrive and timeout was reached.
        !           405: 
        !           406:     This function is synchronized with the ISR.
        !           407: 
        !           408: Arguments:
        !           409: 
        !           410:     Context - Really a pointer to the device object.
        !           411: 
        !           412: Return value:
        !           413: 
        !           414:     Always FALSE.
        !           415: 
        !           416: --*/
        !           417: 
        !           418: {
        !           419: 
        !           420:     PDEVICE_OBJECT deviceObject = Context;
        !           421:     PPAR_DEVICE_EXTENSION extension = deviceObject->DeviceExtension;
        !           422: 
        !           423:     ParDump(
        !           424:         PARTIMEOUT,
        !           425:         ("PARALLEL: In ParManageTimeout\n")
        !           426:         );
        !           427: 
        !           428:     //
        !           429:     // Reset the storm interrupt count back to zero on each timer tick.
        !           430:     //
        !           431: 
        !           432:     extension->UnexpectedCount = 0;
        !           433: 
        !           434:     if (extension->TimerCount < 0) {
        !           435: 
        !           436:         //
        !           437:         // Nothing to do.
        !           438:         //
        !           439:         return FALSE;
        !           440: 
        !           441:     } else {
        !           442: 
        !           443:         //
        !           444:         // We can assume that we are called with the cancel spinlock
        !           445:         // held.  Check to see if we have a current irp, and if so
        !           446:         // was it canceled.
        !           447:         //
        !           448: 
        !           449:         if (deviceObject->CurrentIrp) {
        !           450: 
        !           451:             if (deviceObject->CurrentIrp->Cancel) {
        !           452: 
        !           453:                 ParDump(
        !           454:                     PARTIMEOUT,
        !           455:                     ("PARALLEL: In ParManageTimeout - irp %x has been cancelled\n",
        !           456:                      deviceObject->CurrentIrp)
        !           457:                     );
        !           458:                 extension->TimerCount = -1;
        !           459:                 IoRequestDpc(
        !           460:                     deviceObject,
        !           461:                     deviceObject->CurrentIrp,
        !           462:                     (PVOID)ParCancel
        !           463:                     );
        !           464:                 return FALSE;
        !           465: 
        !           466:             }
        !           467: 
        !           468:         }
        !           469: 
        !           470:         if (extension->TimerCount > 0) {
        !           471: 
        !           472:             //
        !           473:             // We are going to call the isr routine.  We do this
        !           474:             // so that if the device went on/off line during IO
        !           475:             // we can start up the IO again.  The driver will NOT
        !           476:             // put a character out to the device if it is off line.
        !           477:             //
        !           478: 
        !           479:             ParInterruptServiceRoutine(
        !           480:                 extension->Interrupt,
        !           481:                 extension->DeviceObject
        !           482:                 );
        !           483:             if (extension->TimerCount != -1) {
        !           484: 
        !           485:                 ASSERT(extension->TimerCount);
        !           486:                 extension->TimerCount--;
        !           487: 
        !           488:             }
        !           489:             return FALSE;
        !           490: 
        !           491:         } else {
        !           492: 
        !           493:             UCHAR deviceStatus = GetStatus(extension->Controller);
        !           494:             PAR_DPC_ACTION action;
        !           495: 
        !           496:             extension->TimerCount = -1;
        !           497: 
        !           498:             ParDump(
        !           499:                 PARTIMEOUT,
        !           500:                 ("PARALLEL: In timeout status of device is %x\n",
        !           501:                  deviceStatus)
        !           502:                 );
        !           503: 
        !           504:             //
        !           505:             // CountBuffer is = 0 if no packet is being writtten or a Dpc
        !           506:             // is completing a request
        !           507:             //
        !           508: 
        !           509:             if (extension->Initializing) {
        !           510: 
        !           511:                 extension->Initializing = FALSE;
        !           512: 
        !           513:                 //
        !           514:                 // This is a patch for the Centronic Interface for the
        !           515:                 // laser printer that hasn't INIT pin, so it doesn't
        !           516:                 // generate an interrupt when it is initialized.
        !           517:                 //
        !           518: 
        !           519:                 if (PAR_OK(deviceStatus)) {
        !           520: 
        !           521:                     ParDump(
        !           522:                         PARTIMEOUT,
        !           523:                         ("PARALLEL - ParManageTimeout: In centronics patch\n")
        !           524:                         );
        !           525:                     extension->Initialized = TRUE;
        !           526: 
        !           527:                     if ((extension->Command == ParSetInformation) &&
        !           528:                         !extension->CompletingIoControl ) {
        !           529: 
        !           530:                           extension->CompletingIoControl = TRUE;
        !           531:                           IoRequestDpc(
        !           532:                               deviceObject,
        !           533:                               deviceObject->CurrentIrp,
        !           534:                               (PVOID)ParCompleteSetIoctl
        !           535:                               );
        !           536: 
        !           537:                     }
        !           538: 
        !           539:                     return FALSE;
        !           540: 
        !           541:                 }
        !           542: 
        !           543:             }
        !           544: 
        !           545:             if ((extension->CountBuffer != 0) ||
        !           546:                 ((extension->Command == ParSetInformation ) &&
        !           547:                  !extension->CompletingIoControl)) {
        !           548: 
        !           549:                 extension->CompletingIoControl = TRUE;
        !           550: 
        !           551:                 if (PAR_POWERED_OFF(deviceStatus) ||
        !           552:                     PAR_NO_CABLE(deviceStatus)) {
        !           553: 
        !           554:                     ParDump(
        !           555:                         PARTIMEOUT,
        !           556:                         ("PARALLEL - ParManageTimeout: powered off\n")
        !           557:                         );
        !           558:                     extension->Initialized = FALSE;
        !           559:                     action = ParPoweredOff;
        !           560: 
        !           561:                 } else if (PAR_NOT_CONNECTED(deviceStatus)) {
        !           562: 
        !           563:                     ParDump(
        !           564:                         PARTIMEOUT,
        !           565:                         ("PARALLEL - ParManageTimeout: not connected\n")
        !           566:                         );
        !           567:                     extension->Initialized = FALSE;
        !           568:                     action = ParNotConnected;
        !           569: 
        !           570:                 } else if (PAR_OFF_LINE(deviceStatus)) {
        !           571: 
        !           572:                     ParDump(
        !           573:                         PARTIMEOUT,
        !           574:                         ("PARALLEL - ParManageTimeout: off line\n")
        !           575:                         );
        !           576:                     action = ParOffline;
        !           577: 
        !           578:                 } else if (PAR_PAPER_EMPTY(deviceStatus)) {
        !           579: 
        !           580:                     ParDump(
        !           581:                         PARTIMEOUT,
        !           582:                         ("PARALLEL - ParManageTimeout: paper empty\n")
        !           583:                         );
        !           584:                     action = ParPaperEmpty;
        !           585: 
        !           586:                 } else if (PAR_BUSY(deviceStatus)) {
        !           587: 
        !           588:                     ParDump(
        !           589:                         PARTIMEOUT,
        !           590:                         ("PARALLEL - ParManageTimeout: busy\n")
        !           591:                         );
        !           592:                     action = ParBusy;
        !           593: 
        !           594:                 } else {
        !           595: 
        !           596:                     //
        !           597:                     // This code should never be executed.
        !           598:                     //
        !           599: 
        !           600:                     ParDump(
        !           601:                         PARTIMEOUT,
        !           602:                         ("PARALLEL - ParManageTimeout: shouldn't be here\n")
        !           603:                         );
        !           604:                     extension->Initialized = FALSE;
        !           605:                     action = ParUnknownError;
        !           606: 
        !           607:                 }
        !           608: 
        !           609:                 IoRequestDpc(
        !           610:                     deviceObject,
        !           611:                     deviceObject->CurrentIrp,
        !           612:                     (PVOID)action
        !           613:                     );
        !           614: 
        !           615:             }
        !           616: 
        !           617:         }
        !           618: 
        !           619:     }
        !           620: 
        !           621:     return FALSE;
        !           622: }
        !           623: 
        !           624: BOOLEAN
        !           625: ParSetTimerStart(
        !           626:     IN PVOID Context
        !           627:     )
        !           628: 
        !           629: /*++
        !           630: 
        !           631: Routine Description:
        !           632: 
        !           633:     This routine is invoked via KeSynchronize.  It is used to
        !           634:     set the value that we should start counting down with
        !           635:     after every successful IO operation.
        !           636: 
        !           637: Arguments:
        !           638: 
        !           639:     Context - Really a pointer to the irp.
        !           640: 
        !           641: Return Value:
        !           642: 
        !           643:     Always False.
        !           644: 
        !           645: --*/
        !           646: 
        !           647: {
        !           648: 
        !           649:     PPAR_DEVICE_EXTENSION extension =
        !           650:         IoGetCurrentIrpStackLocation((PIRP)Context)
        !           651:             ->DeviceObject->DeviceExtension;
        !           652: 
        !           653:     PSERIAL_TIMEOUTS New =
        !           654:         ((PSERIAL_TIMEOUTS)(((PIRP)Context)->AssociatedIrp.SystemBuffer));
        !           655: 
        !           656:     ParDump(
        !           657:         PARDISPATCH,
        !           658:         ("Parallel: SET TIME OUT to %d seconds\n",
        !           659:           extension->TimerStart)
        !           660:         );
        !           661:     extension->TimerStart = New->WriteTotalTimeoutConstant / 1000;
        !           662: 
        !           663:     return FALSE;
        !           664: }
        !           665: 
        !           666: NTSTATUS
        !           667: ParDispatch(
        !           668:     IN PDEVICE_OBJECT DeviceObject,
        !           669:     IN PIRP Irp
        !           670:     )
        !           671: 
        !           672: /*++
        !           673: 
        !           674: Routine Description:
        !           675: 
        !           676:     This is the main dispatch routine for the parallel port driver.
        !           677:     It is given a pointer to the IRP for the current request and
        !           678:     it determines what to do with it. If the request is valid and doen't
        !           679:     have any parameter errors, then it is placed into the work queue.
        !           680:     Otherwise it is not completed and an appropriate error is returned.
        !           681: 
        !           682: Arguments:
        !           683: 
        !           684:     DeviceObject - Pointer to the device object for this device
        !           685: 
        !           686:     Irp - Pointer to the IRP for the current request
        !           687: 
        !           688: Return Value:
        !           689: 
        !           690:     The function value is the final status of the call
        !           691: 
        !           692: --*/
        !           693: 
        !           694: {
        !           695: 
        !           696:     NTSTATUS status = STATUS_SUCCESS;
        !           697:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
        !           698:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
        !           699: 
        !           700:     ParDump(
        !           701:         PARDISPATCH,
        !           702:         ("PARALLEL: In main dispatch with IRP: %x\n",
        !           703:          Irp)
        !           704:         );
        !           705:     Irp->IoStatus.Information=0L;
        !           706:     switch(irpSp->MajorFunction) {
        !           707: 
        !           708:         case IRP_MJ_CLOSE: {
        !           709: 
        !           710:             ParDump(
        !           711:                 PARDISPATCH,
        !           712:                 ("PARALLEL: About to close the port for extension: %x\n",
        !           713:                  extension)
        !           714:                 );
        !           715:             //
        !           716:             // Before we close we want to wait until the busy
        !           717:             // path is false.  We don't want any paths of
        !           718:             // execution running around while we're closed.
        !           719:             //
        !           720: 
        !           721:             while (extension->BusyPath) {
        !           722: 
        !           723:                 KeDelayExecutionThread(
        !           724:                     KernelMode,
        !           725:                     FALSE,
        !           726:                     &extension->BusyDelayAmount
        !           727:                     );
        !           728: 
        !           729:             }
        !           730:             break;
        !           731: 
        !           732: 
        !           733:         }
        !           734:         case IRP_MJ_CREATE:
        !           735: 
        !           736:             ParDump(
        !           737:                 PARDISPATCH,
        !           738:                 ("PARALLEL: About to open the port for extension: %x\n",
        !           739:                  extension)
        !           740:                 );
        !           741:             //
        !           742:             // Let's make sure they aren't trying to create a directory.
        !           743:             // This is a silly, but what's a driver to do!?
        !           744:             //
        !           745: 
        !           746:             if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) {
        !           747: 
        !           748:                 status = STATUS_NOT_A_DIRECTORY;
        !           749: 
        !           750:             }
        !           751: 
        !           752:             break;
        !           753: 
        !           754:         case IRP_MJ_WRITE:
        !           755: 
        !           756:             ParDump(
        !           757:                 PARDISPATCH,
        !           758:                 ("PARALLEL: Starting write IRP: %x for extension: %x\n",
        !           759:                  Irp,
        !           760:                  extension)
        !           761:                 );
        !           762:             if ((irpSp->Parameters.Write.ByteOffset.HighPart != 0) ||
        !           763:                 (irpSp->Parameters.Write.ByteOffset.LowPart != 0)) {
        !           764: 
        !           765:                 status = STATUS_INVALID_PARAMETER;
        !           766: 
        !           767:             } else {
        !           768: 
        !           769:                 if (irpSp->Parameters.Write.Length != 0) {
        !           770: 
        !           771:                     status = STATUS_PENDING;
        !           772:                 }
        !           773: 
        !           774:             }
        !           775: 
        !           776:             break;
        !           777: 
        !           778:         case IRP_MJ_DEVICE_CONTROL:
        !           779: 
        !           780:             ParDump(
        !           781:                 PARDISPATCH,
        !           782:                 ("PARALLEL: Starting device controlIRP: %x for extension: %x\n",
        !           783:                  Irp,
        !           784:                  extension)
        !           785:                 );
        !           786:             switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
        !           787: 
        !           788:                 case IOCTL_PAR_SET_INFORMATION :
        !           789: 
        !           790:                     if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
        !           791:                         1) {
        !           792: 
        !           793:                         status = STATUS_BUFFER_TOO_SMALL;
        !           794: 
        !           795:                     } else {
        !           796: 
        !           797:                         PPAR_SET_INFORMATION irpBuffer =
        !           798:                             Irp->AssociatedIrp.SystemBuffer;
        !           799: 
        !           800:                         //
        !           801:                         // INIT is required, AUTOFEED is optional
        !           802:                         //
        !           803: 
        !           804:                         if (!(irpBuffer->Init & PARALLEL_INIT) ||
        !           805:                              (irpBuffer->Init & ~VALID_FLAGS)) {
        !           806: 
        !           807:                             status = STATUS_INVALID_PARAMETER;
        !           808: 
        !           809:                         } else {
        !           810: 
        !           811:                             status = STATUS_PENDING;
        !           812:                         }
        !           813: 
        !           814:                     }
        !           815: 
        !           816:                     break;
        !           817: 
        !           818:                 case IOCTL_PAR_QUERY_INFORMATION :
        !           819: 
        !           820:                     if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
        !           821:                         sizeof(PAR_QUERY_INFORMATION)) {
        !           822: 
        !           823:                         status = STATUS_BUFFER_TOO_SMALL;
        !           824: 
        !           825:                     } else {
        !           826: 
        !           827:                         status = STATUS_PENDING;
        !           828:                     }
        !           829: 
        !           830:                     break;
        !           831: 
        !           832:                 case IOCTL_SERIAL_SET_TIMEOUTS: {
        !           833: 
        !           834:                     PSERIAL_TIMEOUTS NewTimeouts =
        !           835:                         ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
        !           836: 
        !           837:                     ParDump(
        !           838:                         PARDISPATCH,
        !           839:                         ("PARALLEL: Got a set timeouts irp: %x for extension: %x\n",
        !           840:                          Irp,
        !           841:                          extension)
        !           842:                         );
        !           843: 
        !           844:                     if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
        !           845:                         sizeof(SERIAL_TIMEOUTS)) {
        !           846: 
        !           847:                         status = STATUS_BUFFER_TOO_SMALL;
        !           848:                         break;
        !           849: 
        !           850:                     } else if (NewTimeouts->WriteTotalTimeoutConstant < 2000) {
        !           851: 
        !           852:                         status = STATUS_INVALID_PARAMETER;
        !           853:                         break;
        !           854: 
        !           855:                     }
        !           856: 
        !           857:                     ParSynchronizeExecution(
        !           858:                         extension,
        !           859:                         ParSetTimerStart,
        !           860:                         Irp
        !           861:                         );
        !           862: 
        !           863:                     break;
        !           864: 
        !           865:                 }
        !           866:                 case IOCTL_SERIAL_GET_TIMEOUTS:
        !           867: 
        !           868:                     if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
        !           869:                         sizeof(SERIAL_TIMEOUTS)) {
        !           870: 
        !           871:                         status = STATUS_BUFFER_TOO_SMALL;
        !           872:                         break;
        !           873: 
        !           874:                     }
        !           875: 
        !           876:                     //
        !           877:                     // We don't need to synchronize the read.
        !           878:                     //
        !           879: 
        !           880:                     RtlZeroMemory(
        !           881:                         Irp->AssociatedIrp.SystemBuffer,
        !           882:                         sizeof(SERIAL_TIMEOUTS)
        !           883:                         );
        !           884:                     Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
        !           885:                     ((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer)->
        !           886:                         WriteTotalTimeoutConstant =
        !           887:                         extension->TimerStart * 1000;
        !           888: 
        !           889:                     break;
        !           890: 
        !           891:                 default :
        !           892: 
        !           893:                     status = STATUS_INVALID_PARAMETER;
        !           894:                     break;
        !           895: 
        !           896:             }
        !           897: 
        !           898:             break;
        !           899: 
        !           900:     }
        !           901: 
        !           902:     Irp->IoStatus.Status = status;
        !           903: 
        !           904:     if (status == STATUS_PENDING) {
        !           905: 
        !           906:         IoMarkIrpPending(Irp);
        !           907:         IoStartPacket(
        !           908:             DeviceObject,
        !           909:             Irp,
        !           910:             (PULONG)NULL,
        !           911:             ParCancelRequest
        !           912:             );
        !           913: 
        !           914:     } else {
        !           915: 
        !           916:         ParDump(
        !           917:             PARIRPCOMPLETE,
        !           918:             ("PARALLEL: About to complete IRP in dispatch: %x\n",Irp)
        !           919:             );
        !           920:         IoCompleteRequest(
        !           921:             Irp,
        !           922:             IO_NO_INCREMENT
        !           923:             );
        !           924: 
        !           925:     }
        !           926: 
        !           927:     return status;
        !           928: 
        !           929: }
        !           930: 
        !           931: NTSTATUS
        !           932: ParQueryInformationFile(
        !           933:     IN PDEVICE_OBJECT DeviceObject,
        !           934:     IN PIRP Irp
        !           935:     )
        !           936: 
        !           937: /*++
        !           938: 
        !           939: Routine Description:
        !           940: 
        !           941:     This routine is used to query the end of file information on
        !           942:     the opened parallel port.  Any other file information request
        !           943:     is retured with an invalid parameter.
        !           944: 
        !           945:     This routine always returns an end of file of 0.
        !           946: 
        !           947: Arguments:
        !           948: 
        !           949:     DeviceObject - Pointer to the device object for this device
        !           950: 
        !           951:     Irp - Pointer to the IRP for the current request
        !           952: 
        !           953: Return Value:
        !           954: 
        !           955:     The function value is the final status of the call
        !           956: 
        !           957: --*/
        !           958: 
        !           959: {
        !           960:     //
        !           961:     // The status that gets returned to the caller and
        !           962:     // set in the Irp.
        !           963:     //
        !           964:     NTSTATUS status = STATUS_SUCCESS;
        !           965: 
        !           966:     //
        !           967:     // The current stack location.  This contains all of the
        !           968:     // information we need to process this particular request.
        !           969:     //
        !           970:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
        !           971: 
        !           972:     UNREFERENCED_PARAMETER(DeviceObject);
        !           973: 
        !           974:     ParDump(
        !           975:         PARDISPATCH,
        !           976:         ("PARALLEL: In query information file with Irp: %x\n",
        !           977:          Irp)
        !           978:         );
        !           979:     Irp->IoStatus.Information = 0L;
        !           980:     if (irpSp->Parameters.QueryFile.FileInformationClass ==
        !           981:         FileStandardInformation) {
        !           982: 
        !           983:         PFILE_STANDARD_INFORMATION buf = Irp->AssociatedIrp.SystemBuffer;
        !           984: 
        !           985:         buf->AllocationSize = RtlConvertUlongToLargeInteger(0ul);
        !           986:         buf->EndOfFile = buf->AllocationSize;
        !           987:         buf->NumberOfLinks = 0;
        !           988:         buf->DeletePending = FALSE;
        !           989:         buf->Directory = FALSE;
        !           990:         Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
        !           991: 
        !           992:     } else if (irpSp->Parameters.QueryFile.FileInformationClass ==
        !           993:                FilePositionInformation) {
        !           994: 
        !           995:         ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->
        !           996:             CurrentByteOffset = RtlConvertUlongToLargeInteger(0ul);
        !           997:         Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
        !           998: 
        !           999:     } else {
        !          1000: 
        !          1001:         status = STATUS_INVALID_PARAMETER;
        !          1002: 
        !          1003:     }
        !          1004: 
        !          1005:     Irp->IoStatus.Status = status;
        !          1006:     ParDump(
        !          1007:         PARIRPCOMPLETE,
        !          1008:         ("PARALLEL: About to complete IRP: %x\n",Irp)
        !          1009:         );
        !          1010:     IoCompleteRequest(
        !          1011:         Irp,
        !          1012:         IO_NO_INCREMENT
        !          1013:         );
        !          1014: 
        !          1015:     return status;
        !          1016: 
        !          1017: }
        !          1018: 
        !          1019: NTSTATUS
        !          1020: ParSetInformationFile(
        !          1021:     IN PDEVICE_OBJECT DeviceObject,
        !          1022:     IN PIRP Irp
        !          1023:     )
        !          1024: 
        !          1025: /*++
        !          1026: 
        !          1027: Routine Description:
        !          1028: 
        !          1029:     This routine is used to set the end of file information on
        !          1030:     the opened parallel port.  Any other file information request
        !          1031:     is retured with an invalid parameter.
        !          1032: 
        !          1033:     This routine always ignores the actual end of file since
        !          1034:     the query information code always returns an end of file of 0.
        !          1035: 
        !          1036: Arguments:
        !          1037: 
        !          1038:     DeviceObject - Pointer to the device object for this device
        !          1039: 
        !          1040:     Irp - Pointer to the IRP for the current request
        !          1041: 
        !          1042: Return Value:
        !          1043: 
        !          1044:     The function value is the final status of the call
        !          1045: 
        !          1046: --*/
        !          1047: 
        !          1048: {
        !          1049: 
        !          1050:     NTSTATUS status = STATUS_SUCCESS;
        !          1051: 
        !          1052:     UNREFERENCED_PARAMETER(DeviceObject);
        !          1053: 
        !          1054:     ParDump(
        !          1055:         PARDISPATCH,
        !          1056:         ("PARALLEL: In set information with IRP: %x\n",
        !          1057:          Irp)
        !          1058:         );
        !          1059:     Irp->IoStatus.Information = 0L;
        !          1060:     if (IoGetCurrentIrpStackLocation(Irp)->
        !          1061:             Parameters.SetFile.FileInformationClass !=
        !          1062:         FileEndOfFileInformation) {
        !          1063: 
        !          1064:         status = STATUS_INVALID_PARAMETER;
        !          1065: 
        !          1066:     }
        !          1067: 
        !          1068:     Irp->IoStatus.Status = status;
        !          1069:     ParDump(
        !          1070:         PARIRPCOMPLETE,
        !          1071:         ("PARALLEL: About to complete IRP: %x\n",Irp)
        !          1072:         );
        !          1073:     IoCompleteRequest(
        !          1074:         Irp,
        !          1075:         IO_NO_INCREMENT
        !          1076:         );
        !          1077: 
        !          1078:     return status;
        !          1079: 
        !          1080: }
        !          1081: 
        !          1082: VOID
        !          1083: ParCheckTheWeather(
        !          1084:     IN PPAR_DEVICE_EXTENSION Extension
        !          1085:     )
        !          1086: 
        !          1087: /*++
        !          1088: 
        !          1089: Routine Description:
        !          1090: 
        !          1091:     This routine checks to see if we've gotten too many interrupts
        !          1092:     within a certain amount of time.  If so we turn the device into
        !          1093:     a polling device.  This is to deal with interrupt storms.
        !          1094: 
        !          1095: Arguments:
        !          1096: 
        !          1097:     Extension - Pointer to the device extension.
        !          1098: 
        !          1099: Return Value:
        !          1100: 
        !          1101:     None.
        !          1102: 
        !          1103: --*/
        !          1104: 
        !          1105: {
        !          1106: 
        !          1107:     //
        !          1108:     // We've sometimes seen interrupt storms.  If had no work to do
        !          1109:     // and we are on an EISA or an ISA bus and we've exceeded the
        !          1110:     // threshold for interrupts that weren't ours, then turn off
        !          1111:     // interrupts, turn on the using a timer flag, and set a variable
        !          1112:     // that our one second timer routine will note to cause it to
        !          1113:     // put an event in the event log that this occured.
        !          1114: 
        !          1115:     if ((Extension->UnexpectedCount > PARALLEL_STORM_WATCH) &&
        !          1116:         (!Extension->UsingATimer) &&
        !          1117:         ((Extension->InterfaceType == Eisa) ||
        !          1118:          (Extension->InterfaceType == Isa))) {
        !          1119: 
        !          1120:         if (Extension->AutoFeed) {
        !          1121: 
        !          1122:             StoreControl(
        !          1123:                 Extension->Controller,
        !          1124:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
        !          1125:                         PAR_CONTROL_AUTOFD)
        !          1126:                 );
        !          1127: 
        !          1128:         } else {
        !          1129: 
        !          1130:             StoreControl(
        !          1131:                 Extension->Controller,
        !          1132:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT)
        !          1133:                 );
        !          1134: 
        !          1135:         }
        !          1136: 
        !          1137:         Extension->StormKnocksOutInterrupts = TRUE;
        !          1138:         Extension->UsingATimer = TRUE;
        !          1139: 
        !          1140:     }
        !          1141: 
        !          1142: }
        !          1143: 
        !          1144: BOOLEAN
        !          1145: ParInterruptServiceRoutine(
        !          1146:     IN PKINTERRUPT InterruptObject,
        !          1147:     IN PVOID Context
        !          1148:     )
        !          1149: 
        !          1150: /*++
        !          1151: 
        !          1152: Routine Description:
        !          1153: 
        !          1154:     This is the interrupt service routine for the parallel port driver.
        !          1155:     An interrupt will occur under any of the following conditions:
        !          1156: 
        !          1157:         o   A character was received by the device
        !          1158: 
        !          1159:         o   The device's power was switched off
        !          1160: 
        !          1161:         o   In some printers PAPER_EMPTY and OFF_LINE don't generate
        !          1162:             interrupts, but they are read on the status when a character
        !          1163:             is received ( because the printer accepts one more character )
        !          1164: 
        !          1165: Arguments:
        !          1166: 
        !          1167:     InterruptObject - Pointer to the interrupt object used to connect
        !          1168:             to the interrupt vector for the parallel port
        !          1169: 
        !          1170:     Context - Really a Pointer to the device object for the parallel
        !          1171:              port device that is interrupting
        !          1172: 
        !          1173: Return Value:
        !          1174: 
        !          1175:     Returns TRUE if an interrupt was expected from the device;
        !          1176:     otherwise FALSE
        !          1177: 
        !          1178: --*/
        !          1179: 
        !          1180: {
        !          1181: 
        !          1182:     LONG saveTimer;
        !          1183:     PDEVICE_OBJECT deviceObject = Context;
        !          1184:     PPAR_DEVICE_EXTENSION extension = deviceObject->DeviceExtension;
        !          1185:     UCHAR deviceStatus;
        !          1186:     PAR_DPC_ACTION action;
        !          1187: 
        !          1188:     UNREFERENCED_PARAMETER(InterruptObject);
        !          1189: 
        !          1190:     deviceStatus = GetStatus(extension->Controller);
        !          1191: 
        !          1192:     ParDump(
        !          1193:         PARISR,
        !          1194:         ("PARALLEL: ISR - device status is %x\n",deviceStatus)
        !          1195:         );
        !          1196:     //
        !          1197:     // saveTimer == -1 implies that there is no current operation
        !          1198:     // in progress.
        !          1199:     //
        !          1200: 
        !          1201:     saveTimer = extension->TimerCount;
        !          1202:     action = ParUnknownError;
        !          1203:     extension->TimerCount = -1;
        !          1204: 
        !          1205:     if (extension->Initializing) {
        !          1206: 
        !          1207:         ParDump(
        !          1208:             PARISR,
        !          1209:             ("PARALLEL: ISR - In initializing code path\n")
        !          1210:             );
        !          1211:         extension->Initializing = FALSE;
        !          1212: 
        !          1213:         if (PAR_OK(deviceStatus)) {
        !          1214: 
        !          1215:             extension->Initialized = TRUE;
        !          1216:             if ((extension->Command == ParSetInformation) &&
        !          1217:                 !extension->CompletingIoControl) {
        !          1218: 
        !          1219:                 ParDump(
        !          1220:                     PARISR,
        !          1221:                     ("PARALLEL: ISR - Completing IO control\n")
        !          1222:                     );
        !          1223:                 extension->CompletingIoControl = TRUE;
        !          1224:                 IoRequestDpc(
        !          1225:                     deviceObject,
        !          1226:                     deviceObject->CurrentIrp,
        !          1227:                     (PVOID)ParCompleteWrite
        !          1228:                     );
        !          1229: 
        !          1230:             } else if ((extension->CountBuffer != 0) &&
        !          1231:                        (saveTimer != -1)) {
        !          1232: 
        !          1233:                 ParDump(
        !          1234:                     PARISR,
        !          1235:                     ("PARALLEL: ISR Doing More writes - count:%d\n",
        !          1236:                      extension->CountBuffer)
        !          1237:                     );
        !          1238:                 ParInitiateIo(deviceObject);
        !          1239: 
        !          1240:             }
        !          1241: 
        !          1242:             return TRUE;
        !          1243: 
        !          1244:         } else if ((extension->CountBuffer != 0 ) ||
        !          1245:                    (extension->Command == ParSetInformation) &&
        !          1246:                     !extension->CompletingIoControl) {
        !          1247: 
        !          1248:             if (PAR_POWERED_OFF(deviceStatus)) {
        !          1249: 
        !          1250:                 //
        !          1251:                 // For the real powered off case make sure we aren't
        !          1252:                 // getting an interrupt storm from turning an HPxp
        !          1253:                 // off on an MIO-X00 adapter.
        !          1254:                 //
        !          1255:                 // If it is just an simple turning off then bumping
        !          1256:                 // the unexpected count up won't hurt.
        !          1257:                 //
        !          1258: 
        !          1259:                 extension->UnexpectedCount++;
        !          1260:                 action = ParPoweredOff;
        !          1261:                 ParCheckTheWeather(extension);
        !          1262: 
        !          1263:             } else if (PAR_NO_CABLE(deviceStatus)) {
        !          1264: 
        !          1265:                 action = ParPoweredOff;
        !          1266: 
        !          1267:             } else if (PAR_OFF_LINE(deviceStatus) ||
        !          1268:                        PAR_PAPER_EMPTY(deviceStatus)) {
        !          1269: 
        !          1270:                 //
        !          1271:                 // Paper empty or device off line should let
        !          1272:                 // the normal time out code handle the problem
        !          1273:                 //
        !          1274: 
        !          1275:                 extension->TimerCount = saveTimer;
        !          1276:                 return TRUE;
        !          1277: 
        !          1278:             } else if (PAR_PAPER_EMPTY(deviceStatus)) {
        !          1279: 
        !          1280:                 action = ParPaperEmpty;
        !          1281: 
        !          1282:             } else if (PAR_NOT_CONNECTED(deviceStatus)) {
        !          1283: 
        !          1284:                 action = ParNotConnected;
        !          1285: 
        !          1286:             } else if (PAR_BUSY(deviceStatus)) {
        !          1287: 
        !          1288:                 //
        !          1289:                 // For the busy state we will just let the regular timeout code
        !          1290:                 // handle it.
        !          1291:                 //
        !          1292:                 extension->TimerCount = saveTimer;
        !          1293:                 return TRUE;
        !          1294: 
        !          1295:             }
        !          1296: 
        !          1297:             ParDump(
        !          1298:                 PARISR | PARISRACTION,
        !          1299:                 ("PARALLEL: ISR Completing request with bad status - ACTION: %d\n",
        !          1300:                  action)
        !          1301:                 );
        !          1302:             IoRequestDpc(
        !          1303:                 deviceObject,
        !          1304:                 deviceObject->CurrentIrp,
        !          1305:                 (PVOID)action
        !          1306:                 );
        !          1307: 
        !          1308:             return TRUE;
        !          1309: 
        !          1310:         }
        !          1311: 
        !          1312:     } else {
        !          1313: 
        !          1314:         //
        !          1315:         // The port is not being initialized at this point.  Check to see
        !          1316:         // whether or not it has been initialized at all and drive the
        !          1317:         // remainder of the ISR based on the result.
        !          1318:         //
        !          1319: 
        !          1320:         if (extension->Initialized) {
        !          1321: 
        !          1322:             ParDump(
        !          1323:                 PARISR,
        !          1324:                 ("PARALLEL - ISR Inited path\n")
        !          1325:                 );
        !          1326: 
        !          1327: 
        !          1328:             if (PAR_OK(deviceStatus) && PAR_ONLINE(deviceStatus) &&
        !          1329:                (saveTimer != -1)) {
        !          1330: 
        !          1331:                 if (extension->CountBuffer > 0) {
        !          1332: 
        !          1333:                     ParDump(
        !          1334:                         PARISR,
        !          1335:                         ("PARALLEL - ISR Inited - more io - count:%d\n",
        !          1336:                          extension->CountBuffer)
        !          1337:                         );
        !          1338:                     ParInitiateIo(deviceObject);
        !          1339: 
        !          1340:                 } else {
        !          1341: 
        !          1342:                     ParDump(
        !          1343:                         PARISR,
        !          1344:                         ("PARALLEL - ISR Inited - good io all done:\n")
        !          1345:                         );
        !          1346:                     IoRequestDpc(
        !          1347:                         deviceObject,
        !          1348:                         deviceObject->CurrentIrp,
        !          1349:                         (PVOID)ParCompleteWrite
        !          1350:                         );
        !          1351: 
        !          1352:                 }
        !          1353: 
        !          1354:                 return TRUE;
        !          1355: 
        !          1356:             } else if ((PAR_OK(deviceStatus)) && (saveTimer != -1) &&
        !          1357:                        (extension->CountBuffer == 0)) {
        !          1358: 
        !          1359:                 //
        !          1360:                 // The odd case of the device going off line just after
        !          1361:                 // we give the hardware the very last byte.
        !          1362:                 //
        !          1363: 
        !          1364:                 ParDump(
        !          1365:                     PARISR,
        !          1366:                     ("PARALLEL - ISR Inited - good io all done:\n")
        !          1367:                     );
        !          1368:                 IoRequestDpc(
        !          1369:                     deviceObject,
        !          1370:                     deviceObject->CurrentIrp,
        !          1371:                     (PVOID)ParCompleteWrite
        !          1372:                     );
        !          1373: 
        !          1374:                 return TRUE;
        !          1375: 
        !          1376:             } else {
        !          1377: 
        !          1378:                 if ((saveTimer != -1) &&
        !          1379:                     (PAR_PAPER_EMPTY(deviceStatus) ||
        !          1380:                      PAR_OFF_LINE(deviceStatus))) {
        !          1381: 
        !          1382:                     //
        !          1383:                     // Paper empty or device off line should let
        !          1384:                     // the normal time out code handle the problem
        !          1385:                     //
        !          1386: 
        !          1387:                     ParDump(
        !          1388:                         PARISRACTION,
        !          1389:                         ("PARALLEL: Isr found device to be off line or empty\n")
        !          1390:                         );
        !          1391:                     extension->TimerCount = saveTimer;
        !          1392:                     return TRUE;
        !          1393: 
        !          1394:                 } else if (PAR_POWERED_OFF(deviceStatus) ||
        !          1395:                            PAR_NOT_CONNECTED(deviceStatus) ||
        !          1396:                            PAR_NO_CABLE(deviceStatus)) {
        !          1397: 
        !          1398:                     extension->Initialized = FALSE;
        !          1399: 
        !          1400:                     if (saveTimer != -1) {
        !          1401: 
        !          1402:                         if (PAR_POWERED_OFF(deviceStatus)) {
        !          1403: 
        !          1404:                             //
        !          1405:                             // For the real powered off case make sure we aren't
        !          1406:                             // getting an interrupt storm from turning an HPxp
        !          1407:                             // off on an MIO-X00 adapter.
        !          1408:                             //
        !          1409:                             // If it is just an simple turning off then bumping
        !          1410:                             // the unexpected count up won't hurt.
        !          1411:                             //
        !          1412: 
        !          1413:                             extension->UnexpectedCount++;
        !          1414:                             action = ParPoweredOff;
        !          1415:                             ParCheckTheWeather(extension);
        !          1416: 
        !          1417:                         } else if (PAR_NO_CABLE(deviceStatus)) {
        !          1418: 
        !          1419:                             action = ParPoweredOff;
        !          1420: 
        !          1421:                         }
        !          1422: 
        !          1423:                         if (PAR_NOT_CONNECTED(deviceStatus)) {
        !          1424: 
        !          1425:                             action = ParNotConnected;
        !          1426: 
        !          1427:                         }
        !          1428: 
        !          1429:                         ParDump(
        !          1430:                             PARISR,
        !          1431:                             ("PARALLEL - ISR Inited off/connected complete "
        !          1432:                              "irp - action %d\n",action)
        !          1433:                             );
        !          1434:                         IoRequestDpc(
        !          1435:                             deviceObject,
        !          1436:                             deviceObject->CurrentIrp,
        !          1437:                             (PVOID)action
        !          1438:                             );
        !          1439: 
        !          1440:                         return TRUE;
        !          1441: 
        !          1442:                     } else {
        !          1443: 
        !          1444:                         //
        !          1445:                         // Well we weren't doing an operation, but
        !          1446:                         // the device has changed state since we
        !          1447:                         // last looked.  So this interrupt might
        !          1448:                         // as well have been for us.
        !          1449:                         //
        !          1450: 
        !          1451:                         return TRUE;
        !          1452: 
        !          1453:                     }
        !          1454: 
        !          1455:                 } else if ((PAR_BUSY(deviceStatus)) &&
        !          1456:                            (saveTimer != -1)) {
        !          1457: 
        !          1458:                     ParDump(
        !          1459:                         PARISR | PARBUSYPATH,
        !          1460:                         ("PARALLEL - ISR inited - busy interrupt?\n")
        !          1461:                         );
        !          1462: 
        !          1463:                     //
        !          1464:                     // Well we think that we have work to do, but for
        !          1465:                     // some reason we got an interrupt, yet the device
        !          1466:                     // thinks it's busy.
        !          1467:                     //
        !          1468:                     // Three things could have happened.
        !          1469:                     //
        !          1470:                     // 1) We are running this device off a timer
        !          1471:                     //    (NO interrupts are ever being used).
        !          1472:                     //    The driver is just calling the ISR to
        !          1473:                     //    force the work to be done.
        !          1474:                     //
        !          1475:                     // 2) We are on some kind of Jazz machine.  We
        !          1476:                     //    *THINK* that the part on the machine is
        !          1477:                     //    signaling an interrupt on just the device
        !          1478:                     //    going BUSY, which is bizarre.
        !          1479:                     //
        !          1480:                     // 3) Some printers (whose name shall go unmentioned
        !          1481:                     //    except that their initials are HP),
        !          1482:                     //    seem to give an interrupt to acknowledge
        !          1483:                     //    the character, *THEN* decide that they want
        !          1484:                     //    to go busy (I think this is bizarre too).
        !          1485:                     //
        !          1486:                     //
        !          1487:                     // For 1 we could just return, since the run off
        !          1488:                     // the timer code will calm down and try to run later
        !          1489:                     // if it gets too many "busys".
        !          1490:                     //
        !          1491:                     // For 2 we could also just return, because we
        !          1492:                     // get another acknowledge interrupt later.
        !          1493:                     //
        !          1494:                     // 3 is quite painful because WE ARE NOT GOING
        !          1495:                     // TO GET ANOTHER INTERRUPT FROM THE DEVICE.
        !          1496:                     //
        !          1497:                     // What we do to solve 3 is to queue off a dpc
        !          1498:                     // that will start a timer that when the timer
        !          1499:                     // fires will cause a dpc to synchrnoize with the
        !          1500:                     // isr and then call this isr.  If the busy bit
        !          1501:                     // has gone away then we will just act as if we
        !          1502:                     // got interrupted.  If the busy bit hasn't gone
        !          1503:                     // away, we just start off the dpc again.
        !          1504:                     //
        !          1505: 
        !          1506:                     extension->TimerCount = saveTimer;
        !          1507: 
        !          1508:                     //
        !          1509:                     // If this driver is using a timer to drive the
        !          1510:                     // writes then we should return that we haven't
        !          1511:                     // done anything yet with the io.
        !          1512:                     //
        !          1513: 
        !          1514:                     if (extension->UsingATimer) {
        !          1515: 
        !          1516:                         return FALSE;
        !          1517: 
        !          1518:                     } else {
        !          1519: 
        !          1520:                         if (!extension->BusyPath) {
        !          1521: 
        !          1522:                             extension->BusyPath = TRUE;
        !          1523: 
        !          1524:                             ParDump(
        !          1525:                                 PARBUSYPATH,
        !          1526:                                 ("Parallel: About to queue the start busy"
        !          1527:                                  "timer\n")
        !          1528:                                 );
        !          1529:                             KeInsertQueueDpc(
        !          1530:                                 &extension->StartBusyTimerDpc,
        !          1531:                                 NULL,
        !          1532:                                 NULL
        !          1533:                                 );
        !          1534: 
        !          1535:                         }
        !          1536: 
        !          1537:                     }
        !          1538: 
        !          1539:                 }
        !          1540: 
        !          1541:             }
        !          1542: 
        !          1543:             extension->TimerCount = saveTimer;
        !          1544:             return TRUE;
        !          1545: 
        !          1546:         } else {
        !          1547: 
        !          1548:             // not initialized
        !          1549: 
        !          1550:             if (PAR_POWERED_ON(deviceStatus)) {
        !          1551: 
        !          1552:                 ParDump(
        !          1553:                     PARISR | PARBUSYPATH,
        !          1554:                     ("PARALLEL: ISR - not initialized / not on\n")
        !          1555:                     );
        !          1556:                 extension->AutoFeed = FALSE;
        !          1557:                 ParInitializeDevice(extension);
        !          1558:                 return TRUE;
        !          1559: 
        !          1560:             }
        !          1561: 
        !          1562:         }
        !          1563: 
        !          1564:     }
        !          1565: 
        !          1566:     //
        !          1567:     // Well we couldn't find anything to do.  Restore the
        !          1568:     // timer value and return FALSE.
        !          1569:     //
        !          1570: 
        !          1571:     ParDump(
        !          1572:         PARISR,
        !          1573:         ("PARALLEL: ISR returning FALSE with a timer count of %d\n",
        !          1574:          extension->TimerCount)
        !          1575:         );
        !          1576:     extension->TimerCount = saveTimer;
        !          1577:     extension->UnexpectedCount++;
        !          1578: 
        !          1579:     ParCheckTheWeather(extension);
        !          1580:     return FALSE;
        !          1581: 
        !          1582: }
        !          1583: 
        !          1584: BOOLEAN
        !          1585: ParSynchCount(
        !          1586:     IN PVOID Context
        !          1587:     )
        !          1588: 
        !          1589: /*++
        !          1590: 
        !          1591: Routine Description:
        !          1592: 
        !          1593:     This routine is synchronized to work at device level (e.g. the
        !          1594:     ISR can't be running).  It is used to clear the count buffer.
        !          1595:     We do this so that when we completing a request prematurely, we
        !          1596:     don't have to refer to a variable that the ISR used to determine
        !          1597:     if it is doing work.  We clear that variable here.
        !          1598: 
        !          1599: Arguments:
        !          1600: 
        !          1601:     Context - Pointer to a struct that contains the extension and.
        !          1602:               a ulong to hold the old count.
        !          1603: 
        !          1604: Return Value:
        !          1605: 
        !          1606:     Always False.
        !          1607: 
        !          1608: --*/
        !          1609: 
        !          1610: {
        !          1611: 
        !          1612:     PPAR_SYNCH_COUNT synchCount = Context;
        !          1613: 
        !          1614:     synchCount->OldCount = synchCount->Extension->CountBuffer;
        !          1615:     synchCount->Extension->CountBuffer = 0;
        !          1616: 
        !          1617:     return FALSE;
        !          1618: 
        !          1619: }
        !          1620: 
        !          1621: VOID
        !          1622: ParDpcRoutine(
        !          1623:     IN PKDPC Dpc,
        !          1624:     IN PDEVICE_OBJECT DeviceObject,
        !          1625:     IN PIRP Irp,
        !          1626:     IN PVOID DeferredContext
        !          1627:     )
        !          1628: 
        !          1629: /*++
        !          1630: 
        !          1631: Routine Description:
        !          1632: 
        !          1633:     This is the DPC routine that complete driver's write operation.
        !          1634: 
        !          1635: Arguments:
        !          1636: 
        !          1637:     DeviceObject - Pointer to the device object
        !          1638: 
        !          1639:     Irp - Pointer to the current Irp
        !          1640: 
        !          1641:     DeferredContext - Type of action
        !          1642: 
        !          1643: Return Value:
        !          1644: 
        !          1645:     None.
        !          1646: 
        !          1647: --*/
        !          1648: 
        !          1649: {
        !          1650: 
        !          1651:     UNREFERENCED_PARAMETER(Dpc);
        !          1652: 
        !          1653:     ParDump(
        !          1654:         PARDPC,
        !          1655:         ("PARALLEL: In ParDpcRoutine - current irp is: %x\n",
        !          1656:           Irp)
        !          1657:         );
        !          1658: 
        !          1659:     if (Irp) {
        !          1660: 
        !          1661:         PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
        !          1662:         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
        !          1663:         PAR_DPC_ACTION action = (PAR_DPC_ACTION)DeferredContext;
        !          1664:         PAR_SYNCH_COUNT synchCount;
        !          1665:         KIRQL cancelIrql;
        !          1666: 
        !          1667: 
        !          1668:         //
        !          1669:         // No matter what, this irp is being completed.
        !          1670:         // Kill the cancel routine.
        !          1671:         //
        !          1672: 
        !          1673:         IoAcquireCancelSpinLock(&cancelIrql);
        !          1674:         Irp->CancelRoutine = NULL;
        !          1675:         IoReleaseCancelSpinLock(cancelIrql);
        !          1676: 
        !          1677:         synchCount.Extension = extension;
        !          1678:         synchCount.OldCount = 0;
        !          1679:         ParSynchronizeExecution(
        !          1680:             extension,
        !          1681:             ParSynchCount,
        !          1682:             &synchCount
        !          1683:             );
        !          1684: 
        !          1685:         switch (action) {
        !          1686: 
        !          1687:             case ParCompleteWrite :
        !          1688: 
        !          1689:                 Irp->IoStatus.Status = STATUS_SUCCESS;
        !          1690:                 Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
        !          1691:                                             synchCount.OldCount;
        !          1692:                 ParDump(
        !          1693:                     PARDPC,
        !          1694:                     ("PARALLEL: DPC - Complete Write\n"
        !          1695:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1696:                      Irp->IoStatus.Status,
        !          1697:                      Irp->IoStatus.Information)
        !          1698:                     );
        !          1699:                 break;
        !          1700: 
        !          1701:             case ParCompleteSetIoctl :
        !          1702: 
        !          1703:                 Irp->IoStatus.Status = STATUS_SUCCESS;
        !          1704:                 ParDump(
        !          1705:                     PARDPC,
        !          1706:                     ("PARALLEL: DPC - Complete Set Ioctl\n"
        !          1707:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1708:                      Irp->IoStatus.Status,
        !          1709:                      Irp->IoStatus.Information)
        !          1710:                     );
        !          1711:                 break;
        !          1712: 
        !          1713:             case ParPoweredOff :
        !          1714: 
        !          1715:                 Irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
        !          1716:                 ParDump(
        !          1717:                     PARDPC,
        !          1718:                     ("PARALLEL: DPC - powered off\n"
        !          1719:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1720:                      Irp->IoStatus.Status,
        !          1721:                      Irp->IoStatus.Information)
        !          1722:                     );
        !          1723:                 break;
        !          1724: 
        !          1725:             case ParNotConnected :
        !          1726: 
        !          1727:                 Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
        !          1728:                 ParDump(
        !          1729:                     PARDPC,
        !          1730:                     ("PARALLEL: DPC - not connected\n"
        !          1731:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1732:                      Irp->IoStatus.Status,
        !          1733:                      Irp->IoStatus.Information)
        !          1734:                     );
        !          1735:                 break;
        !          1736: 
        !          1737:             case ParOffline :
        !          1738: 
        !          1739:                 Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
        !          1740:                 Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
        !          1741:                                             synchCount.OldCount;
        !          1742:                 ParDump(
        !          1743:                     PARDPC,
        !          1744:                     ("PARALLEL: DPC - off line\n"
        !          1745:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1746:                      Irp->IoStatus.Status,
        !          1747:                      Irp->IoStatus.Information)
        !          1748:                     );
        !          1749:                 break;
        !          1750: 
        !          1751:             case ParPaperEmpty :
        !          1752: 
        !          1753:                 Irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
        !          1754:                 Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
        !          1755:                                             synchCount.OldCount;
        !          1756:                 ParDump(
        !          1757:                     PARDPC,
        !          1758:                     ("PARALLEL: DPC - paper empty\n"
        !          1759:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1760:                      Irp->IoStatus.Status,
        !          1761:                      Irp->IoStatus.Information)
        !          1762:                     );
        !          1763:                 break;
        !          1764: 
        !          1765:             case ParUnknownError :
        !          1766: 
        !          1767:                 Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
        !          1768:                 ParDump(
        !          1769:                     PARDPC,
        !          1770:                     ("PARALLEL: DPC - unknown error\n"
        !          1771:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1772:                      Irp->IoStatus.Status,
        !          1773:                      Irp->IoStatus.Information)
        !          1774:                     );
        !          1775:                 ParLogError(
        !          1776:                     DeviceObject->DriverObject,
        !          1777:                     DeviceObject,
        !          1778:                     extension->OriginalController,
        !          1779:                     ParPhysicalZero,
        !          1780:                     extension->IrpSequence,
        !          1781:                     irpSp->MajorFunction,
        !          1782:                     0,
        !          1783:                     38,
        !          1784:                     Irp->IoStatus.Status,
        !          1785:                     IO_ERR_NOT_READY
        !          1786:                     );
        !          1787:                 break;
        !          1788: 
        !          1789:             case ParBusy :
        !          1790: 
        !          1791:                 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
        !          1792:                 Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
        !          1793:                                             synchCount.OldCount;
        !          1794:                 ParDump(
        !          1795:                     PARDPC,
        !          1796:                     ("PARALLEL: DPC - device busy\n"
        !          1797:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1798:                      Irp->IoStatus.Status,
        !          1799:                      Irp->IoStatus.Information)
        !          1800:                     );
        !          1801:                 break;
        !          1802: 
        !          1803:             case ParCancel:
        !          1804: 
        !          1805:                 Irp->IoStatus.Status = STATUS_CANCELLED;
        !          1806:                 Irp->IoStatus.Information = 0;
        !          1807:                 ParDump(
        !          1808:                     PARDPC,
        !          1809:                     ("PARALLEL: DPC - cancel part of the case\n"
        !          1810:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1811:                      Irp->IoStatus.Status,
        !          1812:                      Irp->IoStatus.Information)
        !          1813:                     );
        !          1814:                 break;
        !          1815: 
        !          1816: 
        !          1817:             default :
        !          1818: 
        !          1819:                 Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
        !          1820:                 ParDump(
        !          1821:                     PARDPC,
        !          1822:                     ("PARALLEL: DPC - default part of the case\n"
        !          1823:                      "--------  STATUS/INFORMATON: %x/%x\n",
        !          1824:                      Irp->IoStatus.Status,
        !          1825:                      Irp->IoStatus.Information)
        !          1826:                     );
        !          1827:                 ParLogError(
        !          1828:                     DeviceObject->DriverObject,
        !          1829:                     DeviceObject,
        !          1830:                     extension->OriginalController,
        !          1831:                     ParPhysicalZero,
        !          1832:                     extension->IrpSequence,
        !          1833:                     irpSp->MajorFunction,
        !          1834:                     0,
        !          1835:                     39,
        !          1836:                     Irp->IoStatus.Status,
        !          1837:                     IO_ERR_NOT_READY
        !          1838:                     );
        !          1839:                 break;
        !          1840:         }
        !          1841: 
        !          1842:         IoStartNextPacket(
        !          1843:             DeviceObject,
        !          1844:             TRUE
        !          1845:             );
        !          1846:         ParDump(
        !          1847:             PARIRPCOMPLETE,
        !          1848:             ("PARALLEL: About to complete IRP: %x\n",Irp)
        !          1849:             );
        !          1850:         IoCompleteRequest(
        !          1851:             Irp,
        !          1852:             IO_PARALLEL_INCREMENT
        !          1853:             );
        !          1854: 
        !          1855:     }
        !          1856: 
        !          1857: }
        !          1858: 
        !          1859: BOOLEAN
        !          1860: ParStartCriticalFunctions(
        !          1861:     IN PVOID Context
        !          1862:     )
        !          1863: 
        !          1864: /*++
        !          1865: 
        !          1866: Routine Description :
        !          1867: 
        !          1868:     This routine starts the writing operations on the device.
        !          1869: 
        !          1870: Arguments :
        !          1871: 
        !          1872:     Context - Really a pointer to the device object for the parallel port
        !          1873:                     device
        !          1874: 
        !          1875: Return value :
        !          1876: 
        !          1877:     Always FALSE;
        !          1878: 
        !          1879: --*/
        !          1880: 
        !          1881: {
        !          1882:     PDEVICE_OBJECT deviceObject = Context;
        !          1883:     PIO_STACK_LOCATION irpSp =
        !          1884:         IoGetCurrentIrpStackLocation(deviceObject->CurrentIrp);
        !          1885:     PPAR_DEVICE_EXTENSION extension = deviceObject->DeviceExtension;
        !          1886: 
        !          1887:     extension->Command = ParWrite;
        !          1888: 
        !          1889:     //
        !          1890:     // Initialize the state machine for this packet so the remainder of the
        !          1891:     // driver can determine the number of characters that are to be written
        !          1892:     // to the device.
        !          1893:     //
        !          1894: 
        !          1895:     extension->CompletingIoControl = FALSE;
        !          1896:     extension->CountBuffer = irpSp->Parameters.Write.Length;
        !          1897: 
        !          1898:     //
        !          1899:     // patch for HP laserjet that hasn't INIT pin
        !          1900:     //
        !          1901: 
        !          1902:     if (!extension->Initialized) {     //begin HP patch
        !          1903: 
        !          1904:         UCHAR deviceStatus = GetStatus(extension->Controller);
        !          1905: 
        !          1906:         ParDump(
        !          1907:             PARCRIT,
        !          1908:             ("PARALLEL: Critical - In HP patch\n")
        !          1909:             );
        !          1910:         if (PAR_OK(deviceStatus)) {
        !          1911: 
        !          1912:             ParDump(
        !          1913:                 PARCRIT,
        !          1914:                 ("PARALLEL: Critical - It was initialized\n")
        !          1915:                 );
        !          1916:             extension->Initialized = TRUE;
        !          1917: 
        !          1918:         }
        !          1919: 
        !          1920:     }                                          //end HP patch
        !          1921: 
        !          1922: 
        !          1923:     if (extension->Initialized) {
        !          1924: 
        !          1925:         ParDump(
        !          1926:             PARCRIT,
        !          1927:             ("PARALLEL: Critical - Sending a byte\n")
        !          1928:             );
        !          1929:         ParInitiateIo(deviceObject);
        !          1930: 
        !          1931:     } else {
        !          1932: 
        !          1933:         ParDump(
        !          1934:             PARCRIT,
        !          1935:             ("PARALLEL: Critical - reinitializing the device\n")
        !          1936:             );
        !          1937:        extension->AutoFeed = FALSE;
        !          1938:        ParInitializeDevice(extension);
        !          1939: 
        !          1940:     }
        !          1941: 
        !          1942:     //
        !          1943:     // If we are running off the timer then just
        !          1944:     // queue off the "polling" code.
        !          1945:     //
        !          1946: 
        !          1947:     if (extension->UsingATimer) {
        !          1948: 
        !          1949:         ParDump(
        !          1950:             PARCRIT,
        !          1951:             ("PARALLEL: Critical - queueing off the polling DPC\n")
        !          1952:             );
        !          1953:         KeInsertQueueDpc(
        !          1954:             &extension->PollingDpc,
        !          1955:             NULL,
        !          1956:             NULL
        !          1957:             );
        !          1958: 
        !          1959:     }
        !          1960: 
        !          1961:     return FALSE;
        !          1962: 
        !          1963: }
        !          1964: 
        !          1965: BOOLEAN
        !          1966: ParManageIoDevice(
        !          1967:      IN PVOID Context
        !          1968:      )
        !          1969: 
        !          1970: /*++
        !          1971: 
        !          1972: Routine Description :
        !          1973: 
        !          1974:     This routine starts the IoControl commands.
        !          1975: 
        !          1976: Arguments :
        !          1977: 
        !          1978:     Context - Really a pointer to a communication area between StartIo
        !          1979:               and ManageIoDevice
        !          1980: 
        !          1981: Return Value :
        !          1982: 
        !          1983:     Always FALSE
        !          1984: 
        !          1985: --*/
        !          1986: {
        !          1987:     PCONTROL_AREA ioControlArea = Context;
        !          1988:     PPAR_DEVICE_EXTENSION extension = ioControlArea->Extension;
        !          1989:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(ioControlArea->Irp);
        !          1990: 
        !          1991:     extension->CompletingIoControl = FALSE;
        !          1992: 
        !          1993:     if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
        !          1994:         IOCTL_PAR_SET_INFORMATION) {
        !          1995: 
        !          1996:         PPAR_SET_INFORMATION irpBuffer =
        !          1997:             ioControlArea->Irp->AssociatedIrp.SystemBuffer;
        !          1998: 
        !          1999:         extension->Command = ParSetInformation;
        !          2000: 
        !          2001:         extension->AutoFeed = (BOOLEAN)
        !          2002:                              ((irpBuffer->Init & PARALLEL_AUTOFEED) != 0);
        !          2003: 
        !          2004:         ParInitializeDevice(extension);
        !          2005: 
        !          2006:     } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
        !          2007:                IOCTL_PAR_QUERY_INFORMATION) {
        !          2008: 
        !          2009:         ioControlArea->Status = GetStatus(extension->Controller);
        !          2010:         ioControlArea->Control = GetControl(extension->Controller);
        !          2011:         extension->Command = ParQueryInformation;
        !          2012:         extension->CompletingIoControl = TRUE;
        !          2013: 
        !          2014:     }
        !          2015: 
        !          2016:     return FALSE;
        !          2017: }
        !          2018: 
        !          2019: VOID
        !          2020: ParStartIo(
        !          2021:     IN PDEVICE_OBJECT DeviceObject,
        !          2022:     IN PIRP Irp
        !          2023:     )
        !          2024: 
        !          2025: /*++
        !          2026: 
        !          2027: Routine Description:
        !          2028: 
        !          2029:     This routine starts an I/O operation for the driver and
        !          2030:     then returns
        !          2031: 
        !          2032: Arguments:
        !          2033: 
        !          2034:     DeviceObject - Pointer to the device object of this device
        !          2035: 
        !          2036:     Irp - Pointer to the current IRP
        !          2037: 
        !          2038: Return Value:
        !          2039: 
        !          2040:     None
        !          2041: 
        !          2042: --*/
        !          2043: 
        !          2044: {
        !          2045:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
        !          2046:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
        !          2047: 
        !          2048:     //
        !          2049:     // Increment the following value so that we can have a "unique"
        !          2050:     // value to give to the error log routine.
        !          2051:     //
        !          2052: 
        !          2053:     extension->IrpSequence++;
        !          2054: 
        !          2055:     ParDump(
        !          2056:         PARDISPATCH,
        !          2057:         ("PARALLEL: In startio with IRP: %x\n",
        !          2058:          Irp)
        !          2059:         );
        !          2060:     if (irpSp->MajorFunction == IRP_MJ_WRITE) {
        !          2061: 
        !          2062:         ParDump(
        !          2063:             PARSTART,
        !          2064:             ("PARALLEL - startio - Starting off a write\n")
        !          2065:             );
        !          2066:         ParSynchronizeExecution(
        !          2067:             extension,
        !          2068:             ParStartCriticalFunctions,
        !          2069:             DeviceObject
        !          2070:             );
        !          2071: 
        !          2072:     } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
        !          2073: 
        !          2074:         CONTROL_AREA ioControlArea;
        !          2075: 
        !          2076:         ioControlArea.Extension = extension;
        !          2077:         ioControlArea.Irp = Irp;
        !          2078: 
        !          2079:         ParDump(
        !          2080:             PARSTART,
        !          2081:             ("PARALLEL - startio - Starting off a device io control\n")
        !          2082:             );
        !          2083:         ParSynchronizeExecution(
        !          2084:             extension,
        !          2085:             ParManageIoDevice,
        !          2086:             &ioControlArea
        !          2087:             );
        !          2088: 
        !          2089:         if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
        !          2090:             IOCTL_PAR_QUERY_INFORMATION) {
        !          2091: 
        !          2092:             PPAR_QUERY_INFORMATION irpBuffer = Irp->AssociatedIrp.SystemBuffer;
        !          2093: 
        !          2094:             ParDump(
        !          2095:                 PARSTART,
        !          2096:                 ("PARALLEL - startio - Starting off a query\n")
        !          2097:                 );
        !          2098:             Irp->IoStatus.Status = STATUS_SUCCESS;
        !          2099: 
        !          2100:             //
        !          2101:             // Interpretating Status & Control
        !          2102:             //
        !          2103: 
        !          2104:             irpBuffer->Status = 0x0;
        !          2105: 
        !          2106:             if (PAR_POWERED_OFF(ioControlArea.Status) ||
        !          2107:                 PAR_NO_CABLE(ioControlArea.Status)) {
        !          2108: 
        !          2109:                 irpBuffer->Status =
        !          2110:                     (UCHAR)(irpBuffer->Status | PARALLEL_POWER_OFF);
        !          2111: 
        !          2112:             } else if (PAR_PAPER_EMPTY(ioControlArea.Status)) {
        !          2113: 
        !          2114:                 irpBuffer->Status =
        !          2115:                     (UCHAR)(irpBuffer->Status | PARALLEL_PAPER_EMPTY);
        !          2116: 
        !          2117:             } else if (PAR_OFF_LINE(ioControlArea.Status)) {
        !          2118: 
        !          2119:                 irpBuffer->Status =
        !          2120:                     (UCHAR)(irpBuffer->Status | PARALLEL_OFF_LINE);
        !          2121: 
        !          2122:             } else if (PAR_NOT_CONNECTED(ioControlArea.Status)) {
        !          2123: 
        !          2124:                 irpBuffer->Status =
        !          2125:                     (UCHAR)(irpBuffer->Status | PARALLEL_NOT_CONNECTED);
        !          2126: 
        !          2127:             }
        !          2128: 
        !          2129:             if ( PAR_BUSY( ioControlArea.Status ) ) {
        !          2130: 
        !          2131:                 irpBuffer->Status =
        !          2132:                     (UCHAR)(irpBuffer->Status | PARALLEL_BUSY);
        !          2133: 
        !          2134:             }
        !          2135: 
        !          2136:             if (PAR_SELECTED(ioControlArea.Status)) {
        !          2137: 
        !          2138:                 irpBuffer->Status =
        !          2139:                     (UCHAR)(irpBuffer->Status | PARALLEL_SELECTED);
        !          2140: 
        !          2141:             }
        !          2142: 
        !          2143:             if (PAR_AUTOFEED(ioControlArea.Control)) {
        !          2144: 
        !          2145:                 irpBuffer->Status =
        !          2146:                     (UCHAR)(irpBuffer->Status | PARALLEL_AUTOFEED);
        !          2147: 
        !          2148:             }
        !          2149: 
        !          2150:             Irp->IoStatus.Information = sizeof( PAR_QUERY_INFORMATION );
        !          2151:             IoStartNextPacket(
        !          2152:                 DeviceObject,
        !          2153:                 TRUE
        !          2154:                 );
        !          2155:             ParDump(
        !          2156:                 PARIRPCOMPLETE,
        !          2157:                 ("PARALLEL: About to complete IRP: %x\n",Irp)
        !          2158:                 );
        !          2159:             IoCompleteRequest(
        !          2160:                 Irp,
        !          2161:                 IO_NO_INCREMENT
        !          2162:                 );
        !          2163: 
        !          2164:         }
        !          2165: 
        !          2166:     }
        !          2167: 
        !          2168: }
        !          2169: 
        !          2170: BOOLEAN
        !          2171: ParInitiateIo(
        !          2172:     IN PDEVICE_OBJECT DeviceObject
        !          2173:     )
        !          2174: 
        !          2175: /*++
        !          2176: 
        !          2177: Routine Description:
        !          2178: 
        !          2179:     This routine writes UCHARs to the parallel port device.
        !          2180:     It is called from StartCriticalFunctions and ISR.  In other
        !          2181:     words, it fully expects to be synchronized with the isr.
        !          2182: 
        !          2183: Arguments:
        !          2184: 
        !          2185:     DeviceObject - Pointer to the device object of the device
        !          2186: 
        !          2187: Return Value:
        !          2188: 
        !          2189:     Always FALSE.
        !          2190: 
        !          2191: --*/
        !          2192: 
        !          2193: {
        !          2194:     PPAR_DEVICE_EXTENSION extension;
        !          2195:     PIRP irp;
        !          2196:     PIO_STACK_LOCATION irpSp;
        !          2197:     PUCHAR irpBuffer;
        !          2198: 
        !          2199:     extension = DeviceObject->DeviceExtension;
        !          2200: 
        !          2201:     if (extension->Initialized) {
        !          2202: 
        !          2203:         //
        !          2204:         // We only want to write to the port when the device is online.
        !          2205:         //
        !          2206: 
        !          2207:         UCHAR deviceStatus;
        !          2208:         ULONG numberWritten = 0;
        !          2209:         ULONG maxNumberToWrite;
        !          2210: 
        !          2211:         if (extension->InterruptMode = Latched) {
        !          2212: 
        !          2213:             maxNumberToWrite = 256;
        !          2214: 
        !          2215:         } else {
        !          2216: 
        !          2217:             maxNumberToWrite = 32;
        !          2218: 
        !          2219:         }
        !          2220:         irp = DeviceObject->CurrentIrp;
        !          2221:         irpSp = IoGetCurrentIrpStackLocation(irp);
        !          2222:         irpBuffer = (PUCHAR)(irp->AssociatedIrp.SystemBuffer);
        !          2223:         irpBuffer = &irpBuffer[irpSp->Parameters.Write.Length -
        !          2224:                                extension->CountBuffer];
        !          2225:         do {
        !          2226: 
        !          2227:             deviceStatus = GetStatus(extension->Controller);
        !          2228: 
        !          2229:             if (PAR_ONLINE(deviceStatus)) {
        !          2230: 
        !          2231:                 StoreData(
        !          2232:                     extension->Controller,
        !          2233:                     *irpBuffer
        !          2234:                     );
        !          2235: 
        !          2236:                 irpBuffer++;
        !          2237:                 extension->CountBuffer--;
        !          2238:                 numberWritten++;
        !          2239: 
        !          2240:             } else {
        !          2241: 
        !          2242:                 ParDump(
        !          2243:                     PARCRIT,
        !          2244:                     ("PARALLEL: Initiate IO - device is not on line, status: %x\n",
        !          2245:                      deviceStatus)
        !          2246:                     );
        !          2247: 
        !          2248:                 break;
        !          2249: 
        !          2250:             }
        !          2251: 
        !          2252:         } while (extension->CountBuffer && (numberWritten < maxNumberToWrite));
        !          2253: 
        !          2254:     }
        !          2255:     extension->TimerCount = extension->TimerStart;
        !          2256:     return FALSE;
        !          2257: }
        !          2258: 
        !          2259: VOID
        !          2260: ParCancelRequest(
        !          2261:     PDEVICE_OBJECT DeviceObject,
        !          2262:     PIRP Irp
        !          2263:     )
        !          2264: 
        !          2265: /*++
        !          2266: 
        !          2267: Routine Description:
        !          2268: 
        !          2269:     This routine is used to cancel any request in the parallel driver.
        !          2270: 
        !          2271: Arguments:
        !          2272: 
        !          2273:     DeviceObject - Pointer to the device object for this device
        !          2274: 
        !          2275:     Irp - Pointer to the IRP to be canceled.
        !          2276: 
        !          2277: Return Value:
        !          2278: 
        !          2279:     None.
        !          2280: 
        !          2281: --*/
        !          2282: 
        !          2283: {
        !          2284: 
        !          2285:     //
        !          2286:     // If this is the current request then just let normal
        !          2287:     // code detect that the current is cancelled.
        !          2288:     //
        !          2289:     // If this isn't the current request then remove the request
        !          2290:     // from the device queue and complete it.
        !          2291:     //
        !          2292: 
        !          2293:     if (Irp != DeviceObject->CurrentIrp) {
        !          2294: 
        !          2295:         KeRemoveEntryDeviceQueue(
        !          2296:             &DeviceObject->DeviceQueue,
        !          2297:             &Irp->Tail.Overlay.DeviceQueueEntry
        !          2298:             );
        !          2299: 
        !          2300:         Irp->IoStatus.Status = STATUS_CANCELLED;
        !          2301:         Irp->IoStatus.Information = 0;
        !          2302: 
        !          2303:         IoReleaseCancelSpinLock(Irp->CancelIrql);
        !          2304: 
        !          2305:         ParDump(
        !          2306:             PARIRPCOMPLETE,
        !          2307:             ("PARALLEL: About to complete IRP: %x\n",Irp)
        !          2308:             );
        !          2309:         IoCompleteRequest(
        !          2310:             Irp,
        !          2311:             IO_NO_INCREMENT
        !          2312:             );
        !          2313: 
        !          2314:     } else {
        !          2315: 
        !          2316:         ParDump(
        !          2317:             PARIRPCOMPLETE,
        !          2318:             ("PARALLEL: Can't complete (CANCEL) IRP: %x because it's current\n",
        !          2319:              Irp)
        !          2320:             );
        !          2321:         IoReleaseCancelSpinLock(Irp->CancelIrql);
        !          2322: 
        !          2323:     }
        !          2324: 
        !          2325: }
        !          2326: 
        !          2327: BOOLEAN
        !          2328: ParSynchronizeExecution(
        !          2329:     IN PPAR_DEVICE_EXTENSION Extension,
        !          2330:     IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
        !          2331:     IN PVOID SynchronizeContext
        !          2332:     )
        !          2333: 
        !          2334: /*++
        !          2335: 
        !          2336: Routine Description:
        !          2337: 
        !          2338:     This routine is used to abstract whether we are using
        !          2339:     an interrupt object or a simple spin lock.
        !          2340: 
        !          2341: Arguments:
        !          2342: 
        !          2343:     Extension - The device extension for the port.
        !          2344: 
        !          2345:     SynchronizeRoutine - A routine to call when the lock
        !          2346:                          is aquired.
        !          2347: 
        !          2348:     SynchronizeContext - What to pass to the synchronization
        !          2349:                          routine.
        !          2350: 
        !          2351: Return Value:
        !          2352: 
        !          2353:     Whatever the synchronization routine returns.
        !          2354: 
        !          2355: --*/
        !          2356: 
        !          2357: {
        !          2358: 
        !          2359:     KIRQL oldIrql;
        !          2360:     BOOLEAN returnValue;
        !          2361: 
        !          2362:     KeAcquireSpinLock(
        !          2363:         &Extension->PollingLock,
        !          2364:         &oldIrql
        !          2365:         );
        !          2366: 
        !          2367:     if (Extension->Interrupt) {
        !          2368: 
        !          2369:         //
        !          2370:         // If we've haven't dropped down to using a timer
        !          2371:         // then the acquiring the polling lock is a bit
        !          2372:         // of extra overhead, but hopefully not too harmful.
        !          2373:         // We did have to pass through this irql anyway.
        !          2374:         //
        !          2375: 
        !          2376:         if (!Extension->UsingATimer) {
        !          2377: 
        !          2378:             //
        !          2379:             // We have a small race where the isr is just about
        !          2380:             // to set this to true.  This is not really a big deal.
        !          2381:             // We will simply synchronize once using the interrupt
        !          2382:             // object and thereafter use the PollingLock.  Overall
        !          2383:             // we are always protected by the polling lock.
        !          2384:             //
        !          2385: 
        !          2386:             returnValue = KeSynchronizeExecution(
        !          2387:                               Extension->Interrupt,
        !          2388:                               SynchronizeRoutine,
        !          2389:                               SynchronizeContext
        !          2390:                               );
        !          2391: 
        !          2392:         } else {
        !          2393: 
        !          2394:             returnValue = SynchronizeRoutine(
        !          2395:                               SynchronizeContext
        !          2396:                               );
        !          2397: 
        !          2398:         }
        !          2399: 
        !          2400:     } else {
        !          2401: 
        !          2402:         returnValue = SynchronizeRoutine(
        !          2403:                           SynchronizeContext
        !          2404:                           );
        !          2405: 
        !          2406:     }
        !          2407: 
        !          2408:     KeReleaseSpinLock(
        !          2409:         &Extension->PollingLock,
        !          2410:         oldIrql
        !          2411:         );
        !          2412: 
        !          2413:     return returnValue;
        !          2414: 
        !          2415: }
        !          2416: 
        !          2417: VOID
        !          2418: ParPollingDpcRoutine(
        !          2419:     IN PKDPC Dpc,
        !          2420:     IN PVOID DeferredContext,
        !          2421:     IN PVOID SystemContext1,
        !          2422:     IN PVOID SystemContext2
        !          2423:     )
        !          2424: 
        !          2425: /*++
        !          2426: 
        !          2427: Routine Description:
        !          2428: 
        !          2429:     This routine is invoked by the polling timer.  It will
        !          2430:     call the parsynchronizeexecution routine to call the
        !          2431:     real polling routine.
        !          2432: 
        !          2433: Arguments:
        !          2434: 
        !          2435:     Dpc - Not Used.
        !          2436: 
        !          2437:     DeferredContext - Really points to the device extension.
        !          2438: 
        !          2439:     SystemContext1 - Not Used.
        !          2440: 
        !          2441:     SystemContext2 - Not Used.
        !          2442: 
        !          2443: Return Value:
        !          2444: 
        !          2445:     None.
        !          2446: 
        !          2447: --*/
        !          2448: 
        !          2449: {
        !          2450: 
        !          2451:     PPAR_DEVICE_EXTENSION extension = DeferredContext;
        !          2452: 
        !          2453:     UNREFERENCED_PARAMETER(Dpc);
        !          2454:     UNREFERENCED_PARAMETER(SystemContext1);
        !          2455:     UNREFERENCED_PARAMETER(SystemContext2);
        !          2456: 
        !          2457:     ParSynchronizeExecution(
        !          2458:         extension,
        !          2459:         ParPolling,
        !          2460:         extension
        !          2461:         );
        !          2462: 
        !          2463: }
        !          2464: 
        !          2465: BOOLEAN
        !          2466: ParPolling(
        !          2467:     IN PVOID Context
        !          2468:     )
        !          2469: 
        !          2470: /*++
        !          2471: 
        !          2472: Routine Description:
        !          2473: 
        !          2474:     This routine is used to drive write requests on a device
        !          2475:     that doesn't isn't using interrupts.
        !          2476: 
        !          2477: Arguments:
        !          2478: 
        !          2479:     Context - really a pointer to the device extension
        !          2480: 
        !          2481: Return Value:
        !          2482: 
        !          2483:     None.
        !          2484: 
        !          2485: --*/
        !          2486: 
        !          2487: {
        !          2488: 
        !          2489:     PPAR_DEVICE_EXTENSION extension = Context;
        !          2490:     KIRQL oldIrql;
        !          2491:     ULONG callToIsr;
        !          2492:     ULONG ticks;
        !          2493: #define MAXTICKSTOWAIT    10000
        !          2494: #define MINTICKSTOWAIT    1
        !          2495: #define MAXTIMESCALLTOISR 10000
        !          2496: #define MAXMIKESINHERE    100000
        !          2497:     ULONG maxTimesCallToIsr = MAXTIMESCALLTOISR;
        !          2498:     ULONG maxTicksToWait = MAXTICKSTOWAIT;
        !          2499: 
        !          2500:     //
        !          2501:     // We try to call the isr maxTimesCallToIsr per each invocation
        !          2502:     // of this routine.
        !          2503:     //
        !          2504: 
        !          2505:     ParDump(
        !          2506:         PARPOLLREPORT,
        !          2507:         ("PARALLEL: Chars starting poll:  %d\n",
        !          2508:          extension->CountBuffer)
        !          2509:         );
        !          2510:     ParDump(
        !          2511:         PARPOLLREPORT,
        !          2512:         ("PARALLEL: Polling irp is:       %x\n",
        !          2513:          extension->DeviceObject->CurrentIrp)
        !          2514:         );
        !          2515: 
        !          2516:     //
        !          2517:     // If there isn't a current irp (like it got canceled somehow)
        !          2518:     // then simply get out.  This is only to write chars for the current
        !          2519:     // irp.
        !          2520:     //
        !          2521: 
        !          2522:     if (!extension->DeviceObject->CurrentIrp) {
        !          2523: 
        !          2524:         return FALSE;
        !          2525: 
        !          2526:     }
        !          2527: 
        !          2528:     for (
        !          2529:         callToIsr = 0;
        !          2530:         callToIsr < maxTimesCallToIsr;
        !          2531:         callToIsr++
        !          2532:         ) {
        !          2533: 
        !          2534:         //
        !          2535:         // We are willing to wait up to MAXTICKSTOWAIT uS "ticks" for each
        !          2536:         // call to the ISR to do something useful.
        !          2537:         //
        !          2538: 
        !          2539:         for (
        !          2540:             ticks = 0;
        !          2541:             ticks < maxTicksToWait;
        !          2542:             ticks++
        !          2543:             ) {
        !          2544: 
        !          2545:             if (ParInterruptServiceRoutine(
        !          2546:                     extension->Interrupt,
        !          2547:                     extension->DeviceObject
        !          2548:                     )) {
        !          2549: 
        !          2550:                 //
        !          2551:                 // We'll we got something done.  If the timercount
        !          2552:                 // is -1 then means we are completing the operation
        !          2553:                 // somehow.  If we are completing, let the normal
        !          2554:                 // completion code do its work.
        !          2555:                 //
        !          2556: 
        !          2557:                 if (extension->TimerCount == -1) {
        !          2558: 
        !          2559:                     ParDump(
        !          2560:                         PARPOLLREPORT,
        !          2561:                         ("PARALLEL: Polling says we're done\n")
        !          2562:                         );
        !          2563:                     return FALSE;
        !          2564: 
        !          2565:                 }
        !          2566: 
        !          2567:                 //
        !          2568:                 // Got did something useful.  Go for more.
        !          2569:                 //
        !          2570:                 // If this is the second time we did something then
        !          2571:                 // adjust the amount of work we do in this routine
        !          2572:                 // based on how long it took the call to work.
        !          2573:                 // We do the second call because the first call might have
        !          2574:                 // been influenced by the fact that this we sitting in the
        !          2575:                 // timer queue for a while and this lets the device get
        !          2576:                 // all caught up.
        !          2577:                 //
        !          2578: 
        !          2579:                 if (callToIsr == 1) {
        !          2580: 
        !          2581:                     if (ticks < MINTICKSTOWAIT) {
        !          2582: 
        !          2583:                         ticks = MINTICKSTOWAIT;
        !          2584: 
        !          2585:                     }
        !          2586: 
        !          2587:                     //
        !          2588:                     // The maximum amount of time we want to spend
        !          2589:                     // in here is MAXMIKESINHERE.  We divide it by
        !          2590:                     // the number of ticks it took for the second
        !          2591:                     // call to the isr.
        !          2592:                     //
        !          2593: 
        !          2594:                     maxTicksToWait = ticks;
        !          2595: 
        !          2596:                     maxTimesCallToIsr = MAXMIKESINHERE / maxTicksToWait;
        !          2597: 
        !          2598:                     if (maxTimesCallToIsr > MAXTIMESCALLTOISR) {
        !          2599: 
        !          2600:                         //
        !          2601:                         // If we are on a really fast machine, or
        !          2602:                         // we are on a really fast printer (or both) let's
        !          2603:                         // not use up our full "slice".  Let's get out
        !          2604:                         // after MAXTIMESCALLTOISR.
        !          2605:                         //
        !          2606: 
        !          2607:                         maxTimesCallToIsr = MAXTIMESCALLTOISR;
        !          2608: 
        !          2609:                     }
        !          2610: 
        !          2611:                 }
        !          2612:                 goto doNextCallToIsr;
        !          2613: 
        !          2614:             } else {
        !          2615: 
        !          2616:                 //
        !          2617:                 // Not ready yet.  Stall for a microsecond.
        !          2618:                 //
        !          2619: 
        !          2620:                 KeStallExecutionProcessor(1);
        !          2621: 
        !          2622:             }
        !          2623: 
        !          2624:         }
        !          2625: 
        !          2626:         //
        !          2627:         // We didn't write the character within the amount
        !          2628:         // of time allocated.  Break out of the outer loop
        !          2629:         //
        !          2630: 
        !          2631:         break;
        !          2632: 
        !          2633: doNextCallToIsr: ;
        !          2634: 
        !          2635:     }
        !          2636: 
        !          2637:     //
        !          2638:     // All done trying to write characters.  Queue a timer to invoke us
        !          2639:     // again.
        !          2640:     //
        !          2641: 
        !          2642:     KeSetTimer(
        !          2643:         &extension->PollingTimer,
        !          2644:         extension->PollingDelayAmount,
        !          2645:         &extension->PollingDpc
        !          2646:         );
        !          2647: 
        !          2648:     ParDump(
        !          2649:         PARPOLLREPORT,
        !          2650:         ("PARALLEL: To go at end of poll: %d\n"
        !          2651:          "--------- Ticks per char is:    %d\n"
        !          2652:          "--------- Calls to isr per:     %d\n",
        !          2653:          extension->CountBuffer,
        !          2654:          maxTicksToWait,
        !          2655:          maxTimesCallToIsr)
        !          2656: 
        !          2657:         );
        !          2658: 
        !          2659:     return FALSE;
        !          2660: #undef MAXTICKSTOWAIT
        !          2661: #undef MINTICKSTOWAIT
        !          2662: #undef MAXTIMESCALLTOISR
        !          2663: #undef MAXMIKESINHERE
        !          2664: }
        !          2665: 
        !          2666: VOID
        !          2667: ParStartBusyTimer(
        !          2668:     IN PKDPC Dpc,
        !          2669:     IN PVOID DeferredContext,
        !          2670:     IN PVOID SystemContext1,
        !          2671:     IN PVOID SystemContext2
        !          2672:     )
        !          2673: 
        !          2674: /*++
        !          2675: 
        !          2676: Routine Description:
        !          2677: 
        !          2678:     This routine is invoked by the dpc that is queued by the
        !          2679:     ISR when it finds that it has work to do yet the status
        !          2680:     is busy.
        !          2681: 
        !          2682: Arguments:
        !          2683: 
        !          2684:     Dpc - Not Used.
        !          2685: 
        !          2686:     DeferredContext - Really points to the device extension.
        !          2687: 
        !          2688:     SystemContext1 - Not Used.
        !          2689: 
        !          2690:     SystemContext2 - Not Used.
        !          2691: 
        !          2692: Return Value:
        !          2693: 
        !          2694:     None.
        !          2695: 
        !          2696: --*/
        !          2697: 
        !          2698: {
        !          2699: 
        !          2700:     PPAR_DEVICE_EXTENSION extension = DeferredContext;
        !          2701: 
        !          2702:     UNREFERENCED_PARAMETER(Dpc);
        !          2703:     UNREFERENCED_PARAMETER(SystemContext1);
        !          2704:     UNREFERENCED_PARAMETER(SystemContext2);
        !          2705: 
        !          2706:     ParDump(
        !          2707:         PARBUSYPATH,
        !          2708:         ("Parallel: In start busy timer dpc\n")
        !          2709:         );
        !          2710:     KeSetTimer(
        !          2711:         &extension->BusyTimer,
        !          2712:         extension->BusyDelayAmount,
        !          2713:         &extension->BusyTimerDpc
        !          2714:         );
        !          2715: 
        !          2716: }
        !          2717: 
        !          2718: VOID
        !          2719: ParBusyTimer(
        !          2720:     IN PKDPC Dpc,
        !          2721:     IN PVOID DeferredContext,
        !          2722:     IN PVOID SystemContext1,
        !          2723:     IN PVOID SystemContext2
        !          2724:     )
        !          2725: 
        !          2726: /*++
        !          2727: 
        !          2728: Routine Description:
        !          2729: 
        !          2730:     This routine is invoked by the dpc that is queued by when
        !          2731:     the busy timer fires.
        !          2732: 
        !          2733: Arguments:
        !          2734: 
        !          2735:     Dpc - Not Used.
        !          2736: 
        !          2737:     DeferredContext - Really points to the device extension.
        !          2738: 
        !          2739:     SystemContext1 - Not Used.
        !          2740: 
        !          2741:     SystemContext2 - Not Used.
        !          2742: 
        !          2743: Return Value:
        !          2744: 
        !          2745:     None.
        !          2746: 
        !          2747: --*/
        !          2748: 
        !          2749: {
        !          2750: 
        !          2751:     PPAR_DEVICE_EXTENSION extension = DeferredContext;
        !          2752: 
        !          2753:     UNREFERENCED_PARAMETER(Dpc);
        !          2754:     UNREFERENCED_PARAMETER(SystemContext1);
        !          2755:     UNREFERENCED_PARAMETER(SystemContext2);
        !          2756: 
        !          2757:     ParDump(
        !          2758:         PARBUSYPATH,
        !          2759:         ("Parallel: In busy timer dpc\n")
        !          2760:         );
        !          2761:     ParSynchronizeExecution(
        !          2762:         extension,
        !          2763:         ParBusyCallIsr,
        !          2764:         extension
        !          2765:         );
        !          2766: 
        !          2767: }
        !          2768: 
        !          2769: BOOLEAN
        !          2770: ParBusyCallIsr(
        !          2771:     IN PVOID Context
        !          2772:     )
        !          2773: 
        !          2774: /*++
        !          2775: 
        !          2776: Routine Description:
        !          2777: 
        !          2778:     This routine is invoked via KeSynchronize execution which
        !          2779:     was invoked by the dpc associated with the busy timer.
        !          2780:     Its sole purpose is to call the interrupt service routine.
        !          2781: 
        !          2782: Arguments:
        !          2783: 
        !          2784:     Context - Really a pointer to the device extension.
        !          2785: 
        !          2786: Return Value:
        !          2787: 
        !          2788:     Always False.
        !          2789: 
        !          2790: --*/
        !          2791: 
        !          2792: {
        !          2793: 
        !          2794:     PPAR_DEVICE_EXTENSION extension = Context;
        !          2795: 
        !          2796:     extension->BusyPath = FALSE;
        !          2797: 
        !          2798:     ParDump(
        !          2799:         PARBUSYPATH,
        !          2800:         ("Parallel: In busy timer - about to call isr\n")
        !          2801:         );
        !          2802:     ParInterruptServiceRoutine(
        !          2803:         extension->Interrupt,
        !          2804:         extension->DeviceObject
        !          2805:         );
        !          2806: 
        !          2807:     return FALSE;
        !          2808: 
        !          2809: }

unix.superglobalmegacorp.com

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