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