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

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     read.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains the code that is very specific to read
        !            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: VOID
        !            34: SerialCancelCurrentRead(
        !            35:     PDEVICE_OBJECT DeviceObject,
        !            36:     PIRP Irp
        !            37:     );
        !            38: 
        !            39: BOOLEAN
        !            40: SerialGrabReadFromIsr(
        !            41:     IN PVOID Context
        !            42:     );
        !            43: 
        !            44: BOOLEAN
        !            45: SerialUpdateReadByIsr(
        !            46:     IN PVOID Context
        !            47:     );
        !            48: 
        !            49: ULONG
        !            50: SerialGetCharsFromIntBuffer(
        !            51:     PSERIAL_DEVICE_EXTENSION Extension
        !            52:     );
        !            53: 
        !            54: BOOLEAN
        !            55: SerialUpdateInterruptBuffer(
        !            56:     IN PVOID Context
        !            57:     );
        !            58: 
        !            59: BOOLEAN
        !            60: SerialUpdateAndSwitchToUser(
        !            61:     IN PVOID Context
        !            62:     );
        !            63: 
        !            64: NTSTATUS
        !            65: SerialResizeBuffer(
        !            66:     IN PSERIAL_DEVICE_EXTENSION Extension
        !            67:     );
        !            68: 
        !            69: ULONG
        !            70: SerialMoveToNewIntBuffer(
        !            71:     PSERIAL_DEVICE_EXTENSION Extension,
        !            72:     PUCHAR NewBuffer
        !            73:     );
        !            74: 
        !            75: BOOLEAN
        !            76: SerialUpdateAndSwitchToNew(
        !            77:     IN PVOID Context
        !            78:     );
        !            79: 
        !            80: 
        !            81: NTSTATUS
        !            82: SerialRead(
        !            83:     IN PDEVICE_OBJECT DeviceObject,
        !            84:     IN PIRP Irp
        !            85:     )
        !            86: 
        !            87: /*++
        !            88: 
        !            89: Routine Description:
        !            90: 
        !            91:     This is the dispatch routine for reading.  It validates the parameters
        !            92:     for the read request and if all is ok then it places the request
        !            93:     on the work queue.
        !            94: 
        !            95: Arguments:
        !            96: 
        !            97:     DeviceObject - Pointer to the device object for this device
        !            98: 
        !            99:     Irp - Pointer to the IRP for the current request
        !           100: 
        !           101: Return Value:
        !           102: 
        !           103:     If the io is zero length then it will return STATUS_SUCCESS,
        !           104:     otherwise this routine will return the status returned by
        !           105:     the actual start read routine.
        !           106: 
        !           107: --*/
        !           108: 
        !           109: {
        !           110: 
        !           111:     PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
        !           112: 
        !           113:     SerialDump(
        !           114:         SERIRPPATH,
        !           115:         ("SERIAL: Dispatch entry for: %x\n",Irp)
        !           116:         );
        !           117:     if (SerialCompleteIfError(
        !           118:             DeviceObject,
        !           119:             Irp
        !           120:             ) != STATUS_SUCCESS) {
        !           121: 
        !           122:         return STATUS_CANCELLED;
        !           123: 
        !           124:     }
        !           125: 
        !           126:     Irp->IoStatus.Information = 0L;
        !           127: 
        !           128:     //
        !           129:     // Quick check for a zero length read.  If it is zero length
        !           130:     // then we are already done!
        !           131:     //
        !           132: 
        !           133:     if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length) {
        !           134: 
        !           135:         //
        !           136:         // Well it looks like we actually have to do some
        !           137:         // work.  Put the read on the queue so that we can
        !           138:         // process it when our previous reads are done.
        !           139:         //
        !           140: 
        !           141:         return SerialStartOrQueue(
        !           142:                    extension,
        !           143:                    Irp,
        !           144:                    &extension->ReadQueue,
        !           145:                    &extension->CurrentReadIrp,
        !           146:                    SerialStartRead
        !           147:                    );
        !           148: 
        !           149:     } else {
        !           150: 
        !           151:         Irp->IoStatus.Status = STATUS_SUCCESS;
        !           152:         SerialDump(
        !           153:             SERIRPPATH,
        !           154:             ("SERIAL: Complete Irp: %x\n",Irp)
        !           155:             );
        !           156:         IoCompleteRequest(
        !           157:             Irp,
        !           158:             0
        !           159:             );
        !           160: 
        !           161:         return STATUS_SUCCESS;
        !           162: 
        !           163:     }
        !           164: 
        !           165: }
        !           166: 
        !           167: NTSTATUS
        !           168: SerialStartRead(
        !           169:     IN PSERIAL_DEVICE_EXTENSION Extension
        !           170:     )
        !           171: 
        !           172: /*++
        !           173: 
        !           174: Routine Description:
        !           175: 
        !           176:     This routine is used to start off any read.  It initializes
        !           177:     the Iostatus fields of the irp.  It will set up any timers
        !           178:     that are used to control the read.  It will attempt to complete
        !           179:     the read from data already in the interrupt buffer.  If the
        !           180:     read can be completed quickly it will start off another if
        !           181:     necessary.
        !           182: 
        !           183: Arguments:
        !           184: 
        !           185:     Extension - Simply a pointer to the serial device extension.
        !           186: 
        !           187: Return Value:
        !           188: 
        !           189:     This routine will return the status of the first read
        !           190:     irp.  This is useful in that if we have a read that can
        !           191:     complete right away (AND there had been nothing in the
        !           192:     queue before it) the read could return SUCCESS and the
        !           193:     application won't have to do a wait.
        !           194: 
        !           195: --*/
        !           196: 
        !           197: {
        !           198: 
        !           199:     SERIAL_UPDATE_CHAR updateChar;
        !           200: 
        !           201:     PIRP newIrp;
        !           202:     KIRQL oldIrql;
        !           203:     KIRQL controlIrql;
        !           204: 
        !           205:     BOOLEAN returnWithWhatsPresent;
        !           206:     BOOLEAN os2ssreturn;
        !           207:     BOOLEAN crunchDownToOne;
        !           208:     BOOLEAN useTotalTimer;
        !           209:     BOOLEAN useIntervalTimer;
        !           210: 
        !           211:     ULONG multiplierVal;
        !           212:     ULONG constantVal;
        !           213: 
        !           214:     LARGE_INTEGER totalTime;
        !           215: 
        !           216:     SERIAL_TIMEOUTS timeoutsForIrp;
        !           217: 
        !           218:     BOOLEAN setFirstStatus = FALSE;
        !           219:     NTSTATUS firstStatus;
        !           220: 
        !           221: 
        !           222:     updateChar.Extension = Extension;
        !           223: 
        !           224:     do {
        !           225: 
        !           226:         //
        !           227:         // Check to see if this is a resize request.  If it is
        !           228:         // then go to a routine that specializes in that.
        !           229:         //
        !           230: 
        !           231:         if (IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
        !           232:             ->MajorFunction != IRP_MJ_READ) {
        !           233: 
        !           234:             NTSTATUS localStatus = SerialResizeBuffer(Extension);
        !           235: 
        !           236:             if (!setFirstStatus) {
        !           237: 
        !           238:                 firstStatus = localStatus;
        !           239:                 setFirstStatus = TRUE;
        !           240: 
        !           241:             }
        !           242: 
        !           243:         } else {
        !           244: 
        !           245:             Extension->NumberNeededForRead =
        !           246:                 IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
        !           247:                     ->Parameters.Read.Length;
        !           248: 
        !           249:             //
        !           250:             // Calculate the timeout value needed for the
        !           251:             // request.  Note that the values stored in the
        !           252:             // timeout record are in milliseconds.
        !           253:             //
        !           254: 
        !           255:             useTotalTimer = FALSE;
        !           256:             returnWithWhatsPresent = FALSE;
        !           257:             os2ssreturn = FALSE;
        !           258:             crunchDownToOne = FALSE;
        !           259:             useIntervalTimer = FALSE;
        !           260: 
        !           261: 
        !           262:             //
        !           263:             // Always initialize the timer objects so that the
        !           264:             // completion code can tell when it attempts to
        !           265:             // cancel the timers whether the timers had ever
        !           266:             // been Set.
        !           267:             //
        !           268: 
        !           269:             KeInitializeTimer(&Extension->ReadRequestTotalTimer);
        !           270:             KeInitializeTimer(&Extension->ReadRequestIntervalTimer);
        !           271: 
        !           272:             //
        !           273:             // We get the *current* timeout values to use for timing
        !           274:             // this read.
        !           275:             //
        !           276: 
        !           277:             KeAcquireSpinLock(
        !           278:                 &Extension->ControlLock,
        !           279:                 &controlIrql
        !           280:                 );
        !           281: 
        !           282:             timeoutsForIrp = Extension->Timeouts;
        !           283: 
        !           284:             KeReleaseSpinLock(
        !           285:                 &Extension->ControlLock,
        !           286:                 controlIrql
        !           287:                 );
        !           288: 
        !           289:             //
        !           290:             // Calculate the interval timeout for the read.
        !           291:             //
        !           292: 
        !           293:             if (timeoutsForIrp.ReadIntervalTimeout &&
        !           294:                 (timeoutsForIrp.ReadIntervalTimeout !=
        !           295:                  MAXULONG)) {
        !           296: 
        !           297:                 useIntervalTimer = TRUE;
        !           298: 
        !           299:                 Extension->IntervalTime = RtlEnlargedUnsignedMultiply(
        !           300:                                              timeoutsForIrp.ReadIntervalTimeout,
        !           301:                                              10000
        !           302:                                              );
        !           303: 
        !           304: 
        !           305:                 if (RtlLargeIntegerGreaterThanOrEqualTo(
        !           306:                         Extension->IntervalTime,
        !           307:                         Extension->CutOverAmount
        !           308:                         )) {
        !           309: 
        !           310:                     Extension->IntervalTimeToUse =
        !           311:                         &Extension->LongIntervalAmount;
        !           312: 
        !           313:                 } else {
        !           314: 
        !           315:                     Extension->IntervalTimeToUse =
        !           316:                         &Extension->ShortIntervalAmount;
        !           317: 
        !           318:                 }
        !           319: 
        !           320:             }
        !           321: 
        !           322:             if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) {
        !           323: 
        !           324:                 //
        !           325:                 // We need to do special return quickly stuff here.
        !           326:                 //
        !           327:                 // 1) If both constant and multiplier are
        !           328:                 //    0 then we return immediately with whatever
        !           329:                 //    we've got, even if it was zero.
        !           330:                 //
        !           331:                 // 2) If constant and multiplier are not MAXULONG
        !           332:                 //    then return immediately if any characters
        !           333:                 //    are present, but if nothing is there, then
        !           334:                 //    use the timeouts as specified.
        !           335:                 //
        !           336:                 // 3) If multiplier is MAXULONG then do as in
        !           337:                 //    "2" but return when the first character
        !           338:                 //    arrives.
        !           339:                 //
        !           340: 
        !           341:                 if (!timeoutsForIrp.ReadTotalTimeoutConstant &&
        !           342:                     !timeoutsForIrp.ReadTotalTimeoutMultiplier) {
        !           343: 
        !           344:                     returnWithWhatsPresent = TRUE;
        !           345: 
        !           346:                 } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
        !           347:                             &&
        !           348:                            (timeoutsForIrp.ReadTotalTimeoutMultiplier
        !           349:                             != MAXULONG)) {
        !           350: 
        !           351:                     useTotalTimer = TRUE;
        !           352:                     os2ssreturn = TRUE;
        !           353:                     multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
        !           354:                     constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
        !           355: 
        !           356:                 } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
        !           357:                             &&
        !           358:                            (timeoutsForIrp.ReadTotalTimeoutMultiplier
        !           359:                             == MAXULONG)) {
        !           360: 
        !           361:                     useTotalTimer = TRUE;
        !           362:                     os2ssreturn = TRUE;
        !           363:                     crunchDownToOne = TRUE;
        !           364:                     multiplierVal = 0;
        !           365:                     constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
        !           366: 
        !           367:                 }
        !           368: 
        !           369:             } else {
        !           370: 
        !           371:                 //
        !           372:                 // If both the multiplier and the constant are
        !           373:                 // zero then don't do any total timeout processing.
        !           374:                 //
        !           375: 
        !           376:                 if (timeoutsForIrp.ReadTotalTimeoutMultiplier ||
        !           377:                     timeoutsForIrp.ReadTotalTimeoutConstant) {
        !           378: 
        !           379:                     //
        !           380:                     // We have some timer values to calculate.
        !           381:                     //
        !           382: 
        !           383:                     useTotalTimer = TRUE;
        !           384:                     multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
        !           385:                     constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
        !           386: 
        !           387:                 }
        !           388: 
        !           389:             }
        !           390: 
        !           391:             if (useTotalTimer) {
        !           392: 
        !           393:                 totalTime = RtlEnlargedUnsignedMultiply(
        !           394:                                 Extension->NumberNeededForRead,
        !           395:                                 multiplierVal
        !           396:                                 );
        !           397: 
        !           398:                 totalTime = RtlLargeIntegerAdd(
        !           399:                                 totalTime,
        !           400:                                 RtlConvertUlongToLargeInteger(
        !           401:                                     constantVal
        !           402:                                     )
        !           403:                                 );
        !           404: 
        !           405:                 totalTime = RtlExtendedIntegerMultiply(
        !           406:                                 totalTime,
        !           407:                                 -10000
        !           408:                                 );
        !           409: 
        !           410:             }
        !           411: 
        !           412: 
        !           413:             //
        !           414:             // We do this copy in the hope of getting most (if not
        !           415:             // all) of the characters out of the interrupt buffer.
        !           416:             //
        !           417:             // Note that we need to protect this operation with a
        !           418:             // spinlock since we don't want a purge to hose us.
        !           419:             //
        !           420: 
        !           421:             KeAcquireSpinLock(
        !           422:                 &Extension->ControlLock,
        !           423:                 &controlIrql
        !           424:                 );
        !           425: 
        !           426:             updateChar.CharsCopied = SerialGetCharsFromIntBuffer(Extension);
        !           427: 
        !           428:             //
        !           429:             // See if we have any cause to return immediately.
        !           430:             //
        !           431: 
        !           432:             if (returnWithWhatsPresent || (!Extension->NumberNeededForRead) ||
        !           433:                 (os2ssreturn &&
        !           434:                  Extension->CurrentReadIrp->IoStatus.Information)) {
        !           435: 
        !           436:                 //
        !           437:                 // We got all we needed for this read.
        !           438:                 // Update the number of characters in the
        !           439:                 // interrupt read buffer.
        !           440:                 //
        !           441: 
        !           442:                 KeSynchronizeExecution(
        !           443:                     Extension->Interrupt,
        !           444:                     SerialUpdateInterruptBuffer,
        !           445:                     &updateChar
        !           446:                     );
        !           447: 
        !           448:                 KeReleaseSpinLock(
        !           449:                     &Extension->ControlLock,
        !           450:                     controlIrql
        !           451:                     );
        !           452: 
        !           453:                 Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
        !           454:                 if (!setFirstStatus) {
        !           455: 
        !           456:                     firstStatus = STATUS_SUCCESS;
        !           457:                     setFirstStatus = TRUE;
        !           458: 
        !           459:                 }
        !           460: 
        !           461:             } else {
        !           462: 
        !           463:                 //
        !           464:                 // The irp might go under control of the isr.  It
        !           465:                 // won't hurt to initialize the reference count
        !           466:                 // right now.
        !           467:                 //
        !           468: 
        !           469:                 SERIAL_INIT_REFERENCE(Extension->CurrentReadIrp);
        !           470: 
        !           471:                 IoAcquireCancelSpinLock(&oldIrql);
        !           472: 
        !           473:                 //
        !           474:                 // We need to see if this irp should be canceled.
        !           475:                 //
        !           476: 
        !           477:                 if (Extension->CurrentReadIrp->Cancel) {
        !           478: 
        !           479:                     IoReleaseCancelSpinLock(oldIrql);
        !           480:                     KeReleaseSpinLock(
        !           481:                         &Extension->ControlLock,
        !           482:                         controlIrql
        !           483:                         );
        !           484:                     Extension->CurrentReadIrp->IoStatus.Status =
        !           485:                         STATUS_CANCELLED;
        !           486:                     Extension->CurrentReadIrp->IoStatus.Information = 0;
        !           487: 
        !           488:                     if (!setFirstStatus) {
        !           489: 
        !           490:                         firstStatus = STATUS_CANCELLED;
        !           491:                         setFirstStatus = TRUE;
        !           492: 
        !           493:                     }
        !           494: 
        !           495:                 } else {
        !           496: 
        !           497:                     //
        !           498:                     // If we are supposed to crunch the read down to
        !           499:                     // one character, then update the read length
        !           500:                     // in the irp and truncate the number needed for
        !           501:                     // read down to one. Note that if we are doing
        !           502:                     // this crunching, then the information must be
        !           503:                     // zero (or we would have completed above) and
        !           504:                     // the number needed for the read must still be
        !           505:                     // equal to the read length.
        !           506:                     //
        !           507: 
        !           508:                     if (crunchDownToOne) {
        !           509: 
        !           510:                         ASSERT(
        !           511:                             (!Extension->CurrentReadIrp->IoStatus.Information)
        !           512:                             &&
        !           513:                             (Extension->NumberNeededForRead ==
        !           514:                                 IoGetCurrentIrpStackLocation(
        !           515:                                     Extension->CurrentReadIrp
        !           516:                                     )->Parameters.Read.Length)
        !           517:                             );
        !           518: 
        !           519:                         Extension->NumberNeededForRead = 1;
        !           520:                         IoGetCurrentIrpStackLocation(
        !           521:                             Extension->CurrentReadIrp
        !           522:                             )->Parameters.Read.Length = 1;
        !           523: 
        !           524:                     }
        !           525: 
        !           526:                     //
        !           527:                     // We still need to get more characters for this read.
        !           528:                     // synchronize with the isr so that we can update the
        !           529:                     // number of characters and if necessary it will have the
        !           530:                     // isr switch to copying into the users buffer.
        !           531:                     //
        !           532: 
        !           533:                     KeSynchronizeExecution(
        !           534:                         Extension->Interrupt,
        !           535:                         SerialUpdateAndSwitchToUser,
        !           536:                         &updateChar
        !           537:                         );
        !           538: 
        !           539:                     if (!updateChar.Completed) {
        !           540: 
        !           541:                         //
        !           542:                         // The irp still isn't complete.  The
        !           543:                         // completion routines will end up reinvoking
        !           544:                         // this routine.  So we simply leave.
        !           545:                         //
        !           546:                         // First thought we should start off the total
        !           547:                         // timer for the read and increment the reference
        !           548:                         // count that the total timer has on the current
        !           549:                         // irp.  Note that this is safe, because even if
        !           550:                         // the io has been satisfied by the isr it can't
        !           551:                         // complete yet because we still own the cancel
        !           552:                         // spinlock.
        !           553:                         //
        !           554: 
        !           555:                         if (useTotalTimer) {
        !           556: 
        !           557:                             SERIAL_INC_REFERENCE(Extension->CurrentReadIrp);
        !           558: 
        !           559:                             KeSetTimer(
        !           560:                                 &Extension->ReadRequestTotalTimer,
        !           561:                                 totalTime,
        !           562:                                 &Extension->TotalReadTimeoutDpc
        !           563:                                 );
        !           564: 
        !           565:                         }
        !           566: 
        !           567:                         if (useIntervalTimer) {
        !           568: 
        !           569:                             SERIAL_INC_REFERENCE(Extension->CurrentReadIrp);
        !           570: 
        !           571:                             KeQuerySystemTime(
        !           572:                                 &Extension->LastReadTime
        !           573:                                 );
        !           574:                             KeSetTimer(
        !           575:                                 &Extension->ReadRequestIntervalTimer,
        !           576:                                 *Extension->IntervalTimeToUse,
        !           577:                                 &Extension->IntervalReadTimeoutDpc
        !           578:                                 );
        !           579: 
        !           580:                         }
        !           581: 
        !           582:                         IoMarkIrpPending(Extension->CurrentReadIrp);
        !           583:                         IoReleaseCancelSpinLock(oldIrql);
        !           584:                         KeReleaseSpinLock(
        !           585:                             &Extension->ControlLock,
        !           586:                             controlIrql
        !           587:                             );
        !           588:                         if (!setFirstStatus) {
        !           589: 
        !           590:                             firstStatus = STATUS_PENDING;
        !           591: 
        !           592:                         }
        !           593:                         return firstStatus;
        !           594: 
        !           595:                     } else {
        !           596: 
        !           597:                         IoReleaseCancelSpinLock(oldIrql);
        !           598:                         KeReleaseSpinLock(
        !           599:                             &Extension->ControlLock,
        !           600:                             controlIrql
        !           601:                             );
        !           602:                         Extension->CurrentReadIrp->IoStatus.Status =
        !           603:                             STATUS_SUCCESS;
        !           604: 
        !           605:                         if (!setFirstStatus) {
        !           606: 
        !           607:                             firstStatus = STATUS_SUCCESS;
        !           608:                             setFirstStatus = TRUE;
        !           609: 
        !           610:                         }
        !           611: 
        !           612:                     }
        !           613: 
        !           614:                 }
        !           615: 
        !           616:             }
        !           617: 
        !           618:         }
        !           619: 
        !           620:         //
        !           621:         // Well the operation is complete.
        !           622:         //
        !           623: 
        !           624:         SerialGetNextIrp(
        !           625:             &Extension->CurrentReadIrp,
        !           626:             &Extension->ReadQueue,
        !           627:             &newIrp,
        !           628:             TRUE
        !           629:             );
        !           630: 
        !           631:     } while (newIrp);
        !           632: 
        !           633:     return firstStatus;
        !           634: 
        !           635: }
        !           636: 
        !           637: VOID
        !           638: SerialCompleteRead(
        !           639:     IN PKDPC Dpc,
        !           640:     IN PVOID DeferredContext,
        !           641:     IN PVOID SystemContext1,
        !           642:     IN PVOID SystemContext2
        !           643:     )
        !           644: 
        !           645: /*++
        !           646: 
        !           647: Routine Description:
        !           648: 
        !           649:     This routine is merely used to complete any read that
        !           650:     ended up being used by the Isr.  It assumes that the
        !           651:     status and the information fields of the irp are already
        !           652:     correctly filled in.
        !           653: 
        !           654: Arguments:
        !           655: 
        !           656:     Dpc - Not Used.
        !           657: 
        !           658:     DeferredContext - Really points to the device extension.
        !           659: 
        !           660:     SystemContext1 - Not Used.
        !           661: 
        !           662:     SystemContext2 - Not Used.
        !           663: 
        !           664: Return Value:
        !           665: 
        !           666:     None.
        !           667: 
        !           668: --*/
        !           669: 
        !           670: {
        !           671: 
        !           672:     PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
        !           673:     KIRQL oldIrql;
        !           674: 
        !           675:     UNREFERENCED_PARAMETER(Dpc);
        !           676:     UNREFERENCED_PARAMETER(SystemContext1);
        !           677:     UNREFERENCED_PARAMETER(SystemContext2);
        !           678: 
        !           679: 
        !           680:     IoAcquireCancelSpinLock(&oldIrql);
        !           681: 
        !           682:     //
        !           683:     // We set this to indicate to the interval timer
        !           684:     // that the read has completed.
        !           685:     //
        !           686:     // Recall that the interval timer dpc can be lurking in some
        !           687:     // DPC queue.
        !           688:     //
        !           689: 
        !           690:     extension->CountOnLastRead = SERIAL_COMPLETE_READ_COMPLETE;
        !           691: 
        !           692:     SerialTryToCompleteCurrent(
        !           693:         extension,
        !           694:         NULL,
        !           695:         oldIrql,
        !           696:         STATUS_SUCCESS,
        !           697:         &extension->CurrentReadIrp,
        !           698:         &extension->ReadQueue,
        !           699:         &extension->ReadRequestIntervalTimer,
        !           700:         &extension->ReadRequestTotalTimer,
        !           701:         SerialStartRead,
        !           702:         SerialGetNextIrp
        !           703:         );
        !           704: 
        !           705: }
        !           706: 
        !           707: VOID
        !           708: SerialCancelCurrentRead(
        !           709:     PDEVICE_OBJECT DeviceObject,
        !           710:     PIRP Irp
        !           711:     )
        !           712: 
        !           713: /*++
        !           714: 
        !           715: Routine Description:
        !           716: 
        !           717:     This routine is used to cancel the current read.
        !           718: 
        !           719: Arguments:
        !           720: 
        !           721:     DeviceObject - Pointer to the device object for this device
        !           722: 
        !           723:     Irp - Pointer to the IRP to be canceled.
        !           724: 
        !           725: Return Value:
        !           726: 
        !           727:     None.
        !           728: 
        !           729: --*/
        !           730: 
        !           731: {
        !           732: 
        !           733:     PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
        !           734: 
        !           735:     //
        !           736:     // We set this to indicate to the interval timer
        !           737:     // that the read has encountered a cancel.
        !           738:     //
        !           739:     // Recall that the interval timer dpc can be lurking in some
        !           740:     // DPC queue.
        !           741:     //
        !           742: 
        !           743:     extension->CountOnLastRead = SERIAL_COMPLETE_READ_CANCEL;
        !           744: 
        !           745:     SerialTryToCompleteCurrent(
        !           746:         extension,
        !           747:         SerialGrabReadFromIsr,
        !           748:         Irp->CancelIrql,
        !           749:         STATUS_CANCELLED,
        !           750:         &extension->CurrentReadIrp,
        !           751:         &extension->ReadQueue,
        !           752:         &extension->ReadRequestIntervalTimer,
        !           753:         &extension->ReadRequestTotalTimer,
        !           754:         SerialStartRead,
        !           755:         SerialGetNextIrp
        !           756:         );
        !           757: 
        !           758: }
        !           759: 
        !           760: BOOLEAN
        !           761: SerialGrabReadFromIsr(
        !           762:     IN PVOID Context
        !           763:     )
        !           764: 
        !           765: /*++
        !           766: 
        !           767: Routine Description:
        !           768: 
        !           769:     This routine is used to grab (if possible) the irp from the
        !           770:     isr.  If it finds that the isr still owns the irp it grabs
        !           771:     the ipr away (updating the number of characters copied into the
        !           772:     users buffer).  If it grabs it away it also decrements the
        !           773:     reference count on the irp since it no longer belongs to the
        !           774:     isr (and the dpc that would complete it).
        !           775: 
        !           776:     NOTE: This routine assumes that if the current buffer that the
        !           777:           ISR is copying characters into is the interrupt buffer then
        !           778:           the dpc has already been queued.
        !           779: 
        !           780:     NOTE: This routine is being called from KeSynchronizeExecution.
        !           781: 
        !           782:     NOTE: This routine assumes that it is called with the cancel spin
        !           783:           lock held.
        !           784: 
        !           785: Arguments:
        !           786: 
        !           787:     Context - Really a pointer to the device extension.
        !           788: 
        !           789: Return Value:
        !           790: 
        !           791:     Always false.
        !           792: 
        !           793: --*/
        !           794: 
        !           795: {
        !           796: 
        !           797:     PSERIAL_DEVICE_EXTENSION extension = Context;
        !           798: 
        !           799:     if (extension->ReadBufferBase !=
        !           800:         extension->InterruptReadBuffer) {
        !           801: 
        !           802:         //
        !           803:         // We need to set the information to the number of characters
        !           804:         // that the read wanted minus the number of characters that
        !           805:         // didn't get read into the interrupt buffer.
        !           806:         //
        !           807: 
        !           808:         extension->CurrentReadIrp->IoStatus.Information =
        !           809:             IoGetCurrentIrpStackLocation(
        !           810:                 extension->CurrentReadIrp
        !           811:                 )->Parameters.Read.Length -
        !           812:             ((extension->LastCharSlot - extension->CurrentCharSlot) + 1);
        !           813: 
        !           814:         //
        !           815:         // Switch back to the interrupt buffer.
        !           816:         //
        !           817: 
        !           818:         extension->ReadBufferBase = extension->InterruptReadBuffer;
        !           819:         extension->CurrentCharSlot = extension->InterruptReadBuffer;
        !           820:         extension->FirstReadableChar = extension->InterruptReadBuffer;
        !           821:         extension->LastCharSlot = extension->InterruptReadBuffer +
        !           822:                                       (extension->BufferSize - 1);
        !           823:         extension->CharsInInterruptBuffer = 0;
        !           824: 
        !           825:         SERIAL_DEC_REFERENCE(extension->CurrentReadIrp);
        !           826: 
        !           827:     }
        !           828: 
        !           829:     return FALSE;
        !           830: 
        !           831: }
        !           832: 
        !           833: VOID
        !           834: SerialReadTimeout(
        !           835:     IN PKDPC Dpc,
        !           836:     IN PVOID DeferredContext,
        !           837:     IN PVOID SystemContext1,
        !           838:     IN PVOID SystemContext2
        !           839:     )
        !           840: 
        !           841: /*++
        !           842: 
        !           843: Routine Description:
        !           844: 
        !           845:     This routine is used to complete a read because its total
        !           846:     timer has expired.
        !           847: 
        !           848: Arguments:
        !           849: 
        !           850:     Dpc - Not Used.
        !           851: 
        !           852:     DeferredContext - Really points to the device extension.
        !           853: 
        !           854:     SystemContext1 - Not Used.
        !           855: 
        !           856:     SystemContext2 - Not Used.
        !           857: 
        !           858: Return Value:
        !           859: 
        !           860:     None.
        !           861: 
        !           862: --*/
        !           863: 
        !           864: {
        !           865: 
        !           866:     PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
        !           867:     KIRQL oldIrql;
        !           868: 
        !           869:     UNREFERENCED_PARAMETER(Dpc);
        !           870:     UNREFERENCED_PARAMETER(SystemContext1);
        !           871:     UNREFERENCED_PARAMETER(SystemContext2);
        !           872: 
        !           873:     IoAcquireCancelSpinLock(&oldIrql);
        !           874: 
        !           875:     //
        !           876:     // We set this to indicate to the interval timer
        !           877:     // that the read has completed due to total timeout.
        !           878:     //
        !           879:     // Recall that the interval timer dpc can be lurking in some
        !           880:     // DPC queue.
        !           881:     //
        !           882: 
        !           883:     extension->CountOnLastRead = SERIAL_COMPLETE_READ_TOTAL;
        !           884: 
        !           885:     SerialTryToCompleteCurrent(
        !           886:         extension,
        !           887:         SerialGrabReadFromIsr,
        !           888:         oldIrql,
        !           889:         STATUS_TIMEOUT,
        !           890:         &extension->CurrentReadIrp,
        !           891:         &extension->ReadQueue,
        !           892:         &extension->ReadRequestIntervalTimer,
        !           893:         &extension->ReadRequestTotalTimer,
        !           894:         SerialStartRead,
        !           895:         SerialGetNextIrp
        !           896:         );
        !           897: 
        !           898: }
        !           899: 
        !           900: BOOLEAN
        !           901: SerialUpdateReadByIsr(
        !           902:     IN PVOID Context
        !           903:     )
        !           904: 
        !           905: /*++
        !           906: 
        !           907: Routine Description:
        !           908: 
        !           909:     This routine is used to update the count of characters read
        !           910:     by the isr since the last interval timer experation.
        !           911: 
        !           912:     NOTE: This routine is being called from KeSynchronizeExecution.
        !           913: 
        !           914:     NOTE: This routine assumes that it is called with the cancel spin
        !           915:           lock held.
        !           916: 
        !           917: Arguments:
        !           918: 
        !           919:     Context - Really a pointer to the device extension.
        !           920: 
        !           921: Return Value:
        !           922: 
        !           923:     Always false.
        !           924: 
        !           925: --*/
        !           926: 
        !           927: {
        !           928: 
        !           929:     PSERIAL_DEVICE_EXTENSION extension = Context;
        !           930: 
        !           931:     extension->CountOnLastRead = extension->ReadByIsr;
        !           932:     extension->ReadByIsr = 0;
        !           933: 
        !           934:     return FALSE;
        !           935: 
        !           936: }
        !           937: 
        !           938: VOID
        !           939: SerialIntervalReadTimeout(
        !           940:     IN PKDPC Dpc,
        !           941:     IN PVOID DeferredContext,
        !           942:     IN PVOID SystemContext1,
        !           943:     IN PVOID SystemContext2
        !           944:     )
        !           945: 
        !           946: /*++
        !           947: 
        !           948: Routine Description:
        !           949: 
        !           950:     This routine is used timeout the request if the time between
        !           951:     characters exceed the interval time.  A global is kept in
        !           952:     the device extension that records the count of characters read
        !           953:     the last the last time this routine was invoked (This dpc
        !           954:     will resubmit the timer if the count has changed).  If the
        !           955:     count has not changed then this routine will attempt to complete
        !           956:     the irp.  Note the special case of the last count being zero.
        !           957:     The timer isn't really in effect until the first character is
        !           958:     read.
        !           959: 
        !           960: Arguments:
        !           961: 
        !           962:     Dpc - Not Used.
        !           963: 
        !           964:     DeferredContext - Really points to the device extension.
        !           965: 
        !           966:     SystemContext1 - Not Used.
        !           967: 
        !           968:     SystemContext2 - Not Used.
        !           969: 
        !           970: Return Value:
        !           971: 
        !           972:     None.
        !           973: 
        !           974: --*/
        !           975: 
        !           976: {
        !           977: 
        !           978:     PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
        !           979:     KIRQL oldIrql;
        !           980: 
        !           981:     UNREFERENCED_PARAMETER(Dpc);
        !           982:     UNREFERENCED_PARAMETER(SystemContext1);
        !           983:     UNREFERENCED_PARAMETER(SystemContext2);
        !           984: 
        !           985:     IoAcquireCancelSpinLock(&oldIrql);
        !           986: 
        !           987:     if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_TOTAL) {
        !           988: 
        !           989:         //
        !           990:         // This value is only set by the total
        !           991:         // timer to indicate that it has fired.
        !           992:         // If so, then we should simply try to complete.
        !           993:         //
        !           994: 
        !           995:         SerialTryToCompleteCurrent(
        !           996:             extension,
        !           997:             SerialGrabReadFromIsr,
        !           998:             oldIrql,
        !           999:             STATUS_TIMEOUT,
        !          1000:             &extension->CurrentReadIrp,
        !          1001:             &extension->ReadQueue,
        !          1002:             &extension->ReadRequestIntervalTimer,
        !          1003:             &extension->ReadRequestTotalTimer,
        !          1004:             SerialStartRead,
        !          1005:             SerialGetNextIrp
        !          1006:             );
        !          1007: 
        !          1008:     } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_COMPLETE) {
        !          1009: 
        !          1010:         //
        !          1011:         // This value is only set by the regular
        !          1012:         // completion routine.
        !          1013:         //
        !          1014:         // If so, then we should simply try to complete.
        !          1015:         //
        !          1016: 
        !          1017:         SerialTryToCompleteCurrent(
        !          1018:             extension,
        !          1019:             SerialGrabReadFromIsr,
        !          1020:             oldIrql,
        !          1021:             STATUS_SUCCESS,
        !          1022:             &extension->CurrentReadIrp,
        !          1023:             &extension->ReadQueue,
        !          1024:             &extension->ReadRequestIntervalTimer,
        !          1025:             &extension->ReadRequestTotalTimer,
        !          1026:             SerialStartRead,
        !          1027:             SerialGetNextIrp
        !          1028:             );
        !          1029: 
        !          1030:     } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_CANCEL) {
        !          1031: 
        !          1032:         //
        !          1033:         // This value is only set by the cancel
        !          1034:         // read routine.
        !          1035:         //
        !          1036:         // If so, then we should simply try to complete.
        !          1037:         //
        !          1038: 
        !          1039:         SerialTryToCompleteCurrent(
        !          1040:             extension,
        !          1041:             SerialGrabReadFromIsr,
        !          1042:             oldIrql,
        !          1043:             STATUS_CANCELLED,
        !          1044:             &extension->CurrentReadIrp,
        !          1045:             &extension->ReadQueue,
        !          1046:             &extension->ReadRequestIntervalTimer,
        !          1047:             &extension->ReadRequestTotalTimer,
        !          1048:             SerialStartRead,
        !          1049:             SerialGetNextIrp
        !          1050:             );
        !          1051: 
        !          1052:     } else if (extension->CountOnLastRead || extension->ReadByIsr) {
        !          1053: 
        !          1054:         //
        !          1055:         // Something has happened since we last came here.  We
        !          1056:         // check to see if the ISR has read in any more characters.
        !          1057:         // If it did then we should update the isr's read count
        !          1058:         // and resubmit the timer.
        !          1059:         //
        !          1060: 
        !          1061:         if (extension->ReadByIsr) {
        !          1062: 
        !          1063:             KeSynchronizeExecution(
        !          1064:                 extension->Interrupt,
        !          1065:                 SerialUpdateReadByIsr,
        !          1066:                 extension
        !          1067:                 );
        !          1068: 
        !          1069:             //
        !          1070:             // Save off the "last" time something was read.
        !          1071:             // As we come back to this routine we will compare
        !          1072:             // the current time to the "last" time.  If the
        !          1073:             // difference is ever larger then the interval
        !          1074:             // requested by the user, then time out the request.
        !          1075:             //
        !          1076: 
        !          1077:             KeQuerySystemTime(
        !          1078:                 &extension->LastReadTime
        !          1079:                 );
        !          1080: 
        !          1081:             KeSetTimer(
        !          1082:                 &extension->ReadRequestIntervalTimer,
        !          1083:                 *extension->IntervalTimeToUse,
        !          1084:                 &extension->IntervalReadTimeoutDpc
        !          1085:                 );
        !          1086: 
        !          1087:             IoReleaseCancelSpinLock(oldIrql);
        !          1088: 
        !          1089:         } else {
        !          1090: 
        !          1091:             //
        !          1092:             // Take the difference between the current time
        !          1093:             // and the last time we had characters and
        !          1094:             // see if it is greater then the interval time.
        !          1095:             // if it is, then time out the request.  Otherwise
        !          1096:             // go away again for a while.
        !          1097:             //
        !          1098: 
        !          1099:             //
        !          1100:             // No characters read in the interval time.  Kill
        !          1101:             // this read.
        !          1102:             //
        !          1103: 
        !          1104:             LARGE_INTEGER currentTime;
        !          1105: 
        !          1106:             KeQuerySystemTime(
        !          1107:                 &currentTime
        !          1108:                 );
        !          1109: 
        !          1110:             if (RtlLargeIntegerGreaterThanOrEqualTo(
        !          1111:                     RtlLargeIntegerSubtract(
        !          1112:                         currentTime,
        !          1113:                         extension->LastReadTime
        !          1114:                         ),
        !          1115:                     extension->IntervalTime
        !          1116:                     )) {
        !          1117: 
        !          1118:                 SerialTryToCompleteCurrent(
        !          1119:                     extension,
        !          1120:                     SerialGrabReadFromIsr,
        !          1121:                     oldIrql,
        !          1122:                     STATUS_TIMEOUT,
        !          1123:                     &extension->CurrentReadIrp,
        !          1124:                     &extension->ReadQueue,
        !          1125:                     &extension->ReadRequestIntervalTimer,
        !          1126:                     &extension->ReadRequestTotalTimer,
        !          1127:                     SerialStartRead,
        !          1128:                     SerialGetNextIrp
        !          1129:                     );
        !          1130: 
        !          1131:             } else {
        !          1132: 
        !          1133:                 KeSetTimer(
        !          1134:                     &extension->ReadRequestIntervalTimer,
        !          1135:                     *extension->IntervalTimeToUse,
        !          1136:                     &extension->IntervalReadTimeoutDpc
        !          1137:                     );
        !          1138:                 IoReleaseCancelSpinLock(oldIrql);
        !          1139: 
        !          1140:             }
        !          1141: 
        !          1142: 
        !          1143:         }
        !          1144: 
        !          1145:     } else {
        !          1146: 
        !          1147:         //
        !          1148:         // Timer doesn't really start until the first character.
        !          1149:         // So we should simply resubmit ourselves.
        !          1150:         //
        !          1151: 
        !          1152:         KeSetTimer(
        !          1153:             &extension->ReadRequestIntervalTimer,
        !          1154:             *extension->IntervalTimeToUse,
        !          1155:             &extension->IntervalReadTimeoutDpc
        !          1156:             );
        !          1157: 
        !          1158:         IoReleaseCancelSpinLock(oldIrql);
        !          1159: 
        !          1160:     }
        !          1161: 
        !          1162: 
        !          1163: }
        !          1164: 
        !          1165: ULONG
        !          1166: SerialGetCharsFromIntBuffer(
        !          1167:     PSERIAL_DEVICE_EXTENSION Extension
        !          1168:     )
        !          1169: 
        !          1170: /*++
        !          1171: 
        !          1172: Routine Description:
        !          1173: 
        !          1174:     This routine is used to copy any characters out of the interrupt
        !          1175:     buffer into the users buffer.  It will be reading values that
        !          1176:     are updated with the ISR but this is safe since this value is
        !          1177:     only decremented by synchronization routines.  This routine will
        !          1178:     return the number of characters copied so some other routine
        !          1179:     can call a synchronization routine to update what is seen at
        !          1180:     interrupt level.
        !          1181: 
        !          1182: Arguments:
        !          1183: 
        !          1184:     Extension - A pointer to the device extension.
        !          1185: 
        !          1186: Return Value:
        !          1187: 
        !          1188:     The number of characters that were copied into the user
        !          1189:     buffer.
        !          1190: 
        !          1191: --*/
        !          1192: 
        !          1193: {
        !          1194: 
        !          1195:     //
        !          1196:     // This value will be the number of characters that this
        !          1197:     // routine returns.  It will be the minimum of the number
        !          1198:     // of characters currently in the buffer or the number of
        !          1199:     // characters required for the read.
        !          1200:     //
        !          1201:     ULONG numberOfCharsToGet;
        !          1202: 
        !          1203:     //
        !          1204:     // This holds the number of characters between the first
        !          1205:     // readable character and - the last character we will read or
        !          1206:     // the real physical end of the buffer (not the last readable
        !          1207:     // character).
        !          1208:     //
        !          1209:     ULONG firstTryNumberToGet;
        !          1210: 
        !          1211: 
        !          1212:     //
        !          1213:     // The minimum of the number of characters we need and
        !          1214:     // the number of characters available
        !          1215:     //
        !          1216: 
        !          1217:     numberOfCharsToGet = Extension->CharsInInterruptBuffer;
        !          1218: 
        !          1219:     if (numberOfCharsToGet > Extension->NumberNeededForRead) {
        !          1220: 
        !          1221:         numberOfCharsToGet = Extension->NumberNeededForRead;
        !          1222: 
        !          1223:     }
        !          1224: 
        !          1225:     if (numberOfCharsToGet) {
        !          1226: 
        !          1227:         //
        !          1228:         // This will hold the number of characters between the
        !          1229:         // first available character and the end of the buffer.
        !          1230:         // Note that the buffer could wrap around but for the
        !          1231:         // purposes of the first copy we don't care about that.
        !          1232:         //
        !          1233: 
        !          1234:         firstTryNumberToGet = (Extension->LastCharSlot -
        !          1235:                                Extension->FirstReadableChar) + 1;
        !          1236: 
        !          1237:         if (firstTryNumberToGet > numberOfCharsToGet) {
        !          1238: 
        !          1239:             //
        !          1240:             // The characters don't wrap. Actually they may wrap but
        !          1241:             // we don't care for the purposes of this read since the
        !          1242:             // characters we need are available before the wrap.
        !          1243:             //
        !          1244: 
        !          1245:             RtlMoveMemory(
        !          1246:                 ((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
        !          1247:                     + (IoGetCurrentIrpStackLocation(
        !          1248:                            Extension->CurrentReadIrp
        !          1249:                            )->Parameters.Read.Length
        !          1250:                        - Extension->NumberNeededForRead
        !          1251:                       ),
        !          1252:                 Extension->FirstReadableChar,
        !          1253:                 numberOfCharsToGet
        !          1254:                 );
        !          1255: 
        !          1256:             Extension->NumberNeededForRead -= numberOfCharsToGet;
        !          1257: 
        !          1258:             //
        !          1259:             // We now will move the pointer to the first character after
        !          1260:             // what we just copied into the users buffer.
        !          1261:             //
        !          1262:             // We need to check if the stream of readable characters
        !          1263:             // is wrapping around to the beginning of the buffer.
        !          1264:             //
        !          1265:             // Note that we may have just taken the last characters
        !          1266:             // at the end of the buffer.
        !          1267:             //
        !          1268: 
        !          1269:             if ((Extension->FirstReadableChar + (numberOfCharsToGet - 1)) ==
        !          1270:                 Extension->LastCharSlot) {
        !          1271: 
        !          1272:                 Extension->FirstReadableChar = Extension->InterruptReadBuffer;
        !          1273: 
        !          1274:             } else {
        !          1275: 
        !          1276:                 Extension->FirstReadableChar += numberOfCharsToGet;
        !          1277: 
        !          1278:             }
        !          1279: 
        !          1280:         } else {
        !          1281: 
        !          1282:             //
        !          1283:             // The characters do wrap.  Get up until the end of the buffer.
        !          1284:             //
        !          1285: 
        !          1286:             RtlMoveMemory(
        !          1287:                 ((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
        !          1288:                     + (IoGetCurrentIrpStackLocation(
        !          1289:                            Extension->CurrentReadIrp
        !          1290:                            )->Parameters.Read.Length
        !          1291:                        - Extension->NumberNeededForRead
        !          1292:                       ),
        !          1293:                 Extension->FirstReadableChar,
        !          1294:                 firstTryNumberToGet
        !          1295:                 );
        !          1296: 
        !          1297:             Extension->NumberNeededForRead -= firstTryNumberToGet;
        !          1298: 
        !          1299:             //
        !          1300:             // Now get the rest of the characters from the beginning of the
        !          1301:             // buffer.
        !          1302:             //
        !          1303: 
        !          1304:             RtlMoveMemory(
        !          1305:                 ((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
        !          1306:                     + (IoGetCurrentIrpStackLocation(
        !          1307:                            Extension->CurrentReadIrp
        !          1308:                            )->Parameters.Read.Length
        !          1309:                        - Extension->NumberNeededForRead
        !          1310:                       ),
        !          1311:                 Extension->InterruptReadBuffer,
        !          1312:                 numberOfCharsToGet - firstTryNumberToGet
        !          1313:                 );
        !          1314: 
        !          1315:             Extension->FirstReadableChar = Extension->InterruptReadBuffer +
        !          1316:                                            (numberOfCharsToGet -
        !          1317:                                             firstTryNumberToGet);
        !          1318: 
        !          1319:             Extension->NumberNeededForRead -= (numberOfCharsToGet -
        !          1320:                                                firstTryNumberToGet);
        !          1321: 
        !          1322:         }
        !          1323: 
        !          1324:     }
        !          1325: 
        !          1326:     Extension->CurrentReadIrp->IoStatus.Information += numberOfCharsToGet;
        !          1327:     return numberOfCharsToGet;
        !          1328: 
        !          1329: }
        !          1330: 
        !          1331: BOOLEAN
        !          1332: SerialUpdateInterruptBuffer(
        !          1333:     IN PVOID Context
        !          1334:     )
        !          1335: 
        !          1336: /*++
        !          1337: 
        !          1338: Routine Description:
        !          1339: 
        !          1340:     This routine is used to update the number of characters that
        !          1341:     remain in the interrupt buffer.  We need to use this routine
        !          1342:     since the count could be updated during the update by execution
        !          1343:     of the ISR.
        !          1344: 
        !          1345:     NOTE: This is called by KeSynchronizeExecution.
        !          1346: 
        !          1347: Arguments:
        !          1348: 
        !          1349:     Context - Points to a structure that contains a pointer to the
        !          1350:               device extension and count of the number of characters
        !          1351:               that we previously copied into the users buffer.  The
        !          1352:               structure actually has a third field that we don't
        !          1353:               use in this routine.
        !          1354: 
        !          1355: Return Value:
        !          1356: 
        !          1357:     Always FALSE.
        !          1358: 
        !          1359: --*/
        !          1360: 
        !          1361: {
        !          1362: 
        !          1363:     PSERIAL_UPDATE_CHAR update = Context;
        !          1364:     PSERIAL_DEVICE_EXTENSION extension = update->Extension;
        !          1365: 
        !          1366:     ASSERT(extension->CharsInInterruptBuffer >= update->CharsCopied);
        !          1367:     extension->CharsInInterruptBuffer -= update->CharsCopied;
        !          1368: 
        !          1369:     //
        !          1370:     // Deal with flow control if necessary.
        !          1371:     //
        !          1372: 
        !          1373:     SerialHandleReducedIntBuffer(extension);
        !          1374: 
        !          1375: 
        !          1376:     return FALSE;
        !          1377: 
        !          1378: }
        !          1379: 
        !          1380: BOOLEAN
        !          1381: SerialUpdateAndSwitchToUser(
        !          1382:     IN PVOID Context
        !          1383:     )
        !          1384: 
        !          1385: /*++
        !          1386: 
        !          1387: Routine Description:
        !          1388: 
        !          1389:     This routine gets the (hopefully) few characters that
        !          1390:     remain in the interrupt buffer after the first time we tried
        !          1391:     to get them out.  If we still don't have enough characters
        !          1392:     to satisfy the read it will then we set things up so that the
        !          1393:     ISR uses the user buffer copy into.
        !          1394: 
        !          1395:     This routine is also used to update a count that is maintained
        !          1396:     by the ISR to keep track of the number of characters in its buffer.
        !          1397: 
        !          1398:     NOTE: This is called by KeSynchronizeExecution.
        !          1399: 
        !          1400: Arguments:
        !          1401: 
        !          1402:     Context - Points to a structure that contains a pointer to the
        !          1403:               device extension, a count of the number of characters
        !          1404:               that we previously copied into the users buffer, and
        !          1405:               a boolean that we will set that defines whether we
        !          1406:               switched the ISR to copy into the users buffer.
        !          1407: 
        !          1408: Return Value:
        !          1409: 
        !          1410:     Always FALSE.
        !          1411: 
        !          1412: --*/
        !          1413: 
        !          1414: {
        !          1415: 
        !          1416:     PSERIAL_UPDATE_CHAR updateChar = Context;
        !          1417:     PSERIAL_DEVICE_EXTENSION extension = updateChar->Extension;
        !          1418: 
        !          1419:     SerialUpdateInterruptBuffer(Context);
        !          1420: 
        !          1421:     //
        !          1422:     // There are more characters to get to satisfy this read.
        !          1423:     // Copy any characters that have arrived since we got
        !          1424:     // the last batch.
        !          1425:     //
        !          1426: 
        !          1427:     updateChar->CharsCopied = SerialGetCharsFromIntBuffer(extension);
        !          1428: 
        !          1429:     SerialUpdateInterruptBuffer(Context);
        !          1430: 
        !          1431:     //
        !          1432:     // No more new characters will be "received" until we exit
        !          1433:     // this routine.  We again check to make sure that we
        !          1434:     // haven't satisfied this read, and if we haven't we set things
        !          1435:     // up so that the ISR copies into the user buffer.
        !          1436:     //
        !          1437: 
        !          1438:     if (extension->NumberNeededForRead) {
        !          1439: 
        !          1440:         //
        !          1441:         // We shouldn't be switching unless there are no
        !          1442:         // characters left.
        !          1443:         //
        !          1444: 
        !          1445:         ASSERT(!extension->CharsInInterruptBuffer);
        !          1446: 
        !          1447:         //
        !          1448:         // We use the following to values to do inteval timing.
        !          1449:         //
        !          1450:         // CountOnLastRead is mostly used to simply prevent
        !          1451:         // the interval timer from timing out before any characters
        !          1452:         // are read. (Interval timing should only be effective
        !          1453:         // after the first character is read.)
        !          1454:         //
        !          1455:         // After the first time the interval timer fires and
        !          1456:         // characters have be read we will simply update with
        !          1457:         // the value of ReadByIsr and then set ReadByIsr to zero.
        !          1458:         // (We do that in a synchronization routine.
        !          1459:         //
        !          1460:         // If the interval timer dpc routine ever encounters
        !          1461:         // ReadByIsr == 0 when CountOnLastRead is non-zero it
        !          1462:         // will timeout the read.
        !          1463:         //
        !          1464:         // (Note that we have a special case of CountOnLastRead
        !          1465:         // < 0.  This is done by the read completion routines other
        !          1466:         // than the total timeout dpc to indicate that the total
        !          1467:         // timeout has expired.)
        !          1468:         //
        !          1469: 
        !          1470:         extension->CountOnLastRead =
        !          1471:             extension->CurrentReadIrp->IoStatus.Information;
        !          1472: 
        !          1473:         extension->ReadByIsr = 0;
        !          1474: 
        !          1475:         //
        !          1476:         // By compareing the read buffer base address to the
        !          1477:         // the base address of the interrupt buffer the ISR
        !          1478:         // can determine whether we are using the interrupt
        !          1479:         // buffer or the user buffer.
        !          1480:         //
        !          1481: 
        !          1482:         extension->ReadBufferBase =
        !          1483:             extension->CurrentReadIrp->AssociatedIrp.SystemBuffer;
        !          1484: 
        !          1485:         //
        !          1486:         // The current char slot is after the last copied in
        !          1487:         // character.  We know there is always room since we
        !          1488:         // we wouldn't have gotten here if there wasn't.
        !          1489:         //
        !          1490: 
        !          1491:         extension->CurrentCharSlot = extension->ReadBufferBase +
        !          1492:             extension->CurrentReadIrp->IoStatus.Information;
        !          1493: 
        !          1494:         //
        !          1495:         // The last position that a character can go is on the
        !          1496:         // last byte of user buffer.  While the actual allocated
        !          1497:         // buffer space may be bigger, we know that there is at
        !          1498:         // least as much as the read length.
        !          1499:         //
        !          1500: 
        !          1501:         extension->LastCharSlot = extension->ReadBufferBase +
        !          1502:                                       (IoGetCurrentIrpStackLocation(
        !          1503:                                           extension->CurrentReadIrp
        !          1504:                                           )->Parameters.Read.Length
        !          1505:                                        - 1);
        !          1506: 
        !          1507:         //
        !          1508:         // Mark the irp as being in a cancelable state.
        !          1509:         //
        !          1510: 
        !          1511:         IoSetCancelRoutine(
        !          1512:             extension->CurrentReadIrp,
        !          1513:             SerialCancelCurrentRead
        !          1514:             );
        !          1515: 
        !          1516:         //
        !          1517:         // Increment the reference count twice.
        !          1518:         //
        !          1519:         // Once for the Isr owning the irp and once
        !          1520:         // because the cancel routine has a reference
        !          1521:         // to it.
        !          1522:         //
        !          1523: 
        !          1524:         SERIAL_INC_REFERENCE(extension->CurrentReadIrp);
        !          1525:         SERIAL_INC_REFERENCE(extension->CurrentReadIrp);
        !          1526: 
        !          1527:         updateChar->Completed = FALSE;
        !          1528: 
        !          1529:     } else {
        !          1530: 
        !          1531:         updateChar->Completed = TRUE;
        !          1532: 
        !          1533:     }
        !          1534: 
        !          1535:     return FALSE;
        !          1536: 
        !          1537: }
        !          1538: //
        !          1539: // We use this structure only to communicate to the synchronization
        !          1540: // routine when we are switching to the resized buffer.
        !          1541: //
        !          1542: typedef struct _SERIAL_RESIZE_PARAMS {
        !          1543:     PSERIAL_DEVICE_EXTENSION Extension;
        !          1544:     PUCHAR OldBuffer;
        !          1545:     PUCHAR NewBuffer;
        !          1546:     ULONG NewBufferSize;
        !          1547:     ULONG NumberMoved;
        !          1548:     } SERIAL_RESIZE_PARAMS,*PSERIAL_RESIZE_PARAMS;
        !          1549: 
        !          1550: NTSTATUS
        !          1551: SerialResizeBuffer(
        !          1552:     IN PSERIAL_DEVICE_EXTENSION Extension
        !          1553:     )
        !          1554: 
        !          1555: /*++
        !          1556: 
        !          1557: Routine Description:
        !          1558: 
        !          1559:     This routine will process the resize buffer request.
        !          1560:     If size requested for the RX buffer is smaller than
        !          1561:     the current buffer then we will simply return
        !          1562:     STATUS_SUCCESS.  (We don't want to make buffers smaller.
        !          1563:     If we did that then we all of a sudden have "overrun"
        !          1564:     problems to deal with as well as flow control to deal
        !          1565:     with - very painful.)  We ignore the TX buffer size
        !          1566:     request since we don't use a TX buffer.
        !          1567: 
        !          1568: Arguments:
        !          1569: 
        !          1570:     Extension - Pointer to the device extension for the port.
        !          1571: 
        !          1572: Return Value:
        !          1573: 
        !          1574:     STATUS_SUCCESS if everything worked out ok.
        !          1575:     STATUS_INSUFFICIENT_RESOURCES if we couldn't allocate the
        !          1576:     memory for the buffer.
        !          1577: 
        !          1578: --*/
        !          1579: 
        !          1580: {
        !          1581: 
        !          1582:     PSERIAL_QUEUE_SIZE rs = Extension->CurrentReadIrp->AssociatedIrp
        !          1583:                                                        .SystemBuffer;
        !          1584:     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(
        !          1585:                                    Extension->CurrentReadIrp
        !          1586:                                    );
        !          1587:     PVOID newBuffer = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
        !          1588: 
        !          1589:     irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
        !          1590:     Extension->CurrentReadIrp->IoStatus.Information = 0L;
        !          1591:     Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
        !          1592: 
        !          1593:     if (rs->InSize <= Extension->BufferSize) {
        !          1594: 
        !          1595:         //
        !          1596:         // Nothing to do.  We don't make buffers smaller.  Just
        !          1597:         // agree with the user.  We must deallocate the memory
        !          1598:         // that was already allocated in the ioctl dispatch routine.
        !          1599:         //
        !          1600: 
        !          1601:         ExFreePool(newBuffer);
        !          1602: 
        !          1603:     } else {
        !          1604: 
        !          1605:         SERIAL_RESIZE_PARAMS rp;
        !          1606:         KIRQL controlIrql;
        !          1607: 
        !          1608:         //
        !          1609:         // Hmmm, looks like we actually have to go
        !          1610:         // through with this.  We need to move all the
        !          1611:         // data that is in the current buffer into this
        !          1612:         // new buffer.  We'll do this in two steps.
        !          1613:         //
        !          1614:         // First we go up to dispatch level and try to
        !          1615:         // move as much as we can without stopping the
        !          1616:         // ISR from running.  We go up to dispatch level
        !          1617:         // by acquiring the control lock.  We do it at
        !          1618:         // dispatch using the control lock so that:
        !          1619:         //
        !          1620:         //    1) We can't be context switched in the middle
        !          1621:         //       of the move.  Our pointers into the buffer
        !          1622:         //       could be *VERY* stale by the time we got back.
        !          1623:         //
        !          1624:         //    2) We use the control lock since we don't want
        !          1625:         //       some pesky purge irp to come along while
        !          1626:         //       we are trying to move.
        !          1627:         //
        !          1628:         // After the move, but while we still hold the control
        !          1629:         // lock, we synch with the ISR and get those last
        !          1630:         // (hopefully) few characters that have come in since
        !          1631:         // we started the copy.  We switch all of our pointers,
        !          1632:         // counters, and such to point to this new buffer.  NOTE:
        !          1633:         // we need to be careful.  If the buffer we were using
        !          1634:         // was not the default one created when we initialized
        !          1635:         // the device (i.e. it was created via a previous IRP of
        !          1636:         // this type), we should deallocate it.
        !          1637:         //
        !          1638: 
        !          1639:         rp.Extension = Extension;
        !          1640:         rp.OldBuffer = Extension->InterruptReadBuffer;
        !          1641:         rp.NewBuffer = newBuffer;
        !          1642:         rp.NewBufferSize = rs->InSize;
        !          1643: 
        !          1644:         KeAcquireSpinLock(
        !          1645:             &Extension->ControlLock,
        !          1646:             &controlIrql
        !          1647:             );
        !          1648: 
        !          1649:         rp.NumberMoved = SerialMoveToNewIntBuffer(
        !          1650:                              Extension,
        !          1651:                              newBuffer
        !          1652:                              );
        !          1653: 
        !          1654:         KeSynchronizeExecution(
        !          1655:             Extension->Interrupt,
        !          1656:             SerialUpdateAndSwitchToNew,
        !          1657:             &rp
        !          1658:             );
        !          1659: 
        !          1660:         KeReleaseSpinLock(
        !          1661:             &Extension->ControlLock,
        !          1662:             controlIrql
        !          1663:             );
        !          1664: 
        !          1665:         //
        !          1666:         // Free up the memory that the old buffer consumed.
        !          1667:         //
        !          1668: 
        !          1669:         ExFreePool(rp.OldBuffer);
        !          1670: 
        !          1671:     }
        !          1672: 
        !          1673:     return STATUS_SUCCESS;
        !          1674: 
        !          1675: }
        !          1676: 
        !          1677: ULONG
        !          1678: SerialMoveToNewIntBuffer(
        !          1679:     PSERIAL_DEVICE_EXTENSION Extension,
        !          1680:     PUCHAR NewBuffer
        !          1681:     )
        !          1682: 
        !          1683: /*++
        !          1684: 
        !          1685: Routine Description:
        !          1686: 
        !          1687:     This routine is used to copy any characters out of the interrupt
        !          1688:     buffer into the "new" buffer.  It will be reading values that
        !          1689:     are updated with the ISR but this is safe since this value is
        !          1690:     only decremented by synchronization routines.  This routine will
        !          1691:     return the number of characters copied so some other routine
        !          1692:     can call a synchronization routine to update what is seen at
        !          1693:     interrupt level.
        !          1694: 
        !          1695: Arguments:
        !          1696: 
        !          1697:     Extension - A pointer to the device extension.
        !          1698:     NewBuffer - Where the characters are to be move to.
        !          1699: 
        !          1700: Return Value:
        !          1701: 
        !          1702:     The number of characters that were copied into the user
        !          1703:     buffer.
        !          1704: 
        !          1705: --*/
        !          1706: 
        !          1707: {
        !          1708: 
        !          1709:     ULONG numberOfCharsMoved = Extension->CharsInInterruptBuffer;
        !          1710: 
        !          1711:     if (numberOfCharsMoved) {
        !          1712: 
        !          1713:         //
        !          1714:         // This holds the number of characters between the first
        !          1715:         // readable character and the last character we will read or
        !          1716:         // the real physical end of the buffer (not the last readable
        !          1717:         // character).
        !          1718:         //
        !          1719:         ULONG firstTryNumberToGet = (Extension->LastCharSlot -
        !          1720:                                      Extension->FirstReadableChar) + 1;
        !          1721: 
        !          1722:         if (firstTryNumberToGet >= numberOfCharsMoved) {
        !          1723: 
        !          1724:             //
        !          1725:             // The characters don't wrap.
        !          1726:             //
        !          1727: 
        !          1728:             RtlMoveMemory(
        !          1729:                 NewBuffer,
        !          1730:                 Extension->FirstReadableChar,
        !          1731:                 numberOfCharsMoved
        !          1732:                 );
        !          1733: 
        !          1734:             if ((Extension->FirstReadableChar+(numberOfCharsMoved-1)) ==
        !          1735:                 Extension->LastCharSlot) {
        !          1736: 
        !          1737:                 Extension->FirstReadableChar = Extension->InterruptReadBuffer;
        !          1738: 
        !          1739:             } else {
        !          1740: 
        !          1741:                 Extension->FirstReadableChar += numberOfCharsMoved;
        !          1742: 
        !          1743:             }
        !          1744: 
        !          1745:         } else {
        !          1746: 
        !          1747:             //
        !          1748:             // The characters do wrap.  Get up until the end of the buffer.
        !          1749:             //
        !          1750: 
        !          1751:             RtlMoveMemory(
        !          1752:                 NewBuffer,
        !          1753:                 Extension->FirstReadableChar,
        !          1754:                 firstTryNumberToGet
        !          1755:                 );
        !          1756: 
        !          1757:             //
        !          1758:             // Now get the rest of the characters from the beginning of the
        !          1759:             // buffer.
        !          1760:             //
        !          1761: 
        !          1762:             RtlMoveMemory(
        !          1763:                 NewBuffer+firstTryNumberToGet,
        !          1764:                 Extension->InterruptReadBuffer,
        !          1765:                 numberOfCharsMoved - firstTryNumberToGet
        !          1766:                 );
        !          1767: 
        !          1768:             Extension->FirstReadableChar = Extension->InterruptReadBuffer +
        !          1769:                                    numberOfCharsMoved - firstTryNumberToGet;
        !          1770: 
        !          1771:         }
        !          1772: 
        !          1773:     }
        !          1774: 
        !          1775:     return numberOfCharsMoved;
        !          1776: 
        !          1777: }
        !          1778: 
        !          1779: BOOLEAN
        !          1780: SerialUpdateAndSwitchToNew(
        !          1781:     IN PVOID Context
        !          1782:     )
        !          1783: 
        !          1784: /*++
        !          1785: 
        !          1786: Routine Description:
        !          1787: 
        !          1788:     This routine gets the (hopefully) few characters that
        !          1789:     remain in the interrupt buffer after the first time we tried
        !          1790:     to get them out.
        !          1791: 
        !          1792:     NOTE: This is called by KeSynchronizeExecution.
        !          1793: 
        !          1794: Arguments:
        !          1795: 
        !          1796:     Context - Points to a structure that contains a pointer to the
        !          1797:               device extension, a pointer to the buffer we are moving
        !          1798:               to, and a count of the number of characters
        !          1799:               that we previously copied into the new buffer, and the
        !          1800:               actual size of the new buffer.
        !          1801: 
        !          1802: Return Value:
        !          1803: 
        !          1804:     Always FALSE.
        !          1805: 
        !          1806: --*/
        !          1807: 
        !          1808: {
        !          1809: 
        !          1810:     PSERIAL_RESIZE_PARAMS params = Context;
        !          1811:     PSERIAL_DEVICE_EXTENSION extension = params->Extension;
        !          1812:     ULONG tempCharsInInterruptBuffer = extension->CharsInInterruptBuffer;
        !          1813: 
        !          1814:     ASSERT(extension->CharsInInterruptBuffer >= params->NumberMoved);
        !          1815: 
        !          1816:     //
        !          1817:     // We temporarily reduce the chars in interrupt buffer to
        !          1818:     // "fool" the move routine.  We will restore it after the
        !          1819:     // move.
        !          1820:     //
        !          1821: 
        !          1822:     extension->CharsInInterruptBuffer -= params->NumberMoved;
        !          1823: 
        !          1824:     if (extension->CharsInInterruptBuffer) {
        !          1825: 
        !          1826:         SerialMoveToNewIntBuffer(
        !          1827:             extension,
        !          1828:             params->NewBuffer + params->NumberMoved
        !          1829:             );
        !          1830: 
        !          1831:     }
        !          1832: 
        !          1833:     extension->CharsInInterruptBuffer = tempCharsInInterruptBuffer;
        !          1834: 
        !          1835: 
        !          1836:     extension->LastCharSlot = params->NewBuffer + (params->NewBufferSize - 1);
        !          1837:     extension->FirstReadableChar = params->NewBuffer;
        !          1838:     extension->ReadBufferBase = params->NewBuffer;
        !          1839:     extension->InterruptReadBuffer = params->NewBuffer;
        !          1840:     extension->BufferSize = params->NewBufferSize;
        !          1841: 
        !          1842:     //
        !          1843:     // We *KNOW* that the new interrupt buffer is larger than the
        !          1844:     // old buffer.  We don't need to worry about it being full.
        !          1845:     //
        !          1846: 
        !          1847:     extension->CurrentCharSlot = extension->InterruptReadBuffer +
        !          1848:                                  extension->CharsInInterruptBuffer;
        !          1849: 
        !          1850:     //
        !          1851:     // We set up the default xon/xoff limits.
        !          1852:     //
        !          1853: 
        !          1854:     extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
        !          1855:     extension->HandFlow.XonLimit = extension->BufferSize >> 1;
        !          1856: 
        !          1857:     extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
        !          1858:                                    (extension->BufferSize>>4));
        !          1859: 
        !          1860:     //
        !          1861:     // Since we (essentially) reduced the percentage of the interrupt
        !          1862:     // buffer being full, we need to handle any flow control.
        !          1863:     //
        !          1864: 
        !          1865:     SerialHandleReducedIntBuffer(extension);
        !          1866: 
        !          1867:     return FALSE;
        !          1868: 
        !          1869: }

unix.superglobalmegacorp.com

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