Annotation of ntddk/src/comm/parallel/pardrvr.c, revision 1.1.1.1

1.1       root        1: /*++
                      2: 
                      3: Copyright (c) 1990, 1991, 1992, 1993 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:     Complete rewrite to make it thread based and polled.
                     21: 
                     22: 
                     23: --*/
                     24: 
                     25: //
                     26: // Note that we include ntddser that we can use the serials
                     27: // timeout structure and ioctl to set the timeout for a write.
                     28: //
                     29: 
                     30: #include <stddef.h>
                     31: #include "ntddk.h"
                     32: #include "ntddpar.h"
                     33: #include "ntddser.h"
                     34: #include "par.h"
                     35: #include "parlog.h"
                     36: 
                     37: #define VALID_FLAGS PARALLEL_INIT & ( PARALLEL_INIT | PARALLEL_AUTOFEED )
                     38: 
                     39: //
                     40: // Busy, PE
                     41: //
                     42: 
                     43: #define PAR_PAPER_EMPTY( Status ) ( \
                     44:             (Status & PAR_STATUS_PE) )
                     45: 
                     46: //
                     47: // Busy, not select, not error
                     48: //
                     49: 
                     50: #define PAR_OFF_LINE( Status ) ( \
                     51:             (Status & PAR_STATUS_NOT_ERROR) && \
                     52:             ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
                     53:             !(Status & PAR_STATUS_SLCT) )
                     54: 
                     55: //
                     56: // error, ack, not busy
                     57: //
                     58: 
                     59: #define PAR_POWERED_OFF( Status ) ( \
                     60:             ((Status & PAR_STATUS_NOT_ERROR) ^ PAR_STATUS_NOT_ERROR) && \
                     61:             ((Status & PAR_STATUS_NOT_ACK) ^ PAR_STATUS_NOT_ACK) && \
                     62:             (Status & PAR_STATUS_NOT_BUSY))
                     63: 
                     64: //
                     65: // not error, not busy, not select
                     66: //
                     67: 
                     68: #define PAR_NOT_CONNECTED( Status ) ( \
                     69:             (Status & PAR_STATUS_NOT_ERROR) && \
                     70:             (Status & PAR_STATUS_NOT_BUSY) &&\
                     71:             !(Status & PAR_STATUS_SLCT) )
                     72: 
                     73: //
                     74: // not error, not busy
                     75: //
                     76: 
                     77: #define PAR_OK(Status) ( \
                     78:             (Status & PAR_STATUS_NOT_ERROR) && \
                     79:             ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
                     80:             (Status & PAR_STATUS_NOT_BUSY) )
                     81: 
                     82: //
                     83: // not error, not busy, selected.
                     84: //
                     85: #define PAR_ONLINE(Status) ( \
                     86:             (Status & PAR_STATUS_NOT_ERROR) && \
                     87:             (Status & PAR_STATUS_NOT_BUSY) && \
                     88:             ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
                     89:             (Status & PAR_STATUS_SLCT) )
                     90: 
                     91:     //
                     92: // busy, select, not error
                     93: //
                     94: 
                     95: #define PAR_POWERED_ON(Status) ( \
                     96:             ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
                     97:             (Status & PAR_STATUS_SLCT) && \
                     98:             (Status & PAR_STATUS_NOT_ERROR))
                     99: 
                    100: //
                    101: // busy, not error
                    102: //
                    103: 
                    104: #define PAR_BUSY(Status) (\
                    105:              (( Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
                    106:              ( Status & PAR_STATUS_NOT_ERROR ) )
                    107: 
                    108: //
                    109: // selected
                    110: //
                    111: 
                    112: #define PAR_SELECTED(Status) ( \
                    113:             ( Status & PAR_STATUS_SLCT ) )
                    114: 
                    115: //
                    116: // No cable attached.
                    117: //
                    118: #define PAR_NO_CABLE(Status) ( \
                    119:             ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
                    120:             (Status & PAR_STATUS_NOT_ACK) &&                          \
                    121:             (Status & PAR_STATUS_PE) &&                               \
                    122:             (Status & PAR_STATUS_SLCT) &&                             \
                    123:             (Status & PAR_STATUS_NOT_ERROR))
                    124: 
                    125: //
                    126: // autofeed
                    127: //
                    128: 
                    129: #define PAR_AUTOFEED( Control ) (\
                    130:             ( Control & PAR_CONTROL_AUTOFD ) )
                    131: 
                    132: typedef struct _LOAD_PACKET {
                    133:     NTSTATUS *Status;
                    134:     PPAR_DEVICE_EXTENSION Extension;
                    135:     WORK_QUEUE_ITEM WorkQueueItem;
                    136:     KEVENT Event;
                    137:     } LOAD_PACKET,*PLOAD_PACKET;
                    138: 
                    139: VOID
                    140: ParallelThread(
                    141:     IN PVOID Context
                    142:     );
                    143: 
                    144: VOID
                    145: ParWriteOutData(
                    146:     PPAR_DEVICE_EXTENSION Extension
                    147:     );
                    148: 
                    149: VOID
                    150: ParCreateSystemThread(
                    151:     PVOID Context
                    152:     );
                    153: 
                    154: VOID
                    155: ParNotInitError(
                    156:     IN PPAR_DEVICE_EXTENSION Extension,
                    157:     IN UCHAR deviceStatus
                    158:     );
                    159: 
                    160: 
                    161: UCHAR
                    162: ParInitializeDevice(
                    163:     IN PPAR_DEVICE_EXTENSION Extension
                    164:     )
                    165: 
                    166: /*++
                    167: 
                    168: Routine Description:
                    169: 
                    170:     This routine is invoked to initialize the parallel port drive.
                    171:     It performs the following actions:
                    172: 
                    173:         o   Send INIT to the driver and if the device is online, it sends
                    174:             SLIN
                    175: 
                    176: Arguments:
                    177: 
                    178:     Context - Really the device extension.
                    179: 
                    180: Return Value:
                    181: 
                    182:     The last value that we got from the status register.
                    183: 
                    184: --*/
                    185: 
                    186: {
                    187: 
                    188:     KIRQL oldIrql;
                    189:     LONG countDown;
                    190:     UCHAR deviceStatus;
                    191:     LARGE_INTEGER startOfSpin;
                    192:     LARGE_INTEGER nextQuery;
                    193:     LARGE_INTEGER difference;
                    194:     BOOLEAN doDelays;
                    195: 
                    196:     deviceStatus = GetStatus(Extension->Controller);
                    197:     ParDump(
                    198:         PARINITDEV,
                    199:         ("PARALLEL: In ParInitializeDevice - device status is %x\n"
                    200:          "          Initialized: %x\n",
                    201:          deviceStatus,
                    202:          Extension->Initialized)
                    203:         );
                    204: 
                    205:     if (!Extension->Initialized) {
                    206: 
                    207:         //
                    208:         // Clear the register.
                    209:         //
                    210: 
                    211:         if (GetControl(Extension->Controller) &
                    212:             PAR_CONTROL_NOT_INIT) {
                    213: 
                    214:             //
                    215:             // We should stall for at least 60 microseconds after
                    216:             // the init.
                    217:             //
                    218: 
                    219:             KeRaiseIrql(
                    220:                 DISPATCH_LEVEL,
                    221:                 &oldIrql
                    222:                 );
                    223:             StoreControl(
                    224:                 Extension->Controller,
                    225:                 (UCHAR)(PAR_CONTROL_WR_CONTROL)
                    226:                 );
                    227:             KeStallExecutionProcessor(60);
                    228:             KeLowerIrql(oldIrql);
                    229: 
                    230:         }
                    231: 
                    232:         if (Extension->AutoFeed) {
                    233: 
                    234:             StoreControl(
                    235:                 Extension->Controller,
                    236:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
                    237:                         PAR_CONTROL_AUTOFD)
                    238:                 );
                    239: 
                    240:         } else {
                    241: 
                    242:             StoreControl(
                    243:                 Extension->Controller,
                    244:                 (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT)
                    245:                 );
                    246: 
                    247:         }
                    248: 
                    249:         //
                    250:         // Spin for up to 15 seconds waiting for the device
                    251:         // to initialize.
                    252:         //
                    253: 
                    254:         countDown = 15;
                    255:         doDelays = FALSE;
                    256:         KeQueryTickCount(&startOfSpin);
                    257:         ParDump(
                    258:             PARINITDEV,
                    259:             ("PARALLEL: Starting init wait loop\n")
                    260:             );
                    261:         do {
                    262: 
                    263:             //
                    264:             // After about a second of spinning, let the rest of
                    265:             // the machine have time for one second.
                    266:             //
                    267: 
                    268:             if (doDelays) {
                    269: 
                    270:                 difference = RtlLargeIntegerNegate(Extension->AbsoluteOneSecond);
                    271:                 KeDelayExecutionThread(
                    272:                     KernelMode,
                    273:                     FALSE,
                    274:                     &difference
                    275:                     );
                    276:                 ParDump(
                    277:                     PARINITDEV,
                    278:                     ("PARALLEL: Did delay thread of one second\n")
                    279:                     );
                    280:                 countDown--;
                    281: 
                    282:             } else {
                    283: 
                    284:                 KeQueryTickCount(&nextQuery);
                    285: 
                    286:                 difference = RtlLargeIntegerSubtract(
                    287:                                  nextQuery,
                    288:                                  startOfSpin
                    289:                                  );
                    290: 
                    291:                 ASSERT(KeQueryTimeIncrement() <= MAXLONG);
                    292:                 if (RtlLargeIntegerGreaterThanOrEqualTo(
                    293:                         RtlExtendedIntegerMultiply(
                    294:                             difference,
                    295:                             (LONG)KeQueryTimeIncrement()
                    296:                             ),
                    297:                         Extension->AbsoluteOneSecond
                    298:                         )) {
                    299: 
                    300:                     ParDump(
                    301:                         PARINITDEV,
                    302:                         ("PARALLEL: Did spin of one second\n"
                    303:                          "          startOfSpin: %x nextQuery: %x\n",
                    304:                          startOfSpin.LowPart,nextQuery.LowPart)
                    305:                         );
                    306:                     ParDump(
                    307:                         PARINITDEV,
                    308:                         ("PARALLEL: parintialize 1 seconds wait\n")
                    309:                         );
                    310:                     countDown--;
                    311:                     doDelays = TRUE;
                    312: 
                    313:                 }
                    314: 
                    315:             }
                    316: 
                    317:             if (countDown <= 0) {
                    318: 
                    319:                 ParDump(
                    320:                     PARINITDEV,
                    321:                     ("PARALLEL: leaving with init timeout - status %x\n",
                    322:                      deviceStatus)
                    323:                     );
                    324:                 Extension->Initialized = FALSE;
                    325:                 return deviceStatus;
                    326: 
                    327:             }
                    328: 
                    329:             deviceStatus = GetStatus(Extension->Controller);
                    330: 
                    331:         } while (PAR_BUSY(deviceStatus) ||
                    332:                  ((!PAR_OK(deviceStatus)) &&
                    333:                   (!PAR_OFF_LINE(deviceStatus)) &&
                    334:                   (!PAR_POWERED_OFF(deviceStatus)) &&
                    335:                   (!PAR_NOT_CONNECTED(deviceStatus)) &&
                    336:                   (!PAR_NO_CABLE(deviceStatus))));
                    337: 
                    338:         if (PAR_OK(deviceStatus) || PAR_OFF_LINE(deviceStatus)) {
                    339: 
                    340:             ParDump(
                    341:                 PARINITDEV,
                    342:                 ("PARALLEL: device is set to initialized\n")
                    343:                 );
                    344:             Extension->Initialized = TRUE;
                    345: 
                    346:         }
                    347: 
                    348:     }
                    349: 
                    350:     ParDump(
                    351:         PARINITDEV,
                    352:         ("PARALLEL: In ParInitializeDevice - leaving with device status is %x\n",
                    353:          deviceStatus)
                    354:         );
                    355:     return deviceStatus;
                    356: 
                    357: }
                    358: 
                    359: NTSTATUS
                    360: ParCreateOpen(
                    361:     IN PDEVICE_OBJECT DeviceObject,
                    362:     IN PIRP Irp
                    363:     )
                    364: 
                    365: {
                    366: 
                    367:     NTSTATUS returnStatus;
                    368:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
                    369:     PLOAD_PACKET loadPacket;
                    370: 
                    371:     ParDump(
                    372:         PARIRPPATH,
                    373:         ("PARALLEL: In create/open with IRP: %x\n",
                    374:          Irp)
                    375:         );
                    376:     Irp->IoStatus.Information = 0;
                    377: 
                    378:     if (!extension->Initialized) {
                    379: 
                    380:         UCHAR deviceStatus = ParInitializeDevice(extension);
                    381: 
                    382:         if (!extension->Initialized) {
                    383: 
                    384:             extension->CurrentOpIrp = Irp;
                    385: 
                    386:             ParNotInitError(
                    387:                 extension,
                    388:                 deviceStatus
                    389:                 );
                    390: 
                    391:             extension->CurrentOpIrp = NULL;
                    392:             returnStatus = Irp->IoStatus.Status;
                    393:             goto AllDone;
                    394: 
                    395:         }
                    396: 
                    397:     }
                    398: 
                    399:     extension->TimeToTerminateThread = FALSE;
                    400:     extension->ThreadObjectPointer = NULL;
                    401:     ParDump(
                    402:         PARTHREAD,
                    403:         ("PARALLEL: open initializing - state before init - %d\n",
                    404:          extension->RequestSemaphore.Header.SignalState)
                    405:         );
                    406:     KeInitializeSemaphore(
                    407:         &extension->RequestSemaphore,
                    408:         0L,
                    409:         MAXLONG
                    410:         );
                    411: 
                    412:     if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options
                    413:         & FILE_DIRECTORY_FILE) {
                    414: 
                    415:         returnStatus = Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
                    416: 
                    417:     } else {
                    418: 
                    419:         loadPacket = ExAllocatePool(
                    420:                         PagedPool,
                    421:                         sizeof(LOAD_PACKET)
                    422:                         );
                    423: 
                    424:         if (!loadPacket) {
                    425: 
                    426:             returnStatus = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                    427: 
                    428:         } else {
                    429: 
                    430:             loadPacket->Status = &Irp->IoStatus.Status;
                    431:             loadPacket->Extension = extension;
                    432:             KeInitializeEvent(
                    433:                 &loadPacket->Event,
                    434:                 NotificationEvent,
                    435:                 FALSE
                    436:                 );
                    437:             ExInitializeWorkItem(
                    438:                 &loadPacket->WorkQueueItem,
                    439:                 ParCreateSystemThread,
                    440:                 loadPacket
                    441:                 );
                    442:             ExQueueWorkItem(
                    443:                 &loadPacket->WorkQueueItem,
                    444:                 DelayedWorkQueue
                    445:                 );
                    446:             KeWaitForSingleObject(
                    447:                 &loadPacket->Event,
                    448:                 UserRequest,
                    449:                 KernelMode,
                    450:                 FALSE,
                    451:                 NULL
                    452:                 );
                    453: 
                    454:             returnStatus = Irp->IoStatus.Status;
                    455: 
                    456:         }
                    457: 
                    458:     }
                    459: 
                    460: AllDone:;
                    461: 
                    462:     ParDump(
                    463:         PARIRPPATH,
                    464:         ("PARALLEL: About to complete IRP in create/open\n"
                    465:          "Irp: %x status: %x Information: %x\n",
                    466:          Irp,
                    467:          Irp->IoStatus.Status,
                    468:          Irp->IoStatus.Information)
                    469:         );
                    470:     IoCompleteRequest(
                    471:         Irp,
                    472:         IO_NO_INCREMENT
                    473:         );
                    474: 
                    475:     return returnStatus;
                    476: 
                    477: }
                    478: 
                    479: VOID
                    480: ParCreateSystemThread(
                    481:     PVOID Context
                    482:     )
                    483: 
                    484: {
                    485: 
                    486:     HANDLE threadHandle;
                    487:     //
                    488:     // This function is executing in the context of a system
                    489:     // worker thread.  It is used so that we can create a
                    490:     // thread in the context of the system process.
                    491:     //
                    492: 
                    493:     PLOAD_PACKET lp = Context;
                    494: 
                    495:     //
                    496:     // Start the thread and capture the thread handle into the extension
                    497:     //
                    498: 
                    499:     *lp->Status = PsCreateSystemThread(
                    500:                      &threadHandle,
                    501:                      THREAD_ALL_ACCESS,
                    502:                      NULL,
                    503:                      NULL,
                    504:                      NULL,
                    505:                      ParallelThread,
                    506:                      lp->Extension
                    507:                      );
                    508: 
                    509:     if (!NT_ERROR(*lp->Status)) {
                    510: 
                    511:         //
                    512:         // We've got the thread.  Now get a pointer to it.
                    513:         //
                    514: 
                    515:         *lp->Status = ObReferenceObjectByHandle(
                    516:                            threadHandle,
                    517:                            THREAD_ALL_ACCESS,
                    518:                            NULL,
                    519:                            KernelMode,
                    520:                            &lp->Extension->ThreadObjectPointer,
                    521:                            NULL
                    522:                            );
                    523: 
                    524:         if (NT_ERROR(*lp->Status)) {
                    525: 
                    526:             ParDump(
                    527:                 PARIRPPATH,
                    528:                 ("PARALLEL: Bad status on open from ref by handle: %x\n",
                    529:                  *lp->Status)
                    530:                 );
                    531: 
                    532:             lp->Extension->TimeToTerminateThread = TRUE;
                    533:             KeReleaseSemaphore(
                    534:                 &lp->Extension->RequestSemaphore,
                    535:                 0,
                    536:                 1,
                    537:                 FALSE
                    538:                 );
                    539: 
                    540:         } else {
                    541: 
                    542:             //
                    543:             // Now that we have a reference to the thread
                    544:             // we can simply close the handle.
                    545:             //
                    546: 
                    547:             ZwClose(threadHandle);
                    548: 
                    549:         }
                    550: 
                    551:     } else {
                    552: 
                    553:         ParDump(
                    554:             PARIRPPATH,
                    555:             ("PARALLEL: Bad status on open from ref by handle: %x\n",
                    556:              *lp->Status)
                    557:             );
                    558: 
                    559:     }
                    560: 
                    561:     //
                    562:     // We're all done.  Let the open code proceed.
                    563:     //
                    564: 
                    565:     KeSetEvent(
                    566:         &lp->Event,
                    567:         0,
                    568:         FALSE
                    569:         );
                    570: 
                    571: }
                    572: 
                    573: NTSTATUS
                    574: ParClose(
                    575:     IN PDEVICE_OBJECT DeviceObject,
                    576:     IN PIRP Irp
                    577:     )
                    578: 
                    579: {
                    580: 
                    581:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
                    582:     NTSTATUS statusOfWait;
                    583: 
                    584:     ParDump(
                    585:         PARIRPPATH,
                    586:         ("PARALLEL: In close with IRP: %x\n",
                    587:          Irp)
                    588:         );
                    589: 
                    590:     //
                    591:     // Set the semaphore that will wake up the thread, which
                    592:     // will then notice that the thread is supposed to die.
                    593:     //
                    594: 
                    595:     Irp->IoStatus.Status = STATUS_SUCCESS;
                    596:     Irp->IoStatus.Information = 0;
                    597:     extension->TimeToTerminateThread = TRUE;
                    598:     ParDump(
                    599:         PARTHREAD,
                    600:         ("PARALLEL: close releasing - state before release - %d\n",
                    601:          extension->RequestSemaphore.Header.SignalState)
                    602:         );
                    603:     KeReleaseSemaphore(
                    604:         &extension->RequestSemaphore,
                    605:         0,
                    606:         1,
                    607:         FALSE
                    608:         );
                    609: 
                    610:     //
                    611:     // Wait on the thread handle, when the wait is satisfied, the
                    612:     // thread has gone away.
                    613:     //
                    614: 
                    615:     statusOfWait = KeWaitForSingleObject(
                    616:                        extension->ThreadObjectPointer,
                    617:                        UserRequest,
                    618:                        KernelMode,
                    619:                        FALSE,
                    620:                        NULL
                    621:                        );
                    622: 
                    623:     ParDump(
                    624:         PARTHREAD,
                    625:         ("PARALLEL: return status of waiting for thread to die: %x\n",
                    626:          statusOfWait)
                    627:         );
                    628: 
                    629:     //
                    630:     // Thread is gone.  Status is successful for the close.
                    631:     // Defreference the pointer to the thread object.
                    632:     //
                    633: 
                    634:     ObDereferenceObject(extension->ThreadObjectPointer);
                    635:     extension->ThreadObjectPointer = NULL;
                    636: 
                    637:     ParDump(
                    638:         PARIRPPATH,
                    639:         ("PARALLEL: About to complete IRP in close\n"
                    640:          "Irp: %x status: %x Information: %x\n",
                    641:          Irp,
                    642:          Irp->IoStatus.Status,
                    643:          Irp->IoStatus.Information)
                    644:         );
                    645:     IoCompleteRequest(
                    646:         Irp,
                    647:         IO_NO_INCREMENT
                    648:         );
                    649: 
                    650:     return STATUS_SUCCESS;
                    651: }
                    652: 
                    653: NTSTATUS
                    654: ParCleanup(
                    655:     IN PDEVICE_OBJECT DeviceObject,
                    656:     IN PIRP Irp
                    657:     )
                    658: 
                    659: {
                    660: 
                    661:     KIRQL cancelIrql;
                    662:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
                    663: 
                    664:     ParDump(
                    665:         PARIRPPATH,
                    666:         ("PARALLEL: In cleanup with IRP: %x\n",
                    667:          Irp)
                    668:         );
                    669: 
                    670:     //
                    671:     // While the list is not empty, go through and cancel each irp.
                    672:     //
                    673: 
                    674:     IoAcquireCancelSpinLock(&cancelIrql);
                    675: 
                    676: 
                    677:     //
                    678:     // Clean the list from back to front.
                    679:     //
                    680: 
                    681:     while (!IsListEmpty(&extension->WorkQueue)) {
                    682: 
                    683:         PDRIVER_CANCEL cancelRoutine;
                    684:         PIRP currentLastIrp = CONTAINING_RECORD(
                    685:                                   extension->WorkQueue.Blink,
                    686:                                   IRP,
                    687:                                   Tail.Overlay.ListEntry
                    688:                                   );
                    689: 
                    690:         RemoveEntryList(extension->WorkQueue.Blink);
                    691: 
                    692:         cancelRoutine = currentLastIrp->CancelRoutine;
                    693:         currentLastIrp->CancelIrql = cancelIrql;
                    694:         currentLastIrp->CancelRoutine = NULL;
                    695:         currentLastIrp->Cancel = TRUE;
                    696: 
                    697:         cancelRoutine(
                    698:             DeviceObject,
                    699:             currentLastIrp
                    700:             );
                    701: 
                    702:         IoAcquireCancelSpinLock(&cancelIrql);
                    703: 
                    704:     }
                    705: 
                    706:     //
                    707:     // If there is a current irp then mark it as cancelled.
                    708:     //
                    709: 
                    710:     if (extension->CurrentOpIrp) {
                    711: 
                    712:         extension->CurrentOpIrp->Cancel = TRUE;
                    713: 
                    714:     }
                    715: 
                    716:     IoReleaseCancelSpinLock(cancelIrql);
                    717: 
                    718:     Irp->IoStatus.Status = STATUS_SUCCESS;
                    719:     Irp->IoStatus.Information=0L;
                    720: 
                    721:     ParDump(
                    722:         PARIRPPATH,
                    723:         ("PARALLEL: About to complete IRP in cleanup\n"
                    724:          "Irp: %x status: %x Information: %x\n",
                    725:          Irp,
                    726:          Irp->IoStatus.Status,
                    727:          Irp->IoStatus.Information)
                    728:         );
                    729:     IoCompleteRequest(
                    730:         Irp,
                    731:         IO_NO_INCREMENT
                    732:         );
                    733: 
                    734:     return STATUS_SUCCESS;
                    735: }
                    736: 
                    737: NTSTATUS
                    738: ParDispatch(
                    739:     IN PDEVICE_OBJECT DeviceObject,
                    740:     IN PIRP Irp
                    741:     )
                    742: 
                    743: /*++
                    744: 
                    745: Routine Description:
                    746: 
                    747:     This is the main dispatch routine for the parallel port driver.
                    748:     It is given a pointer to the IRP for the current request and
                    749:     it determines what to do with it. If the request is valid and doen't
                    750:     have any parameter errors, then it is placed into the work queue.
                    751:     Otherwise it is not completed and an appropriate error is returned.
                    752: 
                    753: Arguments:
                    754: 
                    755:     DeviceObject - Pointer to the device object for this device
                    756: 
                    757:     Irp - Pointer to the IRP for the current request
                    758: 
                    759: Return Value:
                    760: 
                    761:     The function value is the final status of call
                    762: 
                    763: --*/
                    764: 
                    765: {
                    766: 
                    767:     NTSTATUS status = STATUS_SUCCESS;
                    768:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
                    769:     PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
                    770: 
                    771:     ParDump(
                    772:         PARIRPPATH,
                    773:         ("PARALLEL: In main dispatch with IRP: %x\n"
                    774:          "MAIN: %d io control code: %d\n",
                    775:          Irp,
                    776:          irpSp->MajorFunction,
                    777:          irpSp->Parameters.DeviceIoControl.IoControlCode)
                    778:         );
                    779:     Irp->IoStatus.Information=0L;
                    780:     switch(irpSp->MajorFunction) {
                    781: 
                    782:         case IRP_MJ_WRITE:
                    783: 
                    784:             if ((irpSp->Parameters.Write.ByteOffset.HighPart != 0) ||
                    785:                 (irpSp->Parameters.Write.ByteOffset.LowPart != 0)) {
                    786: 
                    787:                 status = STATUS_INVALID_PARAMETER;
                    788: 
                    789:             } else {
                    790: 
                    791:                 if (irpSp->Parameters.Write.Length != 0) {
                    792: 
                    793:                     status = STATUS_PENDING;
                    794:                 }
                    795: 
                    796:             }
                    797: 
                    798:             break;
                    799: 
                    800:         case IRP_MJ_DEVICE_CONTROL:
                    801: 
                    802:             switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
                    803: 
                    804:                 case IOCTL_PAR_SET_INFORMATION :
                    805: 
                    806:                     if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
                    807:                         1) {
                    808: 
                    809:                         status = STATUS_BUFFER_TOO_SMALL;
                    810: 
                    811:                     } else {
                    812: 
                    813:                         PPAR_SET_INFORMATION irpBuffer =
                    814:                             Irp->AssociatedIrp.SystemBuffer;
                    815: 
                    816:                         //
                    817:                         // INIT is required, AUTOFEED is optional
                    818:                         //
                    819: 
                    820:                         if (!(irpBuffer->Init & PARALLEL_INIT) ||
                    821:                              (irpBuffer->Init & ~VALID_FLAGS)) {
                    822: 
                    823:                             status = STATUS_INVALID_PARAMETER;
                    824: 
                    825:                         } else {
                    826: 
                    827:                             status = STATUS_PENDING;
                    828:                         }
                    829: 
                    830:                     }
                    831: 
                    832:                     break;
                    833: 
                    834:                 case IOCTL_PAR_QUERY_INFORMATION :
                    835: 
                    836:                     if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
                    837:                         sizeof(PAR_QUERY_INFORMATION)) {
                    838: 
                    839:                         status = STATUS_BUFFER_TOO_SMALL;
                    840: 
                    841:                     } else {
                    842: 
                    843:                         status = STATUS_PENDING;
                    844:                     }
                    845: 
                    846:                     break;
                    847: 
                    848:                 case IOCTL_SERIAL_SET_TIMEOUTS: {
                    849: 
                    850:                     PSERIAL_TIMEOUTS NewTimeouts =
                    851:                         ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
                    852: 
                    853:                     if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
                    854:                         sizeof(SERIAL_TIMEOUTS)) {
                    855: 
                    856:                         status = STATUS_BUFFER_TOO_SMALL;
                    857:                         break;
                    858: 
                    859:                     } else if (NewTimeouts->WriteTotalTimeoutConstant < 2000) {
                    860: 
                    861:                         status = STATUS_INVALID_PARAMETER;
                    862:                         break;
                    863: 
                    864:                     }
                    865: 
                    866:                     status = STATUS_PENDING;
                    867: 
                    868:                     break;
                    869: 
                    870:                 }
                    871:                 case IOCTL_SERIAL_GET_TIMEOUTS:
                    872: 
                    873:                     if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
                    874:                         sizeof(SERIAL_TIMEOUTS)) {
                    875: 
                    876:                         status = STATUS_BUFFER_TOO_SMALL;
                    877:                         break;
                    878: 
                    879:                     }
                    880: 
                    881:                     //
                    882:                     // We don't need to synchronize the read.
                    883:                     //
                    884: 
                    885:                     RtlZeroMemory(
                    886:                         Irp->AssociatedIrp.SystemBuffer,
                    887:                         sizeof(SERIAL_TIMEOUTS)
                    888:                         );
                    889:                     Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
                    890:                     ((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer)->
                    891:                         WriteTotalTimeoutConstant =
                    892:                         extension->TimerStart * 1000;
                    893: 
                    894:                     break;
                    895: 
                    896:                 default :
                    897: 
                    898:                     status = STATUS_INVALID_PARAMETER;
                    899:                     break;
                    900: 
                    901:             }
                    902: 
                    903:             break;
                    904: 
                    905:         default:
                    906: 
                    907:             status = STATUS_INVALID_PARAMETER;
                    908:             break;
                    909: 
                    910:     }
                    911: 
                    912:     Irp->IoStatus.Status = status;
                    913: 
                    914:     if (status == STATUS_PENDING) {
                    915: 
                    916:         KIRQL oldIrql;
                    917: 
                    918:         //
                    919:         // Acquire the cancel spin lock and put it on the
                    920:         // io queue. Then hit the semaphore and return.
                    921:         //
                    922: 
                    923:         IoAcquireCancelSpinLock(&oldIrql);
                    924: 
                    925:         if (Irp->Cancel) {
                    926: 
                    927:             IoReleaseCancelSpinLock(oldIrql);
                    928: 
                    929:             status = STATUS_CANCELLED;
                    930:             ParDump(
                    931:                 PARIRPPATH,
                    932:                 ("PARALLEL: About to CANCEL IRP in main dispatch\n"
                    933:                  "Irp: %x status: %x Information: %x\n",
                    934:                  Irp,
                    935:                  Irp->IoStatus.Status,
                    936:                  Irp->IoStatus.Information)
                    937:                 );
                    938:             IoCompleteRequest(
                    939:                 Irp,
                    940:                 IO_NO_INCREMENT
                    941:                 );
                    942: 
                    943:         } else {
                    944: 
                    945:             ParDump(
                    946:                 PARIRPPATH,
                    947:                 ("PARALLEL: About to QUEUE IRP in main dispatch\n"
                    948:                  "Irp: %x status: %x Information: %x\n",
                    949:                  Irp,
                    950:                  Irp->IoStatus.Status,
                    951:                  Irp->IoStatus.Information)
                    952:                 );
                    953:             Irp->IoStatus.Status = STATUS_PENDING;
                    954:             IoMarkIrpPending(Irp);
                    955:             IoSetCancelRoutine(
                    956:                 Irp,
                    957:                 ParCancelRequest
                    958:                 );
                    959: 
                    960:             InsertTailList(
                    961:                 &extension->WorkQueue,
                    962:                 &Irp->Tail.Overlay.ListEntry
                    963:                 );
                    964: 
                    965:             IoReleaseCancelSpinLock(oldIrql);
                    966: 
                    967:             ParDump(
                    968:                 PARTHREAD,
                    969:                 ("PARALLEL: dispatch releasing - state before release - %d\n",
                    970:                  extension->RequestSemaphore.Header.SignalState)
                    971:                 );
                    972:             KeReleaseSemaphore(
                    973:                 &extension->RequestSemaphore,
                    974:                 (KPRIORITY)0,
                    975:                 1,
                    976:                 FALSE
                    977:                 );
                    978: 
                    979:         }
                    980: 
                    981:     } else {
                    982: 
                    983:         ParDump(
                    984:             PARIRPPATH,
                    985:             ("PARALLEL: About to complete IRP in main dispatch\n"
                    986:              "Irp: %x status: %x Information: %x\n",
                    987:              Irp,
                    988:              Irp->IoStatus.Status,
                    989:              Irp->IoStatus.Information)
                    990:             );
                    991:         IoCompleteRequest(
                    992:             Irp,
                    993:             IO_NO_INCREMENT
                    994:             );
                    995: 
                    996:     }
                    997: 
                    998:     return status;
                    999: 
                   1000: }
                   1001: 
                   1002: NTSTATUS
                   1003: ParQueryInformationFile(
                   1004:     IN PDEVICE_OBJECT DeviceObject,
                   1005:     IN PIRP Irp
                   1006:     )
                   1007: 
                   1008: /*++
                   1009: 
                   1010: Routine Description:
                   1011: 
                   1012:     This routine is used to query the end of file information on
                   1013:     the opened parallel port.  Any other file information request
                   1014:     is retured with an invalid parameter.
                   1015: 
                   1016:     This routine always returns an end of file of 0.
                   1017: 
                   1018: Arguments:
                   1019: 
                   1020:     DeviceObject - Pointer to the device object for this device
                   1021: 
                   1022:     Irp - Pointer to the IRP for the current request
                   1023: 
                   1024: Return Value:
                   1025: 
                   1026:     The function value is the final status of the call
                   1027: 
                   1028: --*/
                   1029: 
                   1030: {
                   1031:     //
                   1032:     // The status that gets returned to the caller and
                   1033:     // set in the Irp.
                   1034:     //
                   1035:     NTSTATUS status = STATUS_SUCCESS;
                   1036: 
                   1037:     //
                   1038:     // The current stack location.  This contains all of the
                   1039:     // information we need to process this particular request.
                   1040:     //
                   1041:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
                   1042: 
                   1043:     UNREFERENCED_PARAMETER(DeviceObject);
                   1044: 
                   1045:     ParDump(
                   1046:         PARIRPPATH,
                   1047:         ("PARALLEL: In query information file with Irp: %x\n",
                   1048:          Irp)
                   1049:         );
                   1050:     Irp->IoStatus.Information = 0L;
                   1051:     if (irpSp->Parameters.QueryFile.FileInformationClass ==
                   1052:         FileStandardInformation) {
                   1053: 
                   1054:         PFILE_STANDARD_INFORMATION buf = Irp->AssociatedIrp.SystemBuffer;
                   1055: 
                   1056:         buf->AllocationSize = RtlConvertUlongToLargeInteger(0ul);
                   1057:         buf->EndOfFile = buf->AllocationSize;
                   1058:         buf->NumberOfLinks = 0;
                   1059:         buf->DeletePending = FALSE;
                   1060:         buf->Directory = FALSE;
                   1061:         Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
                   1062: 
                   1063:     } else if (irpSp->Parameters.QueryFile.FileInformationClass ==
                   1064:                FilePositionInformation) {
                   1065: 
                   1066:         ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->
                   1067:             CurrentByteOffset = RtlConvertUlongToLargeInteger(0ul);
                   1068:         Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
                   1069: 
                   1070:     } else {
                   1071: 
                   1072:         status = STATUS_INVALID_PARAMETER;
                   1073: 
                   1074:     }
                   1075: 
                   1076:     Irp->IoStatus.Status = status;
                   1077:     ParDump(
                   1078:         PARIRPPATH,
                   1079:         ("PARALLEL: About to complete IRP in query infomration\n"
                   1080:          "Irp: %x status: %x Information: %x\n",
                   1081:          Irp,
                   1082:          Irp->IoStatus.Status,
                   1083:          Irp->IoStatus.Information)
                   1084:         );
                   1085:     IoCompleteRequest(
                   1086:         Irp,
                   1087:         IO_NO_INCREMENT
                   1088:         );
                   1089: 
                   1090:     return status;
                   1091: 
                   1092: }
                   1093: 
                   1094: NTSTATUS
                   1095: ParSetInformationFile(
                   1096:     IN PDEVICE_OBJECT DeviceObject,
                   1097:     IN PIRP Irp
                   1098:     )
                   1099: 
                   1100: /*++
                   1101: 
                   1102: Routine Description:
                   1103: 
                   1104:     This routine is used to set the end of file information on
                   1105:     the opened parallel port.  Any other file information request
                   1106:     is retured with an invalid parameter.
                   1107: 
                   1108:     This routine always ignores the actual end of file since
                   1109:     the query information code always returns an end of file of 0.
                   1110: 
                   1111: Arguments:
                   1112: 
                   1113:     DeviceObject - Pointer to the device object for this device
                   1114: 
                   1115:     Irp - Pointer to the IRP for the current request
                   1116: 
                   1117: Return Value:
                   1118: 
                   1119:     The function value is the final status of the call
                   1120: 
                   1121: --*/
                   1122: 
                   1123: {
                   1124: 
                   1125:     NTSTATUS status = STATUS_SUCCESS;
                   1126: 
                   1127:     UNREFERENCED_PARAMETER(DeviceObject);
                   1128: 
                   1129:     ParDump(
                   1130:         PARIRPPATH,
                   1131:         ("PARALLEL: In set information with IRP: %x\n",
                   1132:          Irp)
                   1133:         );
                   1134:     Irp->IoStatus.Information = 0L;
                   1135:     if (IoGetCurrentIrpStackLocation(Irp)->
                   1136:             Parameters.SetFile.FileInformationClass !=
                   1137:         FileEndOfFileInformation) {
                   1138: 
                   1139:         status = STATUS_INVALID_PARAMETER;
                   1140: 
                   1141:     }
                   1142: 
                   1143:     Irp->IoStatus.Status = status;
                   1144:     ParDump(
                   1145:         PARIRPPATH,
                   1146:         ("PARALLEL: About to complete IRP in set infomration\n"
                   1147:          "Irp: %x status: %x Information: %x\n",
                   1148:          Irp,
                   1149:          Irp->IoStatus.Status,
                   1150:          Irp->IoStatus.Information)
                   1151:         );
                   1152:     IoCompleteRequest(
                   1153:         Irp,
                   1154:         IO_NO_INCREMENT
                   1155:         );
                   1156: 
                   1157:     return status;
                   1158: 
                   1159: }
                   1160: 
                   1161: UCHAR
                   1162: ParManageIoDevice(
                   1163:      IN PPAR_DEVICE_EXTENSION Extension,
                   1164:      OUT PUCHAR Status,
                   1165:      OUT PUCHAR Control
                   1166:      )
                   1167: 
                   1168: /*++
                   1169: 
                   1170: Routine Description :
                   1171: 
                   1172:     This routine does the IoControl commands.
                   1173: 
                   1174: Arguments :
                   1175: 
                   1176:     Extension - The parallel device extension.
                   1177: 
                   1178:     Status - The pointer to the location to return the device status.
                   1179: 
                   1180:     Control - The pointer to the location to return the device control.
                   1181: 
                   1182: Return Value :
                   1183: 
                   1184:     NONE.
                   1185: 
                   1186: --*/
                   1187: {
                   1188:     PIO_STACK_LOCATION irpSp =
                   1189:         IoGetCurrentIrpStackLocation(Extension->CurrentOpIrp);
                   1190: 
                   1191:     if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
                   1192:         IOCTL_PAR_SET_INFORMATION) {
                   1193: 
                   1194:         PPAR_SET_INFORMATION irpBuffer =
                   1195:             Extension->CurrentOpIrp->AssociatedIrp.SystemBuffer;
                   1196: 
                   1197:         Extension->AutoFeed = (BOOLEAN)
                   1198:                               ((irpBuffer->Init & PARALLEL_AUTOFEED) != 0)?
                   1199:                               (TRUE):(FALSE);
                   1200: 
                   1201:         Extension->Initialized = FALSE;
                   1202:         *Status = ParInitializeDevice(Extension);
                   1203: 
                   1204:     } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
                   1205:                IOCTL_PAR_QUERY_INFORMATION) {
                   1206: 
                   1207:         *Status = GetStatus(Extension->Controller);
                   1208:         *Control = GetControl(Extension->Controller);
                   1209: 
                   1210:     }
                   1211: 
                   1212:     return *Status;
                   1213: 
                   1214: }
                   1215: 
                   1216: VOID
                   1217: ParNotInitError(
                   1218:     IN PPAR_DEVICE_EXTENSION Extension,
                   1219:     IN UCHAR deviceStatus
                   1220:     )
                   1221: 
                   1222: {
                   1223: 
                   1224:     PIRP irp = Extension->CurrentOpIrp;
                   1225: 
                   1226:     if (PAR_OFF_LINE(deviceStatus)) {
                   1227: 
                   1228:         irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
                   1229:         ParDump(
                   1230:             PARSTARTER,
                   1231:             ("PARALLEL: starter - off line\n"
                   1232:              "--------  STATUS/INFORMATON: %x/%x\n",
                   1233:              irp->IoStatus.Status,
                   1234:              irp->IoStatus.Information)
                   1235:             );
                   1236: 
                   1237:     } else if (PAR_NO_CABLE(deviceStatus)) {
                   1238: 
                   1239:         irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
                   1240:         ParDump(
                   1241:             PARSTARTER,
                   1242:             ("PARALLEL: starter - no cable - not connect status\n"
                   1243:              "--------  STATUS/INFORMATON: %x/%x\n",
                   1244:              irp->IoStatus.Status,
                   1245:              irp->IoStatus.Information)
                   1246:             );
                   1247: 
                   1248:     } else if (PAR_PAPER_EMPTY(deviceStatus)) {
                   1249: 
                   1250:         irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
                   1251:         ParDump(
                   1252:             PARSTARTER,
                   1253:             ("PARALLEL: starter - paper empty\n"
                   1254:              "--------  STATUS/INFORMATON: %x/%x\n",
                   1255:              irp->IoStatus.Status,
                   1256:              irp->IoStatus.Information)
                   1257:             );
                   1258: 
                   1259:     } else if (PAR_POWERED_OFF(deviceStatus)) {
                   1260: 
                   1261:         irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
                   1262:         ParDump(
                   1263:             PARSTARTER,
                   1264:             ("PARALLEL: starter - power off\n"
                   1265:              "--------  STATUS/INFORMATON: %x/%x\n",
                   1266:              irp->IoStatus.Status,
                   1267:              irp->IoStatus.Information)
                   1268:             );
                   1269: 
                   1270:     } else {
                   1271: 
                   1272:         irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
                   1273:         ParDump(
                   1274:             PARSTARTER,
                   1275:             ("PARALLEL: starter - not conn\n"
                   1276:              "--------  STATUS/INFORMATON: %x/%x\n",
                   1277:              irp->IoStatus.Status,
                   1278:              irp->IoStatus.Information)
                   1279:             );
                   1280: 
                   1281:     }
                   1282: 
                   1283: }
                   1284: 
                   1285: VOID
                   1286: ParStartIo(
                   1287:     IN PPAR_DEVICE_EXTENSION Extension
                   1288:     )
                   1289: 
                   1290: /*++
                   1291: 
                   1292: Routine Description:
                   1293: 
                   1294:     This routine starts an I/O operation for the driver and
                   1295:     then returns
                   1296: 
                   1297: Arguments:
                   1298: 
                   1299:     Extension - The parallel device extension
                   1300: 
                   1301: Return Value:
                   1302: 
                   1303:     None
                   1304: 
                   1305: --*/
                   1306: 
                   1307: {
                   1308:     PIRP irp = Extension->CurrentOpIrp;
                   1309:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
                   1310:     KIRQL cancelIrql;
                   1311: 
                   1312:     ParDump(
                   1313:         PARIRPPATH,
                   1314:         ("PARALLEL: In startio with IRP: %x\n",
                   1315:          irp)
                   1316:         );
                   1317:     if (irpSp->MajorFunction == IRP_MJ_WRITE) {
                   1318: 
                   1319:         UCHAR deviceStatus;
                   1320:         if (!Extension->Initialized) {
                   1321: 
                   1322:             deviceStatus = ParInitializeDevice(Extension);
                   1323: 
                   1324:         }
                   1325: 
                   1326:         if (!Extension->Initialized) {
                   1327: 
                   1328:             ParNotInitError(
                   1329:                 Extension,
                   1330:                 deviceStatus
                   1331:                 );
                   1332: 
                   1333:         } else {
                   1334: 
                   1335:             ParWriteOutData(
                   1336:                 Extension
                   1337:                 );
                   1338:             return;
                   1339: 
                   1340:         }
                   1341: 
                   1342:     } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
                   1343: 
                   1344:         UCHAR status;
                   1345:         UCHAR control;
                   1346: 
                   1347:         ParManageIoDevice(
                   1348:             Extension,
                   1349:             &status,
                   1350:             &control
                   1351:             );
                   1352: 
                   1353:         if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
                   1354:             IOCTL_PAR_SET_INFORMATION) {
                   1355: 
                   1356:             if (!Extension->Initialized) {
                   1357: 
                   1358:                 ParNotInitError(
                   1359:                     Extension,
                   1360:                     status
                   1361:                     );
                   1362: 
                   1363:             } else {
                   1364: 
                   1365:                 irp->IoStatus.Status = STATUS_SUCCESS;
                   1366: 
                   1367:             }
                   1368: 
                   1369:         } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
                   1370:             IOCTL_PAR_QUERY_INFORMATION) {
                   1371: 
                   1372:             PPAR_QUERY_INFORMATION irpBuffer = irp->AssociatedIrp.SystemBuffer;
                   1373: 
                   1374:             irp->IoStatus.Status = STATUS_SUCCESS;
                   1375: 
                   1376:             //
                   1377:             // Interpretating Status & Control
                   1378:             //
                   1379: 
                   1380:             irpBuffer->Status = 0x0;
                   1381: 
                   1382:             if (PAR_POWERED_OFF(status) ||
                   1383:                 PAR_NO_CABLE(status)) {
                   1384: 
                   1385:                 irpBuffer->Status =
                   1386:                     (UCHAR)(status | PARALLEL_POWER_OFF);
                   1387: 
                   1388:             } else if (PAR_PAPER_EMPTY(status)) {
                   1389: 
                   1390:                 irpBuffer->Status =
                   1391:                     (UCHAR)(irpBuffer->Status | PARALLEL_PAPER_EMPTY);
                   1392: 
                   1393:             } else if (PAR_OFF_LINE(status)) {
                   1394: 
                   1395:                 irpBuffer->Status =
                   1396:                     (UCHAR)(irpBuffer->Status | PARALLEL_OFF_LINE);
                   1397: 
                   1398:             } else if (PAR_NOT_CONNECTED(status)) {
                   1399: 
                   1400:                 irpBuffer->Status =
                   1401:                     (UCHAR)(irpBuffer->Status | PARALLEL_NOT_CONNECTED);
                   1402: 
                   1403:             }
                   1404: 
                   1405:             if (PAR_BUSY(status)) {
                   1406: 
                   1407:                 irpBuffer->Status =
                   1408:                     (UCHAR)(irpBuffer->Status | PARALLEL_BUSY);
                   1409: 
                   1410:             }
                   1411: 
                   1412:             if (PAR_SELECTED(status)) {
                   1413: 
                   1414:                 irpBuffer->Status =
                   1415:                     (UCHAR)(irpBuffer->Status | PARALLEL_SELECTED);
                   1416: 
                   1417:             }
                   1418: 
                   1419:             if (PAR_AUTOFEED(control)) {
                   1420: 
                   1421:                 irpBuffer->Status =
                   1422:                     (UCHAR)(irpBuffer->Status | PARALLEL_AUTOFEED);
                   1423: 
                   1424:             }
                   1425: 
                   1426:             irp->IoStatus.Information =
                   1427:                 sizeof( PAR_QUERY_INFORMATION );
                   1428: 
                   1429:         } else {
                   1430: 
                   1431:             PSERIAL_TIMEOUTS new = irp->AssociatedIrp.SystemBuffer;
                   1432: 
                   1433:             //
                   1434:             // The only other thing let through is setting
                   1435:             // the timer start.
                   1436:             //
                   1437: 
                   1438:             Extension->TimerStart = new->WriteTotalTimeoutConstant / 1000;
                   1439:             irp->IoStatus.Status = STATUS_SUCCESS;
                   1440: 
                   1441:         }
                   1442: 
                   1443:     }
                   1444: 
                   1445:     ParDump(
                   1446:         PARIRPPATH,
                   1447:         ("PARALLEL: About to complete IRP in startio\n"
                   1448:          "Irp: %x status: %x Information: %x\n",
                   1449:          irp,
                   1450:          irp->IoStatus.Status,
                   1451:          irp->IoStatus.Information)
                   1452:         );
                   1453: 
                   1454:     IoAcquireCancelSpinLock(&cancelIrql);
                   1455:     Extension->CurrentOpIrp = NULL;
                   1456:     IoReleaseCancelSpinLock(cancelIrql);
                   1457: 
                   1458:     IoCompleteRequest(
                   1459:         irp,
                   1460:         IO_NO_INCREMENT
                   1461:         );
                   1462: 
                   1463:     return;
                   1464: 
                   1465: }
                   1466: 
                   1467: VOID
                   1468: ParCancelRequest(
                   1469:     PDEVICE_OBJECT DeviceObject,
                   1470:     PIRP Irp
                   1471:     )
                   1472: 
                   1473: /*++
                   1474: 
                   1475: Routine Description:
                   1476: 
                   1477:     This routine is used to cancel any request in the parallel driver.
                   1478: 
                   1479: Arguments:
                   1480: 
                   1481:     DeviceObject - Pointer to the device object for this device
                   1482: 
                   1483:     Irp - Pointer to the IRP to be canceled.
                   1484: 
                   1485: Return Value:
                   1486: 
                   1487:     None.
                   1488: 
                   1489: --*/
                   1490: 
                   1491: {
                   1492: 
                   1493:     //
                   1494:     // The only reason that this irp can be on the queue is
                   1495:     // if it's not the current irp.  Pull it off the queue
                   1496:     // and complete it as canceled.
                   1497:     //
                   1498: 
                   1499:     ASSERT(!IsListEmpty(&Irp->Tail.Overlay.ListEntry));
                   1500: 
                   1501:     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
                   1502:     IoReleaseCancelSpinLock(Irp->CancelIrql);
                   1503:     Irp->IoStatus.Status = STATUS_CANCELLED;
                   1504:     Irp->IoStatus.Information = 0;
                   1505:     ParDump(
                   1506:         PARIRPPATH,
                   1507:         ("PARALLEL: About to complete IRP in cancel routine\n"
                   1508:          "Irp: %x status: %x Information: %x\n",
                   1509:          Irp,
                   1510:          Irp->IoStatus.Status,
                   1511:          Irp->IoStatus.Information)
                   1512:         );
                   1513:     IoCompleteRequest(
                   1514:         Irp,
                   1515:         IO_NO_INCREMENT
                   1516:         );
                   1517: 
                   1518: }
                   1519: 
                   1520: VOID
                   1521: ParallelThread(
                   1522:     IN PVOID Context
                   1523:     )
                   1524: 
                   1525: {
                   1526: 
                   1527:     PPAR_DEVICE_EXTENSION extension = Context;
                   1528:     KIRQL oldIrql;
                   1529: 
                   1530:     //
                   1531:     // Lower ourselves down just at tad so that we compete a
                   1532:     // little less.
                   1533:     //
                   1534: 
                   1535:     KeSetBasePriorityThread(
                   1536:         KeGetCurrentThread(),
                   1537:         -1
                   1538:         );
                   1539: 
                   1540:     do {
                   1541: 
                   1542: 
                   1543:         //
                   1544:         // Wait for a request from the dispatch routines.
                   1545:         // KeWaitForSingleObject won't return error here - this thread
                   1546:         // isn't alertable and won't take APCs, and we're not passing in
                   1547:         // a timeout.
                   1548:         //
                   1549: 
                   1550:         ParDump(
                   1551:             PARTHREAD,
                   1552:             ("PARALLEL: semaphore state before wait - %d\n",
                   1553:              extension->RequestSemaphore.Header.SignalState)
                   1554:             );
                   1555:         KeWaitForSingleObject(
                   1556:             &extension->RequestSemaphore,
                   1557:             UserRequest,
                   1558:             KernelMode,
                   1559:             FALSE,
                   1560:             NULL
                   1561:             );
                   1562:         ParDump(
                   1563:             PARTHREAD,
                   1564:             ("PARALLEL: semaphore state after wait - %d\n",
                   1565:              extension->RequestSemaphore.Header.SignalState)
                   1566:             );
                   1567: 
                   1568:         if ( extension->TimeToTerminateThread ) {
                   1569: 
                   1570:             ParDump(
                   1571:                 PARCONFIG,
                   1572:                 ("PARALLEL: Thread asked to kill itself\n")
                   1573:                 );
                   1574: 
                   1575:             PsTerminateSystemThread( STATUS_SUCCESS );
                   1576:         }
                   1577: 
                   1578:         //
                   1579:         // While we are manipulating the queue we capture the
                   1580:         // cancel spin lock.
                   1581:         //
                   1582: 
                   1583:         IoAcquireCancelSpinLock(&oldIrql);
                   1584: 
                   1585:         ASSERT(!extension->CurrentOpIrp);
                   1586:         while (!IsListEmpty(&extension->WorkQueue)) {
                   1587: 
                   1588:             PLIST_ENTRY headOfList;
                   1589:             PIRP currentIrp;
                   1590: 
                   1591:             headOfList = RemoveHeadList(&extension->WorkQueue);
                   1592:             currentIrp = CONTAINING_RECORD(
                   1593:                              headOfList,
                   1594:                              IRP,
                   1595:                              Tail.Overlay.ListEntry
                   1596:                              );
                   1597: 
                   1598:             IoSetCancelRoutine(
                   1599:                 currentIrp,
                   1600:                 NULL
                   1601:                 );
                   1602: 
                   1603:             extension->CurrentOpIrp = currentIrp;
                   1604:             IoReleaseCancelSpinLock(oldIrql);
                   1605: 
                   1606:             //
                   1607:             // Do the Io.
                   1608:             //
                   1609: 
                   1610:             ParStartIo(
                   1611:                 extension
                   1612:                 );
                   1613: 
                   1614:             IoAcquireCancelSpinLock(&oldIrql);
                   1615: 
                   1616:         }
                   1617: 
                   1618:         IoReleaseCancelSpinLock(oldIrql);
                   1619: 
                   1620:     } while (TRUE);
                   1621: 
                   1622: }
                   1623: VOID
                   1624: ParWriteOutData(
                   1625:     PPAR_DEVICE_EXTENSION Extension
                   1626:     )
                   1627: 
                   1628: {
                   1629: 
                   1630:     PIRP irp = Extension->CurrentOpIrp;
                   1631:     KIRQL cancelIrql;
                   1632:     UCHAR deviceStatus;
                   1633:     LONG bytesAtATime;
                   1634:     KIRQL oldIrql;
                   1635:     ULONG timerStart = Extension->TimerStart;
                   1636:     LONG countDown = (LONG)timerStart;
                   1637:     UCHAR oldControl = GetControl(Extension->Controller);
                   1638:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
                   1639:     ULONG bytesToWrite = irpSp->Parameters.Write.Length;
                   1640:     PUCHAR irpBuffer = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
                   1641:     LARGE_INTEGER startOfSpin;
                   1642:     LARGE_INTEGER nextQuery;
                   1643:     LARGE_INTEGER difference;
                   1644:     BOOLEAN doDelays;
                   1645: 
                   1646:     ParDump(
                   1647:         PARTHREAD,
                   1648:         ("PARALLEL: timerStart is: %d\n",
                   1649:          timerStart)
                   1650:         );
                   1651: PushSomeBytes:;
                   1652: 
                   1653:     //
                   1654:     // While we are strobing data we don't want to get context
                   1655:     // switched away.  Raise up to dispatch level to prevent that.
                   1656:     //
                   1657:     // The reason we can't afford the context switch is that
                   1658:     // the device can't have the data strobe line on for more
                   1659:     // than 500 microseconds.
                   1660:     //
                   1661:     //
                   1662:     // We never want to be at raised irql form more than
                   1663:     // 200 microseconds, so we will do no more than 100
                   1664:     // bytes at a time.
                   1665:     //
                   1666: 
                   1667:     KeRaiseIrql(
                   1668:         DISPATCH_LEVEL,
                   1669:         &oldIrql
                   1670:         );
                   1671:     StoreControl(
                   1672:         Extension->Controller,
                   1673:         (UCHAR)(oldControl & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR))
                   1674:         );
                   1675: 
                   1676:     for (
                   1677:         bytesAtATime = 100;
                   1678:         bytesAtATime && bytesToWrite;
                   1679:         bytesAtATime--
                   1680:         ) {
                   1681: 
                   1682:         deviceStatus = GetStatus(Extension->Controller);
                   1683: 
                   1684:         if (PAR_ONLINE(deviceStatus)) {
                   1685: 
                   1686:             //
                   1687:             // Anytime we write out a character we will restart
                   1688:             // the count down timer.
                   1689:             //
                   1690: 
                   1691:             countDown = timerStart;
                   1692:             WRITE_PORT_UCHAR(
                   1693:                 Extension->Controller+PARALLEL_DATA_OFFSET,
                   1694:                 (UCHAR)*irpBuffer
                   1695:                 );
                   1696:             KeStallExecutionProcessor((ULONG)1);
                   1697:             StoreControl(
                   1698:                 Extension->Controller,
                   1699:                 (UCHAR)((oldControl | PAR_CONTROL_STROBE) & ~PAR_CONTROL_DIR)
                   1700:                 );
                   1701:             KeStallExecutionProcessor((ULONG)1);
                   1702:             StoreControl(
                   1703:                 Extension->Controller,
                   1704:                 (UCHAR)(oldControl & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR))
                   1705:                 );
                   1706:             KeStallExecutionProcessor((ULONG)1);
                   1707:             irpBuffer++;
                   1708:             bytesToWrite--;
                   1709: 
                   1710:         } else {
                   1711: 
                   1712:             ParDump(
                   1713:                 PARPUSHER,
                   1714:                 ("PARALLEL: Initiate IO - device is not on line, status: %x\n",
                   1715:                  deviceStatus)
                   1716:                 );
                   1717: 
                   1718:             break;
                   1719: 
                   1720:         }
                   1721: 
                   1722:     }
                   1723: 
                   1724:     //
                   1725:     // Turn the line back to "input".
                   1726:     //
                   1727:     StoreControl(
                   1728:         Extension->Controller,
                   1729:         (UCHAR)(oldControl & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR))
                   1730:         );
                   1731:     KeStallExecutionProcessor((ULONG)1);
                   1732: 
                   1733:     //
                   1734:     // Restore to "original" value.  We don't care what it was.
                   1735:     //
                   1736: 
                   1737:     StoreControl(
                   1738:         Extension->Controller,
                   1739:         oldControl
                   1740:         );
                   1741: 
                   1742:     KeLowerIrql(oldIrql);
                   1743: 
                   1744:     //
                   1745:     // Check to see if the io is done.  If it is then call the
                   1746:     // code to complete the request.
                   1747:     //
                   1748: 
                   1749:     if (!bytesToWrite) {
                   1750: 
                   1751:         irp->IoStatus.Status = STATUS_SUCCESS;
                   1752:         irp->IoStatus.Information = irpSp->Parameters.Write.Length;
                   1753: 
                   1754:         ParDump(
                   1755:             PARIRPPATH,
                   1756:             ("PARALLEL: About to complete IRP in pusher - wrote ok\n"
                   1757:              "irp: %x status: %x Information: %x\n",
                   1758:              irp,
                   1759:              irp->IoStatus.Status,
                   1760:              irp->IoStatus.Information)
                   1761:             );
                   1762:         IoAcquireCancelSpinLock(&cancelIrql);
                   1763:         Extension->CurrentOpIrp = NULL;
                   1764:         IoReleaseCancelSpinLock(cancelIrql);
                   1765:         IoCompleteRequest(
                   1766:             irp,
                   1767:             IO_PARALLEL_INCREMENT
                   1768:             );
                   1769:         return;
                   1770: 
                   1771:         //
                   1772:         // See if the IO has been canceled.  The cancel routine
                   1773:         // has been removed already (when this became the
                   1774:         // current irp).  Simply check the bit.  We don't even
                   1775:         // need to capture the lock.   If we miss a round
                   1776:         // it won't be that bad.
                   1777:         //
                   1778: 
                   1779:     } else if (irp->Cancel) {
                   1780: 
                   1781:         irp->IoStatus.Status = STATUS_CANCELLED;
                   1782:         irp->IoStatus.Information = 0;
                   1783: 
                   1784:         ParDump(
                   1785:             PARIRPPATH,
                   1786:             ("PARALLEL: About to complete IRP in pusher - cancelled\n"
                   1787:              "irp: %x status: %x Information: %x\n",
                   1788:              irp,
                   1789:              irp->IoStatus.Status,
                   1790:              irp->IoStatus.Information)
                   1791:             );
                   1792:         IoAcquireCancelSpinLock(&cancelIrql);
                   1793:         Extension->CurrentOpIrp = NULL;
                   1794:         IoReleaseCancelSpinLock(cancelIrql);
                   1795:         IoCompleteRequest(
                   1796:             irp,
                   1797:             IO_NO_INCREMENT
                   1798:             );
                   1799: 
                   1800:         return;
                   1801: 
                   1802: 
                   1803:         //
                   1804:         // We've taken care of the reasons that the irp "itself"
                   1805:         // might want to be completed.
                   1806:         // printer to see if it is in a state that might
                   1807:         // cause us to complete the irp.
                   1808:         //
                   1809:     } else {
                   1810: 
                   1811:         //
                   1812:         // First let's check if the device status is
                   1813:         // ok and online.  If it is then simply go back
                   1814:         // to the byte pusher.
                   1815:         //
                   1816: 
                   1817:         if (PAR_OK(deviceStatus) && PAR_ONLINE(deviceStatus)) {
                   1818: 
                   1819:             goto PushSomeBytes;
                   1820: 
                   1821:         }
                   1822: 
                   1823:         //
                   1824:         // Perhaps the operator took the device off line,
                   1825:         // or forgot to put in enough paper.  If so, then
                   1826:         // let's hang out here for the until the timeout
                   1827:         // period has expired waiting for them to make things
                   1828:         // all better.
                   1829:         //
                   1830: 
                   1831:         if (PAR_PAPER_EMPTY(deviceStatus) ||
                   1832:             PAR_OFF_LINE(deviceStatus)) {
                   1833: 
                   1834:             if (countDown > 0) {
                   1835: 
                   1836:                 //
                   1837:                 // We'll wait 1 second increments.
                   1838:                 //
                   1839: 
                   1840:                 ParDump(
                   1841:                     PARTHREAD,
                   1842:                     ("PARALLEL: decrementing countdown for pe/ol\n"
                   1843:                      "          countDown: %d status: %x\n",
                   1844:                      countDown,deviceStatus)
                   1845:                     );
                   1846:                 countDown--;
                   1847:                 KeDelayExecutionThread(
                   1848:                     KernelMode,
                   1849:                     FALSE,
                   1850:                     &Extension->OneSecond
                   1851:                     );
                   1852:                 goto PushSomeBytes;
                   1853: 
                   1854:             } else {
                   1855: 
                   1856:                 //
                   1857:                 // Timer has expired.  Complete the request.
                   1858:                 //
                   1859: 
                   1860:                 irp->IoStatus.Information =
                   1861:                     irpSp->Parameters.Write.Length - bytesToWrite;
                   1862:                 if (PAR_OFF_LINE(deviceStatus)) {
                   1863: 
                   1864:                     irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
                   1865:                     ParDump(
                   1866:                         PARIRPPATH,
                   1867:                         ("PARALLEL: About to complete IRP in pusher - offline\n"
                   1868:                          "irp: %x status: %x Information: %x\n",
                   1869:                          irp,
                   1870:                          irp->IoStatus.Status,
                   1871:                          irp->IoStatus.Information)
                   1872:                         );
                   1873: 
                   1874:                 } else {
                   1875: 
                   1876:                     irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
                   1877:                     ParDump(
                   1878:                         PARIRPPATH,
                   1879:                         ("PARALLEL: About to complete IRP in pusher - PE\n"
                   1880:                          "irp: %x status: %x Information: %x\n",
                   1881:                          irp,
                   1882:                          irp->IoStatus.Status,
                   1883:                          irp->IoStatus.Information)
                   1884:                         );
                   1885: 
                   1886:                 }
                   1887: 
                   1888:                 IoAcquireCancelSpinLock(&cancelIrql);
                   1889:                 Extension->CurrentOpIrp = NULL;
                   1890:                 IoReleaseCancelSpinLock(cancelIrql);
                   1891:                 IoCompleteRequest(
                   1892:                     irp,
                   1893:                     IO_PARALLEL_INCREMENT
                   1894:                     );
                   1895:                 return;
                   1896: 
                   1897:             }
                   1898: 
                   1899: 
                   1900:         } else if (PAR_POWERED_OFF(deviceStatus) ||
                   1901:                    PAR_NOT_CONNECTED(deviceStatus) ||
                   1902:                    PAR_NO_CABLE(deviceStatus)) {
                   1903: 
                   1904:             //
                   1905:             // Wimper, wimper, something "bad" happened.  Is what
                   1906:             // happened to the printer (power off, not connected, or
                   1907:             // the cable being pulled) something that will require us
                   1908:             // to reinitialize the printer?  If we need to
                   1909:             // reinitialize the printer then we should complete
                   1910:             // this IO so that the driving application can
                   1911:             // choose what is the best thing to do about it's
                   1912:             // io.
                   1913:             //
                   1914: 
                   1915:             irp->IoStatus.Information = 0;
                   1916:             Extension->Initialized = FALSE;
                   1917: 
                   1918:             if (PAR_POWERED_OFF(deviceStatus)) {
                   1919: 
                   1920:                 irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
                   1921:                 ParDump(
                   1922:                     PARIRPPATH,
                   1923:                     ("PARALLEL: About to complete IRP in pusher - OFF\n"
                   1924:                      "irp: %x status: %x Information: %x\n",
                   1925:                      irp,
                   1926:                      irp->IoStatus.Status,
                   1927:                      irp->IoStatus.Information)
                   1928:                     );
                   1929: 
                   1930:             } else if (PAR_NOT_CONNECTED(deviceStatus) ||
                   1931:                        PAR_NO_CABLE(deviceStatus)) {
                   1932: 
                   1933:                 irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
                   1934:                 ParDump(
                   1935:                     PARIRPPATH,
                   1936:                     ("PARALLEL: About to complete IRP in pusher - NOT CONN\n"
                   1937:                      "irp: %x status: %x Information: %x\n",
                   1938:                      irp,
                   1939:                      irp->IoStatus.Status,
                   1940:                      irp->IoStatus.Information)
                   1941:                     );
                   1942: 
                   1943:             }
                   1944: 
                   1945:             IoAcquireCancelSpinLock(&cancelIrql);
                   1946:             Extension->CurrentOpIrp = NULL;
                   1947:             IoReleaseCancelSpinLock(cancelIrql);
                   1948:             IoCompleteRequest(
                   1949:                 irp,
                   1950:                 IO_PARALLEL_INCREMENT
                   1951:                 );
                   1952:             return;
                   1953: 
                   1954:         }
                   1955: 
                   1956:         //
                   1957:         // The device could simply be busy at this point.  Simply spin
                   1958:         // here waiting for the device to be in a state that we
                   1959:         // care about.
                   1960:         //
                   1961:         // As we spin, get the system ticks.  Every time that it looks
                   1962:         // like a second has passed, decrement the countdown.  If
                   1963:         // it ever goes to zero, then timeout the request.
                   1964:         //
                   1965: 
                   1966:         KeQueryTickCount(&startOfSpin);
                   1967:         doDelays = FALSE;
                   1968:         do {
                   1969: 
                   1970:             //
                   1971:             // After about a second of spinning, let the rest of the
                   1972:             // machine have time for a second.
                   1973:             //
                   1974: 
                   1975:             if (doDelays) {
                   1976: 
                   1977:                 difference = RtlLargeIntegerNegate(Extension->AbsoluteOneSecond);
                   1978:                 KeDelayExecutionThread(
                   1979:                     KernelMode,
                   1980:                     FALSE,
                   1981:                     &difference
                   1982:                     );
                   1983:                 ParDump(
                   1984:                     PARINITDEV,
                   1985:                     ("PARALLEL: Did delay thread of one second\n")
                   1986:                     );
                   1987:                 countDown--;
                   1988: 
                   1989:             } else {
                   1990: 
                   1991:                 KeQueryTickCount(&nextQuery);
                   1992: 
                   1993:                 difference = RtlLargeIntegerSubtract(
                   1994:                                  nextQuery,
                   1995:                                  startOfSpin
                   1996:                                  );
                   1997: 
                   1998:                 if (RtlLargeIntegerGreaterThanOrEqualTo(
                   1999:                         RtlExtendedIntegerMultiply(
                   2000:                             difference,
                   2001:                             (LONG)KeQueryTimeIncrement()
                   2002:                             ),
                   2003:                         Extension->AbsoluteOneSecond
                   2004:                         )) {
                   2005: 
                   2006:                     ParDump(
                   2007:                         PARTHREAD,
                   2008:                         ("PARALLEL: Countdown: %d - device Status: %x lowpart: %x highpart: %x\n",
                   2009:                          countDown,deviceStatus,difference.LowPart,difference.HighPart)
                   2010:                         );
                   2011:                     countDown--;
                   2012:                     doDelays = TRUE;
                   2013: 
                   2014:                 }
                   2015: 
                   2016:             }
                   2017: 
                   2018:             if (countDown <= 0) {
                   2019:                 irp->IoStatus.Status = STATUS_DEVICE_BUSY;
                   2020:                 irp->IoStatus.Information =
                   2021:                     irpSp->Parameters.Write.Length - bytesToWrite;
                   2022: 
                   2023:                 ParDump(
                   2024:                     PARIRPPATH,
                   2025:                     ("PARALLEL: About to complete IRP in pusher - T-OUT\n"
                   2026:                      "irp: %x status: %x Information: %x\n",
                   2027:                      irp,
                   2028:                      irp->IoStatus.Status,
                   2029:                      irp->IoStatus.Information)
                   2030:                     );
                   2031:                 IoAcquireCancelSpinLock(&cancelIrql);
                   2032:                 Extension->CurrentOpIrp = NULL;
                   2033:                 IoReleaseCancelSpinLock(cancelIrql);
                   2034:                 IoCompleteRequest(
                   2035:                     irp,
                   2036:                     IO_PARALLEL_INCREMENT
                   2037:                     );
                   2038: 
                   2039:                 return;
                   2040: 
                   2041:             }
                   2042: 
                   2043:             deviceStatus = GetStatus(Extension->Controller);
                   2044: 
                   2045:         } while ((!PAR_ONLINE(deviceStatus)) &&
                   2046:                  (!PAR_PAPER_EMPTY(deviceStatus)) &&
                   2047:                  (!PAR_POWERED_OFF(deviceStatus)) &&
                   2048:                  (!PAR_NOT_CONNECTED(deviceStatus)) &&
                   2049:                  (!PAR_NO_CABLE(deviceStatus)) &&
                   2050:                   !irp->Cancel);
                   2051: 
                   2052:         if (countDown != (LONG)timerStart) {
                   2053: 
                   2054:             ParDump(
                   2055:                 PARTHREAD,
                   2056:                 ("PARALLEL: Leaving busy loop - countdown %d status %x\n",
                   2057:                  countDown,deviceStatus)
                   2058:                 );
                   2059: 
                   2060:         }
                   2061:         goto PushSomeBytes;
                   2062: 
                   2063:     }
                   2064: 
                   2065:     return;
                   2066: 
                   2067: }
                   2068: 

unix.superglobalmegacorp.com

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