Annotation of ntddk/src/comm/serial/write.c, revision 1.1

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     write.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains the code that is very specific to write
        !            12:     operations in the serial driver
        !            13: 
        !            14: Author:
        !            15: 
        !            16:     Anthony V. Ercolano 26-Sep-1991
        !            17: 
        !            18: Environment:
        !            19: 
        !            20:     Kernel mode
        !            21: 
        !            22: Revision History :
        !            23: 
        !            24: --*/
        !            25: 
        !            26: #include <stddef.h>
        !            27: #include "ntddk.h"
        !            28: #include "ntddser.h"
        !            29: #include "serial.h"
        !            30: #include "serialp.h"
        !            31: 
        !            32: 
        !            33: 
        !            34: BOOLEAN
        !            35: SerialGiveWriteToIsr(
        !            36:     IN PVOID Context
        !            37:     );
        !            38: 
        !            39: VOID
        !            40: SerialCancelCurrentWrite(
        !            41:     PDEVICE_OBJECT DeviceObject,
        !            42:     PIRP Irp
        !            43:     );
        !            44: 
        !            45: BOOLEAN
        !            46: SerialGrabWriteFromIsr(
        !            47:     IN PVOID Context
        !            48:     );
        !            49: 
        !            50: BOOLEAN
        !            51: SerialGrabXoffFromIsr(
        !            52:     IN PVOID Context
        !            53:     );
        !            54: 
        !            55: VOID
        !            56: SerialCancelCurrentXoff(
        !            57:     PDEVICE_OBJECT DeviceObject,
        !            58:     PIRP Irp
        !            59:     );
        !            60: 
        !            61: BOOLEAN
        !            62: SerialGiveXoffToIsr(
        !            63:     IN PVOID Context
        !            64:     );
        !            65: 
        !            66: 
        !            67: 
        !            68: NTSTATUS
        !            69: SerialWrite(
        !            70:     IN PDEVICE_OBJECT DeviceObject,
        !            71:     IN PIRP Irp
        !            72:     )
        !            73: 
        !            74: /*++
        !            75: 
        !            76: Routine Description:
        !            77: 
        !            78:     This is the dispatch routine for write.  It validates the parameters
        !            79:     for the write request and if all is ok then it places the request
        !            80:     on the work queue.
        !            81: 
        !            82: Arguments:
        !            83: 
        !            84:     DeviceObject - Pointer to the device object for this device
        !            85: 
        !            86:     Irp - Pointer to the IRP for the current request
        !            87: 
        !            88: Return Value:
        !            89: 
        !            90:     If the io is zero length then it will return STATUS_SUCCESS,
        !            91:     otherwise this routine will return STATUS_PENDING.
        !            92: 
        !            93: --*/
        !            94: 
        !            95: {
        !            96: 
        !            97:     PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
        !            98: 
        !            99:     SerialDump(
        !           100:         SERIRPPATH,
        !           101:         ("SERIAL: Dispatch entry for: %x\n",Irp)
        !           102:         );
        !           103:     if (SerialCompleteIfError(
        !           104:             DeviceObject,
        !           105:             Irp
        !           106:             ) != STATUS_SUCCESS) {
        !           107: 
        !           108:         return STATUS_CANCELLED;
        !           109: 
        !           110:     }
        !           111: 
        !           112:     Irp->IoStatus.Information = 0L;
        !           113: 
        !           114:     //
        !           115:     // Quick check for a zero length write.  If it is zero length
        !           116:     // then we are already done!
        !           117:     //
        !           118: 
        !           119:     if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length) {
        !           120: 
        !           121:         //
        !           122:         // Well it looks like we actually have to do some
        !           123:         // work.  Put the write on the queue so that we can
        !           124:         // process it when our previous writes are done.
        !           125:         //
        !           126: 
        !           127:         return SerialStartOrQueue(
        !           128:                    Extension,
        !           129:                    Irp,
        !           130:                    &Extension->WriteQueue,
        !           131:                    &Extension->CurrentWriteIrp,
        !           132:                    SerialStartWrite
        !           133:                    );
        !           134: 
        !           135:     } else {
        !           136: 
        !           137:         Irp->IoStatus.Status = STATUS_SUCCESS;
        !           138:         SerialDump(
        !           139:             SERIRPPATH,
        !           140:             ("SERIAL: Complete Irp: %x\n",Irp)
        !           141:             );
        !           142:         IoCompleteRequest(
        !           143:             Irp,
        !           144:             0
        !           145:             );
        !           146: 
        !           147:         return STATUS_SUCCESS;
        !           148: 
        !           149:     }
        !           150: 
        !           151: }
        !           152: 
        !           153: NTSTATUS
        !           154: SerialStartWrite(
        !           155:     IN PSERIAL_DEVICE_EXTENSION Extension
        !           156:     )
        !           157: 
        !           158: /*++
        !           159: 
        !           160: Routine Description:
        !           161: 
        !           162:     This routine is used to start off any write.  It initializes
        !           163:     the Iostatus fields of the irp.  It will set up any timers
        !           164:     that are used to control the write.
        !           165: 
        !           166: Arguments:
        !           167: 
        !           168:     Extension - Points to the serial device extension
        !           169: 
        !           170: Return Value:
        !           171: 
        !           172:     This routine will return STATUS_PENDING for all writes
        !           173:     other than those that we find are cancelled.
        !           174: 
        !           175: --*/
        !           176: 
        !           177: {
        !           178: 
        !           179:     PIRP NewIrp;
        !           180:     KIRQL OldIrql;
        !           181:     LARGE_INTEGER TotalTime;
        !           182:     BOOLEAN UseATimer;
        !           183:     SERIAL_TIMEOUTS Timeouts;
        !           184:     BOOLEAN SetFirstStatus = FALSE;
        !           185:     NTSTATUS FirstStatus;
        !           186: 
        !           187:     do {
        !           188: 
        !           189:         //
        !           190:         // If there is an xoff counter then complete it.
        !           191:         //
        !           192: 
        !           193:         IoAcquireCancelSpinLock(&OldIrql);
        !           194: 
        !           195:         //
        !           196:         // We see if there is a actually an Xoff counter irp.
        !           197:         //
        !           198:         // If there is, we put the write irp back on the head
        !           199:         // of the write list.  We then kill the xoff counter.
        !           200:         // The xoff counter killing code will actually make the
        !           201:         // xoff counter back into the current write irp, and
        !           202:         // in the course of completing the xoff (which is now
        !           203:         // the current write) we will restart this irp.
        !           204:         //
        !           205: 
        !           206:         if (Extension->CurrentXoffIrp) {
        !           207: 
        !           208:             InsertHeadList(
        !           209:                 &Extension->WriteQueue,
        !           210:                 &Extension->CurrentWriteIrp->Tail.Overlay.ListEntry
        !           211:                 );
        !           212: 
        !           213:             if (!SetFirstStatus) {
        !           214: 
        !           215:                 IoMarkIrpPending(Extension->CurrentWriteIrp);
        !           216:                 SetFirstStatus = TRUE;
        !           217:                 FirstStatus = STATUS_PENDING;
        !           218: 
        !           219:             }
        !           220: 
        !           221:             if (SERIAL_REFERENCE_COUNT(Extension->CurrentXoffIrp)) {
        !           222: 
        !           223:                 //
        !           224:                 // The reference count is non-zero.  This implies that
        !           225:                 // the xoff irp has not made it through the completion
        !           226:                 // path yet.  We will increment the reference count
        !           227:                 // and attempt to complete it ourseleves.
        !           228:                 //
        !           229: 
        !           230:                 SERIAL_INC_REFERENCE(Extension->CurrentXoffIrp);
        !           231: 
        !           232:                 Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
        !           233: 
        !           234:                 //
        !           235:                 // The following call will actually release the
        !           236:                 // cancel spin lock.
        !           237:                 //
        !           238: 
        !           239:                 SerialTryToCompleteCurrent(
        !           240:                     Extension,
        !           241:                     SerialGrabXoffFromIsr,
        !           242:                     OldIrql,
        !           243:                     STATUS_SERIAL_MORE_WRITES,
        !           244:                     &Extension->CurrentWriteIrp,
        !           245:                     &Extension->WriteQueue,
        !           246:                     NULL,
        !           247:                     &Extension->XoffCountTimer,
        !           248:                     SerialStartWrite,
        !           249:                     SerialGetNextWrite
        !           250:                     );
        !           251: 
        !           252:                 return FirstStatus;
        !           253: 
        !           254:             } else {
        !           255: 
        !           256:                 //
        !           257:                 // The irp is well on its way to being finished.
        !           258:                 // We can let the regular completion code do the
        !           259:                 // work.  Just release the spin lock.
        !           260:                 //
        !           261: 
        !           262:                 IoReleaseCancelSpinLock(OldIrql);
        !           263: 
        !           264:                 return FirstStatus;
        !           265: 
        !           266:             }
        !           267: 
        !           268:         } else {
        !           269: 
        !           270:             IoReleaseCancelSpinLock(OldIrql);
        !           271: 
        !           272:         }
        !           273: 
        !           274:         UseATimer = FALSE;
        !           275: 
        !           276:         //
        !           277:         // Calculate the timeout value needed for the
        !           278:         // request.  Note that the values stored in the
        !           279:         // timeout record are in milliseconds.  Note that
        !           280:         // if the timeout values are zero then we won't start
        !           281:         // the timer.
        !           282:         //
        !           283: 
        !           284:         KeAcquireSpinLock(
        !           285:             &Extension->ControlLock,
        !           286:             &OldIrql
        !           287:             );
        !           288: 
        !           289:         Timeouts = Extension->Timeouts;
        !           290: 
        !           291:         KeReleaseSpinLock(
        !           292:             &Extension->ControlLock,
        !           293:             OldIrql
        !           294:             );
        !           295: 
        !           296:         if (Timeouts.WriteTotalTimeoutConstant ||
        !           297:             Timeouts.WriteTotalTimeoutMultiplier) {
        !           298: 
        !           299:             PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(
        !           300:                                            Extension->CurrentWriteIrp
        !           301:                                            );
        !           302:             UseATimer = TRUE;
        !           303: 
        !           304:             //
        !           305:             // We have some timer values to calculate.
        !           306:             //
        !           307:             // Take care, we might have an xoff counter masquerading
        !           308:             // as a write.
        !           309:             //
        !           310: 
        !           311:             TotalTime = RtlEnlargedUnsignedMultiply(
        !           312:                             (IrpSp->MajorFunction == IRP_MJ_WRITE)?
        !           313:                                 (IrpSp->Parameters.Write.Length):
        !           314:                                 (1),
        !           315:                             Timeouts.WriteTotalTimeoutMultiplier
        !           316:                             );
        !           317: 
        !           318:             TotalTime = RtlLargeIntegerAdd(
        !           319:                             TotalTime,
        !           320:                             RtlConvertUlongToLargeInteger(
        !           321:                                 Timeouts.WriteTotalTimeoutConstant
        !           322:                                 )
        !           323:                             );
        !           324: 
        !           325:             TotalTime = RtlExtendedIntegerMultiply(
        !           326:                             TotalTime,
        !           327:                             -10000
        !           328:                             );
        !           329: 
        !           330:         }
        !           331: 
        !           332:         //
        !           333:         // The irp may be going to the isr shortly.  Now
        !           334:         // is a good time to initialize its reference counts.
        !           335:         //
        !           336: 
        !           337:         SERIAL_INIT_REFERENCE(Extension->CurrentWriteIrp);
        !           338: 
        !           339:         //
        !           340:         // We need to see if this irp should be canceled.
        !           341:         //
        !           342: 
        !           343:         IoAcquireCancelSpinLock(&OldIrql);
        !           344:         if (Extension->CurrentWriteIrp->Cancel) {
        !           345: 
        !           346:             IoReleaseCancelSpinLock(OldIrql);
        !           347:             Extension->CurrentWriteIrp->IoStatus.Status = STATUS_CANCELLED;
        !           348: 
        !           349:             if (!SetFirstStatus) {
        !           350: 
        !           351:                 FirstStatus = STATUS_CANCELLED;
        !           352:                 SetFirstStatus = TRUE;
        !           353: 
        !           354:             }
        !           355: 
        !           356:         } else {
        !           357: 
        !           358:             if (!SetFirstStatus) {
        !           359: 
        !           360:                 //
        !           361:                 // If we haven't set our first status, then
        !           362:                 // this is the only irp that could have possibly
        !           363:                 // not been on the queue.  (It could have been
        !           364:                 // on the queue if this routine is being invoked
        !           365:                 // from the completion routine.)  Since this
        !           366:                 // irp might never have been on the queue we
        !           367:                 // should mark it as pending.
        !           368:                 //
        !           369: 
        !           370:                 IoMarkIrpPending(Extension->CurrentWriteIrp);
        !           371:                 SetFirstStatus = TRUE;
        !           372:                 FirstStatus = STATUS_PENDING;
        !           373: 
        !           374:             }
        !           375: 
        !           376:             //
        !           377:             // We give the irp to to the isr to write out.
        !           378:             // We set a cancel routine that knows how to
        !           379:             // grab the current write away from the isr.
        !           380:             //
        !           381:             // Since the cancel routine has an implicit reference
        !           382:             // to this irp up the reference count.
        !           383:             //
        !           384: 
        !           385:             IoSetCancelRoutine(
        !           386:                 Extension->CurrentWriteIrp,
        !           387:                 SerialCancelCurrentWrite
        !           388:                 );
        !           389: 
        !           390:             SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp);
        !           391: 
        !           392:             if (UseATimer) {
        !           393: 
        !           394:                 KeSetTimer(
        !           395:                     &Extension->WriteRequestTotalTimer,
        !           396:                     TotalTime,
        !           397:                     &Extension->TotalWriteTimeoutDpc
        !           398:                     );
        !           399: 
        !           400:                 //
        !           401:                 // This timer now has a reference to the irp.
        !           402:                 //
        !           403: 
        !           404:                 SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp);
        !           405:             }
        !           406: 
        !           407:             KeSynchronizeExecution(
        !           408:                 Extension->Interrupt,
        !           409:                 SerialGiveWriteToIsr,
        !           410:                 Extension
        !           411:                 );
        !           412: 
        !           413:             IoReleaseCancelSpinLock(OldIrql);
        !           414:             break;
        !           415: 
        !           416:         }
        !           417: 
        !           418:         //
        !           419:         // Well the write was canceled before we could start it up.
        !           420:         // Try to get another.
        !           421:         //
        !           422: 
        !           423:         SerialGetNextWrite(
        !           424:             &Extension->CurrentWriteIrp,
        !           425:             &Extension->WriteQueue,
        !           426:             &NewIrp,
        !           427:             TRUE
        !           428:             );
        !           429: 
        !           430:     } while (NewIrp);
        !           431: 
        !           432:     return FirstStatus;
        !           433: 
        !           434: }
        !           435: 
        !           436: VOID
        !           437: SerialGetNextWrite(
        !           438:     IN PIRP *CurrentOpIrp,
        !           439:     IN PLIST_ENTRY QueueToProcess,
        !           440:     IN PIRP *NewIrp,
        !           441:     IN BOOLEAN CompleteCurrent
        !           442:     )
        !           443: 
        !           444: /*++
        !           445: 
        !           446: Routine Description:
        !           447: 
        !           448:     This routine completes the old write as well as getting
        !           449:     a pointer to the next write.
        !           450: 
        !           451:     The reason that we have have pointers to the current write
        !           452:     queue as well as the current write irp is so that this
        !           453:     routine may be used in the common completion code for
        !           454:     read and write.
        !           455: 
        !           456: Arguments:
        !           457: 
        !           458:     CurrentOpIrp - Pointer to the pointer that points to the
        !           459:                    current write irp.
        !           460: 
        !           461:     QueueToProcess - Pointer to the write queue.
        !           462: 
        !           463:     NewIrp - A pointer to a pointer to the irp that will be the
        !           464:              current irp.  Note that this could end up pointing
        !           465:              to a null pointer.  This does NOT necessaryly mean
        !           466:              that there is no current write.  What could occur
        !           467:              is that while the cancel lock is held the write
        !           468:              queue ended up being empty, but as soon as we release
        !           469:              the cancel spin lock a new irp came in from
        !           470:              SerialStartWrite.
        !           471: 
        !           472:     CompleteCurrent - Flag indicates whether the CurrentOpIrp should
        !           473:                       be completed.
        !           474: 
        !           475: Return Value:
        !           476: 
        !           477:     None.
        !           478: 
        !           479: --*/
        !           480: 
        !           481: {
        !           482: 
        !           483:     PSERIAL_DEVICE_EXTENSION Extension = CONTAINING_RECORD(
        !           484:                                              QueueToProcess,
        !           485:                                              SERIAL_DEVICE_EXTENSION,
        !           486:                                              WriteQueue
        !           487:                                              );
        !           488: 
        !           489:     do {
        !           490: 
        !           491: 
        !           492:         //
        !           493:         // We could be completing a flush.
        !           494:         //
        !           495: 
        !           496:         if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction
        !           497:             == IRP_MJ_WRITE) {
        !           498: 
        !           499:             KIRQL OldIrql;
        !           500: 
        !           501:             ASSERT(Extension->TotalCharsQueued >=
        !           502:                    (IoGetCurrentIrpStackLocation(*CurrentOpIrp)
        !           503:                     ->Parameters.Write.Length));
        !           504: 
        !           505:             IoAcquireCancelSpinLock(&OldIrql);
        !           506:             Extension->TotalCharsQueued -=
        !           507:                 IoGetCurrentIrpStackLocation(*CurrentOpIrp)
        !           508:                 ->Parameters.Write.Length;
        !           509:             IoReleaseCancelSpinLock(OldIrql);
        !           510: 
        !           511:         } else if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction
        !           512:                    == IRP_MJ_DEVICE_CONTROL) {
        !           513: 
        !           514:             KIRQL OldIrql;
        !           515: 
        !           516:             IoAcquireCancelSpinLock(&OldIrql);
        !           517: 
        !           518:             //
        !           519:             // If CurrentXoffIrp is not equal to null, this
        !           520:             // implies that this is the "second" time around
        !           521:             // for this irp, which implies that we should really
        !           522:             // be completing it this time.
        !           523:             //
        !           524: 
        !           525:             if (Extension->CurrentXoffIrp) {
        !           526: 
        !           527:                 Extension->CurrentXoffIrp = NULL;
        !           528:                 IoReleaseCancelSpinLock(OldIrql);
        !           529: 
        !           530:             } else {
        !           531: 
        !           532:                 PIRP Irp = *CurrentOpIrp;
        !           533: 
        !           534:                 PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer;
        !           535: 
        !           536:                 //
        !           537:                 // We absolutely shouldn't have a cancel routine
        !           538:                 // at this point.
        !           539:                 //
        !           540: 
        !           541:                 ASSERT(!Irp->CancelRoutine);
        !           542: 
        !           543:                 //
        !           544:                 // This could only be a xoff counter masquerading as
        !           545:                 // a write irp.
        !           546:                 //
        !           547: 
        !           548:                 Extension->TotalCharsQueued--;
        !           549: 
        !           550:                 //
        !           551:                 // Check to see of the xoff irp has been set with success.
        !           552:                 // This means that the write completed normally.  If that
        !           553:                 // is the case, and it hasn't been set to cancel in the
        !           554:                 // meanwhile, then go on and make it the CurrentXoffIrp.
        !           555:                 //
        !           556: 
        !           557:                 if (Irp->IoStatus.Status != STATUS_SUCCESS) {
        !           558: 
        !           559:                     //
        !           560:                     // Oh well, we can just finish it off.
        !           561:                     //
        !           562:                     NOTHING;
        !           563: 
        !           564:                 } else if (Irp->Cancel) {
        !           565: 
        !           566:                     Irp->IoStatus.Status = STATUS_CANCELLED;
        !           567: 
        !           568:                 } else {
        !           569: 
        !           570:                     //
        !           571:                     // Give it a new cancel routine, and increment the
        !           572:                     // reference count because the cancel routine has
        !           573:                     // a reference to it.
        !           574:                     //
        !           575: 
        !           576:                     IoSetCancelRoutine(
        !           577:                         Irp,
        !           578:                         SerialCancelCurrentXoff
        !           579:                         );
        !           580: 
        !           581:                     SERIAL_INC_REFERENCE(Irp);
        !           582: 
        !           583:                     //
        !           584:                     // We don't want to complete the current irp now.  This
        !           585:                     // will now get completed by the Xoff counter code.
        !           586:                     //
        !           587: 
        !           588:                     CompleteCurrent = FALSE;
        !           589: 
        !           590:                     //
        !           591:                     // Give the counter to the isr.
        !           592:                     //
        !           593: 
        !           594:                     Extension->CurrentXoffIrp = Irp;
        !           595:                     KeSynchronizeExecution(
        !           596:                         Extension->Interrupt,
        !           597:                         SerialGiveXoffToIsr,
        !           598:                         Extension
        !           599:                         );
        !           600: 
        !           601:                     //
        !           602:                     // Start the timer for the counter and increment
        !           603:                     // the reference count since the timer has a
        !           604:                     // reference to the irp.
        !           605:                     //
        !           606: 
        !           607:                     if (Xc->Timeout) {
        !           608: 
        !           609:                         KeSetTimer(
        !           610:                             &Extension->XoffCountTimer,
        !           611:                             RtlLargeIntegerNegate(
        !           612:                                 RtlEnlargedUnsignedMultiply(
        !           613:                                     10000,
        !           614:                                     Xc->Timeout
        !           615:                                     )
        !           616:                                 ),
        !           617:                             &Extension->XoffCountTimeoutDpc
        !           618:                             );
        !           619: 
        !           620:                         SERIAL_INC_REFERENCE(Irp);
        !           621: 
        !           622:                     }
        !           623: 
        !           624:                 }
        !           625: 
        !           626:                 IoReleaseCancelSpinLock(OldIrql);
        !           627: 
        !           628:             }
        !           629: 
        !           630:         }
        !           631: 
        !           632:         //
        !           633:         // Note that the following call will (probably) also cause
        !           634:         // the current irp to be completed.
        !           635:         //
        !           636: 
        !           637:         SerialGetNextIrp(
        !           638:             CurrentOpIrp,
        !           639:             QueueToProcess,
        !           640:             NewIrp,
        !           641:             CompleteCurrent
        !           642:             );
        !           643: 
        !           644:         if (!*NewIrp) {
        !           645: 
        !           646:             KIRQL OldIrql;
        !           647: 
        !           648:             IoAcquireCancelSpinLock(&OldIrql);
        !           649:             KeSynchronizeExecution(
        !           650:                 Extension->Interrupt,
        !           651:                 SerialProcessEmptyTransmit,
        !           652:                 Extension
        !           653:                 );
        !           654:             IoReleaseCancelSpinLock(OldIrql);
        !           655: 
        !           656:             break;
        !           657: 
        !           658:         } else if (IoGetCurrentIrpStackLocation(*NewIrp)->MajorFunction
        !           659:                    == IRP_MJ_FLUSH_BUFFERS) {
        !           660: 
        !           661:             //
        !           662:             // If we encounter a flush request we just want to get
        !           663:             // the next irp and complete the flush.
        !           664:             //
        !           665:             // Note that if NewIrp is non-null then it is also
        !           666:             // equal to CurrentWriteIrp.
        !           667:             //
        !           668: 
        !           669: 
        !           670:             ASSERT((*NewIrp) == (*CurrentOpIrp));
        !           671:             (*NewIrp)->IoStatus.Status = STATUS_SUCCESS;
        !           672: 
        !           673:         } else {
        !           674: 
        !           675:             break;
        !           676: 
        !           677:         }
        !           678: 
        !           679:     } while (TRUE);
        !           680: 
        !           681: }
        !           682: 
        !           683: VOID
        !           684: SerialCompleteWrite(
        !           685:     IN PKDPC Dpc,
        !           686:     IN PVOID DeferredContext,
        !           687:     IN PVOID SystemContext1,
        !           688:     IN PVOID SystemContext2
        !           689:     )
        !           690: 
        !           691: /*++
        !           692: 
        !           693: Routine Description:
        !           694: 
        !           695:     This routine is merely used to complete any write.  It
        !           696:     assumes that the status and the information fields of
        !           697:     the irp are already correctly filled in.
        !           698: 
        !           699: Arguments:
        !           700: 
        !           701:     Dpc - Not Used.
        !           702: 
        !           703:     DeferredContext - Really points to the device extension.
        !           704: 
        !           705:     SystemContext1 - Not Used.
        !           706: 
        !           707:     SystemContext2 - Not Used.
        !           708: 
        !           709: Return Value:
        !           710: 
        !           711:     None.
        !           712: 
        !           713: --*/
        !           714: 
        !           715: {
        !           716: 
        !           717:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
        !           718:     KIRQL OldIrql;
        !           719: 
        !           720:     UNREFERENCED_PARAMETER(Dpc);
        !           721:     UNREFERENCED_PARAMETER(SystemContext1);
        !           722:     UNREFERENCED_PARAMETER(SystemContext2);
        !           723: 
        !           724:     IoAcquireCancelSpinLock(&OldIrql);
        !           725: 
        !           726:     SerialTryToCompleteCurrent(
        !           727:         Extension,
        !           728:         NULL,
        !           729:         OldIrql,
        !           730:         STATUS_SUCCESS,
        !           731:         &Extension->CurrentWriteIrp,
        !           732:         &Extension->WriteQueue,
        !           733:         NULL,
        !           734:         &Extension->WriteRequestTotalTimer,
        !           735:         SerialStartWrite,
        !           736:         SerialGetNextWrite
        !           737:         );
        !           738: 
        !           739: }
        !           740: 
        !           741: BOOLEAN
        !           742: SerialProcessEmptyTransmit(
        !           743:     IN PVOID Context
        !           744:     )
        !           745: 
        !           746: /*++
        !           747: 
        !           748: Routine Description:
        !           749: 
        !           750:     This routine is used to determine if conditions are appropriate
        !           751:     to satisfy a wait for transmit empty event, and if so to complete
        !           752:     the irp that is waiting for that event.  It also call the code
        !           753:     that checks to see if we should lower the RTS line if we are
        !           754:     doing transmit toggling.
        !           755: 
        !           756:     NOTE: This routine is called by KeSynchronizeExecution.
        !           757: 
        !           758:     NOTE: This routine assumes that it is called with the cancel
        !           759:           spinlock held.
        !           760: 
        !           761: Arguments:
        !           762: 
        !           763:     Context - Really a pointer to the device extension.
        !           764: 
        !           765: Return Value:
        !           766: 
        !           767:     This routine always returns FALSE.
        !           768: 
        !           769: --*/
        !           770: 
        !           771: {
        !           772: 
        !           773:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           774: 
        !           775:     if (Extension->IsrWaitMask && (Extension->IsrWaitMask & SERIAL_EV_TXEMPTY) &&
        !           776:         Extension->EmptiedTransmit && (!Extension->TransmitImmediate) &&
        !           777:         (!Extension->CurrentWriteIrp) && IsListEmpty(&Extension->WriteQueue)) {
        !           778: 
        !           779:         Extension->HistoryMask |= SERIAL_EV_TXEMPTY;
        !           780:         if (Extension->IrpMaskLocation) {
        !           781: 
        !           782:             *Extension->IrpMaskLocation = Extension->HistoryMask;
        !           783:             Extension->IrpMaskLocation = NULL;
        !           784:             Extension->HistoryMask = 0;
        !           785: 
        !           786:             Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
        !           787:             KeInsertQueueDpc(
        !           788:                 &Extension->CommWaitDpc,
        !           789:                 NULL,
        !           790:                 NULL
        !           791:                 );
        !           792: 
        !           793:         }
        !           794: 
        !           795:         Extension->CountOfTryingToLowerRTS++;
        !           796:         SerialPerhapsLowerRTS(Extension);
        !           797: 
        !           798:     }
        !           799: 
        !           800:     return FALSE;
        !           801: 
        !           802: }
        !           803: 
        !           804: BOOLEAN
        !           805: SerialGiveWriteToIsr(
        !           806:     IN PVOID Context
        !           807:     )
        !           808: 
        !           809: /*++
        !           810: 
        !           811: Routine Description:
        !           812: 
        !           813:     Try to start off the write by slipping it in behind
        !           814:     a transmit immediate char, or if that isn't available
        !           815:     and the transmit holding register is empty, "tickle"
        !           816:     the UART into interrupting with a transmit buffer
        !           817:     empty.
        !           818: 
        !           819:     NOTE: This routine is called by KeSynchronizeExecution.
        !           820: 
        !           821:     NOTE: This routine assumes that it is called with the
        !           822:           cancel spin lock held.
        !           823: 
        !           824: Arguments:
        !           825: 
        !           826:     Context - Really a pointer to the device extension.
        !           827: 
        !           828: Return Value:
        !           829: 
        !           830:     This routine always returns FALSE.
        !           831: 
        !           832: --*/
        !           833: 
        !           834: {
        !           835: 
        !           836:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           837: 
        !           838:     //
        !           839:     // The current stack location.  This contains all of the
        !           840:     // information we need to process this particular request.
        !           841:     //
        !           842:     PIO_STACK_LOCATION IrpSp;
        !           843: 
        !           844:     IrpSp = IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp);
        !           845: 
        !           846:     //
        !           847:     // We might have a xoff counter request masquerading as a
        !           848:     // write.  The length of these requests will always be one
        !           849:     // and we can get a pointer to the actual character from
        !           850:     // the data supplied by the user.
        !           851:     //
        !           852: 
        !           853:     if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
        !           854: 
        !           855:         Extension->WriteLength = IrpSp->Parameters.Write.Length;
        !           856:         Extension->WriteCurrentChar =
        !           857:             Extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer;
        !           858: 
        !           859:     } else {
        !           860: 
        !           861:         Extension->WriteLength = 1;
        !           862:         Extension->WriteCurrentChar =
        !           863:             ((PUCHAR)Extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer) +
        !           864:             FIELD_OFFSET(
        !           865:                 SERIAL_XOFF_COUNTER,
        !           866:                 XoffChar
        !           867:                 );
        !           868: 
        !           869:     }
        !           870: 
        !           871:     //
        !           872:     // The isr now has a reference to the irp.
        !           873:     //
        !           874: 
        !           875:     SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp);
        !           876: 
        !           877:     //
        !           878:     // Check first to see if an immediate char is transmitting.
        !           879:     // If it is then we'll just slip in behind it when its
        !           880:     // done.
        !           881:     //
        !           882: 
        !           883:     if (!Extension->TransmitImmediate) {
        !           884: 
        !           885:         //
        !           886:         // If there is no immediate char transmitting then we
        !           887:         // will "re-enable" the transmit holding register empty
        !           888:         // interrupt.  The 8250 family of devices will always
        !           889:         // signal a transmit holding register empty interrupt
        !           890:         // *ANY* time this bit is set to one.  By doing things
        !           891:         // this way we can simply use the normal interrupt code
        !           892:         // to start off this write.
        !           893:         //
        !           894:         // We've been keeping track of whether the transmit holding
        !           895:         // register is empty so it we only need to do this
        !           896:         // if the register is empty.
        !           897:         //
        !           898: 
        !           899:         if (Extension->HoldingEmpty) {
        !           900: 
        !           901:             DISABLE_ALL_INTERRUPTS(Extension->Controller);
        !           902:             ENABLE_ALL_INTERRUPTS(Extension->Controller);
        !           903: 
        !           904:         }
        !           905: 
        !           906:     }
        !           907: 
        !           908:     //
        !           909:     // The rts line may already be up from previous writes,
        !           910:     // however, it won't take much additional time to turn
        !           911:     // on the RTS line if we are doing transmit toggling.
        !           912:     //
        !           913: 
        !           914:     if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        !           915:         SERIAL_TRANSMIT_TOGGLE) {
        !           916: 
        !           917:         SerialSetRTS(Extension);
        !           918: 
        !           919:     }
        !           920: 
        !           921:     return FALSE;
        !           922: 
        !           923: }
        !           924: 
        !           925: VOID
        !           926: SerialCancelCurrentWrite(
        !           927:     PDEVICE_OBJECT DeviceObject,
        !           928:     PIRP Irp
        !           929:     )
        !           930: 
        !           931: /*++
        !           932: 
        !           933: Routine Description:
        !           934: 
        !           935:     This routine is used to cancel the current write.
        !           936: 
        !           937: Arguments:
        !           938: 
        !           939:     DeviceObject - Pointer to the device object for this device
        !           940: 
        !           941:     Irp - Pointer to the IRP to be canceled.
        !           942: 
        !           943: Return Value:
        !           944: 
        !           945:     None.
        !           946: 
        !           947: --*/
        !           948: 
        !           949: {
        !           950: 
        !           951:     PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
        !           952: 
        !           953:     SerialTryToCompleteCurrent(
        !           954:         Extension,
        !           955:         SerialGrabWriteFromIsr,
        !           956:         Irp->CancelIrql,
        !           957:         STATUS_CANCELLED,
        !           958:         &Extension->CurrentWriteIrp,
        !           959:         &Extension->WriteQueue,
        !           960:         NULL,
        !           961:         &Extension->WriteRequestTotalTimer,
        !           962:         SerialStartWrite,
        !           963:         SerialGetNextWrite
        !           964:         );
        !           965: 
        !           966: }
        !           967: 
        !           968: VOID
        !           969: SerialWriteTimeout(
        !           970:     IN PKDPC Dpc,
        !           971:     IN PVOID DeferredContext,
        !           972:     IN PVOID SystemContext1,
        !           973:     IN PVOID SystemContext2
        !           974:     )
        !           975: 
        !           976: /*++
        !           977: 
        !           978: Routine Description:
        !           979: 
        !           980:     This routine will try to timeout the current write.
        !           981: 
        !           982: Arguments:
        !           983: 
        !           984:     Dpc - Not Used.
        !           985: 
        !           986:     DeferredContext - Really points to the device extension.
        !           987: 
        !           988:     SystemContext1 - Not Used.
        !           989: 
        !           990:     SystemContext2 - Not Used.
        !           991: 
        !           992: Return Value:
        !           993: 
        !           994:     None.
        !           995: 
        !           996: --*/
        !           997: 
        !           998: {
        !           999: 
        !          1000:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
        !          1001:     KIRQL OldIrql;
        !          1002: 
        !          1003:     UNREFERENCED_PARAMETER(Dpc);
        !          1004:     UNREFERENCED_PARAMETER(SystemContext1);
        !          1005:     UNREFERENCED_PARAMETER(SystemContext2);
        !          1006: 
        !          1007:     IoAcquireCancelSpinLock(&OldIrql);
        !          1008: 
        !          1009:     SerialTryToCompleteCurrent(
        !          1010:         Extension,
        !          1011:         SerialGrabWriteFromIsr,
        !          1012:         OldIrql,
        !          1013:         STATUS_TIMEOUT,
        !          1014:         &Extension->CurrentWriteIrp,
        !          1015:         &Extension->WriteQueue,
        !          1016:         NULL,
        !          1017:         &Extension->WriteRequestTotalTimer,
        !          1018:         SerialStartWrite,
        !          1019:         SerialGetNextWrite
        !          1020:         );
        !          1021: 
        !          1022: }
        !          1023: 
        !          1024: BOOLEAN
        !          1025: SerialGrabWriteFromIsr(
        !          1026:     IN PVOID Context
        !          1027:     )
        !          1028: 
        !          1029: /*++
        !          1030: 
        !          1031: Routine Description:
        !          1032: 
        !          1033: 
        !          1034:     This routine is used to grab the current irp, which could be timing
        !          1035:     out or canceling, from the ISR
        !          1036: 
        !          1037:     NOTE: This routine is being called from KeSynchronizeExecution.
        !          1038: 
        !          1039:     NOTE: This routine assumes that the cancel spin lock is held
        !          1040:           when this routine is called.
        !          1041: 
        !          1042: Arguments:
        !          1043: 
        !          1044:     Context - Really a pointer to the device extension.
        !          1045: 
        !          1046: Return Value:
        !          1047: 
        !          1048:     Always false.
        !          1049: 
        !          1050: --*/
        !          1051: 
        !          1052: {
        !          1053: 
        !          1054:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !          1055: 
        !          1056:     //
        !          1057:     // Check if the write length is non-zero.  If it is non-zero
        !          1058:     // then the ISR still owns the irp. We calculate the the number
        !          1059:     // of characters written and update the information field of the
        !          1060:     // irp with the characters written.  We then clear the write length
        !          1061:     // the isr sees.
        !          1062:     //
        !          1063: 
        !          1064:     if (Extension->WriteLength) {
        !          1065: 
        !          1066:         //
        !          1067:         // We could have an xoff counter masquerading as a
        !          1068:         // write irp.  If so, don't update the write length.
        !          1069:         //
        !          1070: 
        !          1071:         if (IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp)
        !          1072:             ->MajorFunction == IRP_MJ_WRITE) {
        !          1073: 
        !          1074:             Extension->CurrentWriteIrp->IoStatus.Information =
        !          1075:                 IoGetCurrentIrpStackLocation(
        !          1076:                     Extension->CurrentWriteIrp
        !          1077:                     )->Parameters.Write.Length -
        !          1078:                 Extension->WriteLength;
        !          1079: 
        !          1080:         } else {
        !          1081: 
        !          1082:             Extension->CurrentWriteIrp->IoStatus.Information = 0;
        !          1083: 
        !          1084:         }
        !          1085: 
        !          1086:         //
        !          1087:         // Since the isr no longer references this irp, we can
        !          1088:         // decrement it's reference count.
        !          1089:         //
        !          1090: 
        !          1091:         SERIAL_DEC_REFERENCE(Extension->CurrentWriteIrp);
        !          1092: 
        !          1093:         Extension->WriteLength = 0;
        !          1094: 
        !          1095:     }
        !          1096: 
        !          1097:     return FALSE;
        !          1098: 
        !          1099: }
        !          1100: 
        !          1101: BOOLEAN
        !          1102: SerialGrabXoffFromIsr(
        !          1103:     IN PVOID Context
        !          1104:     )
        !          1105: 
        !          1106: /*++
        !          1107: 
        !          1108: Routine Description:
        !          1109: 
        !          1110:     This routine is used to grab an xoff counter irp from the
        !          1111:     isr when it is no longer masquerading as a write irp.  This
        !          1112:     routine is called by the cancel and timeout code for the
        !          1113:     xoff counter ioctl.
        !          1114: 
        !          1115: 
        !          1116:     NOTE: This routine is being called from KeSynchronizeExecution.
        !          1117: 
        !          1118:     NOTE: This routine assumes that the cancel spin lock is held
        !          1119:           when this routine is called.
        !          1120: 
        !          1121: Arguments:
        !          1122: 
        !          1123:     Context - Really a pointer to the device extension.
        !          1124: 
        !          1125: Return Value:
        !          1126: 
        !          1127:     Always false.
        !          1128: 
        !          1129: --*/
        !          1130: 
        !          1131: {
        !          1132: 
        !          1133:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !          1134: 
        !          1135:     if (Extension->CountSinceXoff) {
        !          1136: 
        !          1137:         //
        !          1138:         // This is only non-zero when there actually is a Xoff ioctl
        !          1139:         // counting down.
        !          1140:         //
        !          1141: 
        !          1142:         Extension->CountSinceXoff = 0;
        !          1143: 
        !          1144:         //
        !          1145:         // We decrement the count since the isr no longer owns
        !          1146:         // the irp.
        !          1147:         //
        !          1148: 
        !          1149:         SERIAL_DEC_REFERENCE(Extension->CurrentXoffIrp);
        !          1150: 
        !          1151:     }
        !          1152: 
        !          1153:     return FALSE;
        !          1154: 
        !          1155: }
        !          1156: 
        !          1157: VOID
        !          1158: SerialCompleteXoff(
        !          1159:     IN PKDPC Dpc,
        !          1160:     IN PVOID DeferredContext,
        !          1161:     IN PVOID SystemContext1,
        !          1162:     IN PVOID SystemContext2
        !          1163:     )
        !          1164: 
        !          1165: /*++
        !          1166: 
        !          1167: Routine Description:
        !          1168: 
        !          1169:     This routine is merely used to truely complete an xoff counter irp.  It
        !          1170:     assumes that the status and the information fields of the irp are
        !          1171:     already correctly filled in.
        !          1172: 
        !          1173: Arguments:
        !          1174: 
        !          1175:     Dpc - Not Used.
        !          1176: 
        !          1177:     DeferredContext - Really points to the device extension.
        !          1178: 
        !          1179:     SystemContext1 - Not Used.
        !          1180: 
        !          1181:     SystemContext2 - Not Used.
        !          1182: 
        !          1183: Return Value:
        !          1184: 
        !          1185:     None.
        !          1186: 
        !          1187: --*/
        !          1188: 
        !          1189: {
        !          1190: 
        !          1191:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
        !          1192:     KIRQL OldIrql;
        !          1193: 
        !          1194:     UNREFERENCED_PARAMETER(Dpc);
        !          1195:     UNREFERENCED_PARAMETER(SystemContext1);
        !          1196:     UNREFERENCED_PARAMETER(SystemContext2);
        !          1197: 
        !          1198:     IoAcquireCancelSpinLock(&OldIrql);
        !          1199: 
        !          1200:     //
        !          1201:     // Turn this irp back into the current write irp so
        !          1202:     // that it will start of any writes behind it.
        !          1203:     //
        !          1204: 
        !          1205:     Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
        !          1206: 
        !          1207:     SerialTryToCompleteCurrent(
        !          1208:         Extension,
        !          1209:         NULL,
        !          1210:         OldIrql,
        !          1211:         STATUS_SUCCESS,
        !          1212:         &Extension->CurrentWriteIrp,
        !          1213:         &Extension->WriteQueue,
        !          1214:         NULL,
        !          1215:         &Extension->XoffCountTimer,
        !          1216:         SerialStartWrite,
        !          1217:         SerialGetNextWrite
        !          1218:         );
        !          1219: 
        !          1220: }
        !          1221: 
        !          1222: VOID
        !          1223: SerialTimeoutXoff(
        !          1224:     IN PKDPC Dpc,
        !          1225:     IN PVOID DeferredContext,
        !          1226:     IN PVOID SystemContext1,
        !          1227:     IN PVOID SystemContext2
        !          1228:     )
        !          1229: 
        !          1230: /*++
        !          1231: 
        !          1232: Routine Description:
        !          1233: 
        !          1234:     This routine is merely used to truely complete an xoff counter irp,
        !          1235:     if its timer has run out.
        !          1236: 
        !          1237: Arguments:
        !          1238: 
        !          1239:     Dpc - Not Used.
        !          1240: 
        !          1241:     DeferredContext - Really points to the device extension.
        !          1242: 
        !          1243:     SystemContext1 - Not Used.
        !          1244: 
        !          1245:     SystemContext2 - Not Used.
        !          1246: 
        !          1247: Return Value:
        !          1248: 
        !          1249:     None.
        !          1250: 
        !          1251: --*/
        !          1252: 
        !          1253: {
        !          1254: 
        !          1255:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
        !          1256:     KIRQL OldIrql;
        !          1257: 
        !          1258:     UNREFERENCED_PARAMETER(Dpc);
        !          1259:     UNREFERENCED_PARAMETER(SystemContext1);
        !          1260:     UNREFERENCED_PARAMETER(SystemContext2);
        !          1261: 
        !          1262:     IoAcquireCancelSpinLock(&OldIrql);
        !          1263: 
        !          1264:     //
        !          1265:     // Turn this irp back into the current write irp so
        !          1266:     // that it will start of any writes behind it.
        !          1267:     //
        !          1268: 
        !          1269:     Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
        !          1270: 
        !          1271:     SerialTryToCompleteCurrent(
        !          1272:         Extension,
        !          1273:         SerialGrabXoffFromIsr,
        !          1274:         OldIrql,
        !          1275:         STATUS_SERIAL_COUNTER_TIMEOUT,
        !          1276:         &Extension->CurrentWriteIrp,
        !          1277:         &Extension->WriteQueue,
        !          1278:         NULL,
        !          1279:         &Extension->XoffCountTimer,
        !          1280:         SerialStartWrite,
        !          1281:         SerialGetNextWrite
        !          1282:         );
        !          1283: 
        !          1284: }
        !          1285: 
        !          1286: VOID
        !          1287: SerialCancelCurrentXoff(
        !          1288:     PDEVICE_OBJECT DeviceObject,
        !          1289:     PIRP Irp
        !          1290:     )
        !          1291: 
        !          1292: /*++
        !          1293: 
        !          1294: Routine Description:
        !          1295: 
        !          1296:     This routine is used to cancel the current write.
        !          1297: 
        !          1298: Arguments:
        !          1299: 
        !          1300:     DeviceObject - Pointer to the device object for this device
        !          1301: 
        !          1302:     Irp - Pointer to the IRP to be canceled.
        !          1303: 
        !          1304: Return Value:
        !          1305: 
        !          1306:     None.
        !          1307: 
        !          1308: --*/
        !          1309: 
        !          1310: {
        !          1311: 
        !          1312:     PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
        !          1313: 
        !          1314:     //
        !          1315:     // Turn this irp back into the current write irp so
        !          1316:     // that it will start of any writes behind it.
        !          1317:     //
        !          1318: 
        !          1319:     Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
        !          1320: 
        !          1321:     SerialTryToCompleteCurrent(
        !          1322:         Extension,
        !          1323:         SerialGrabXoffFromIsr,
        !          1324:         Irp->CancelIrql,
        !          1325:         STATUS_CANCELLED,
        !          1326:         &Extension->CurrentWriteIrp,
        !          1327:         &Extension->WriteQueue,
        !          1328:         NULL,
        !          1329:         &Extension->XoffCountTimer,
        !          1330:         SerialStartWrite,
        !          1331:         SerialGetNextWrite
        !          1332:         );
        !          1333: 
        !          1334: }
        !          1335: 
        !          1336: BOOLEAN
        !          1337: SerialGiveXoffToIsr(
        !          1338:     IN PVOID Context
        !          1339:     )
        !          1340: 
        !          1341: /*++
        !          1342: 
        !          1343: Routine Description:
        !          1344: 
        !          1345: 
        !          1346:     This routine starts off the xoff counter.  It merely
        !          1347:     has to set the xoff count and increment the reference
        !          1348:     count to denote that the isr has a reference to the irp.
        !          1349: 
        !          1350:     NOTE: This routine is called by KeSynchronizeExecution.
        !          1351: 
        !          1352:     NOTE: This routine assumes that it is called with the
        !          1353:           cancel spin lock held.
        !          1354: 
        !          1355: Arguments:
        !          1356: 
        !          1357:     Context - Really a pointer to the device extension.
        !          1358: 
        !          1359: Return Value:
        !          1360: 
        !          1361:     This routine always returns FALSE.
        !          1362: 
        !          1363: --*/
        !          1364: 
        !          1365: {
        !          1366: 
        !          1367:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !          1368: 
        !          1369:     //
        !          1370:     // The current stack location.  This contains all of the
        !          1371:     // information we need to process this particular request.
        !          1372:     //
        !          1373:     PSERIAL_XOFF_COUNTER Xc =
        !          1374:         Extension->CurrentXoffIrp->AssociatedIrp.SystemBuffer;
        !          1375: 
        !          1376:     Extension->CountSinceXoff = Xc->Counter;
        !          1377: 
        !          1378:     //
        !          1379:     // The isr now has a reference to the irp.
        !          1380:     //
        !          1381: 
        !          1382:     SERIAL_INC_REFERENCE(Extension->CurrentXoffIrp);
        !          1383: 
        !          1384:     return FALSE;
        !          1385: 
        !          1386: }

unix.superglobalmegacorp.com

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