Annotation of ntddk/src/comm/oldpar/pardrvr.c, revision 1.1.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.