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

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     modmflow.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This module contains *MOST* of the code used to manipulate
        !            12:     the modem control and status registers.  The vast majority
        !            13:     of the remainder of flow control is concentrated in the
        !            14:     Interrupt service routine.  A very small amount resides
        !            15:     in the read code that pull characters out of the interrupt
        !            16:     buffer.
        !            17: 
        !            18: Author:
        !            19: 
        !            20:     Anthony V. Ercolano 26-Sep-1991
        !            21: 
        !            22: Environment:
        !            23: 
        !            24:     Kernel mode
        !            25: 
        !            26: Revision History :
        !            27: 
        !            28: --*/
        !            29: 
        !            30: #include <stddef.h>
        !            31: #include "ntddk.h"
        !            32: #include "ntddser.h"
        !            33: #include "serial.h"
        !            34: #include "serialp.h"
        !            35: 
        !            36: BOOLEAN
        !            37: SerialDecrementRTSCounter(
        !            38:     IN PVOID Context
        !            39:     );
        !            40: 
        !            41: 
        !            42: BOOLEAN
        !            43: SerialSetDTR(
        !            44:     IN PVOID Context
        !            45:     )
        !            46: 
        !            47: /*++
        !            48: 
        !            49: Routine Description:
        !            50: 
        !            51:     This routine which is only called at interrupt level is used
        !            52:     to set the DTR in the modem control register.
        !            53: 
        !            54: Arguments:
        !            55: 
        !            56:     Context - Really a pointer to the device extension.
        !            57: 
        !            58: Return Value:
        !            59: 
        !            60:     This routine always returns FALSE.
        !            61: 
        !            62: --*/
        !            63: 
        !            64: {
        !            65: 
        !            66:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !            67:     UCHAR ModemControl;
        !            68: 
        !            69:     ModemControl = READ_MODEM_CONTROL(Extension->Controller);
        !            70: 
        !            71:     ModemControl |= SERIAL_MCR_DTR;
        !            72: 
        !            73:     SerialDump(
        !            74:         SERFLOW,
        !            75:         ("SERIAL: Setting DTR for %x\n",
        !            76:          Extension->Controller)
        !            77:         );
        !            78:     WRITE_MODEM_CONTROL(
        !            79:         Extension->Controller,
        !            80:         ModemControl
        !            81:         );
        !            82: 
        !            83:     return FALSE;
        !            84: 
        !            85: }
        !            86: 
        !            87: BOOLEAN
        !            88: SerialClrDTR(
        !            89:     IN PVOID Context
        !            90:     )
        !            91: 
        !            92: /*++
        !            93: 
        !            94: Routine Description:
        !            95: 
        !            96:     This routine which is only called at interrupt level is used
        !            97:     to clear the DTR in the modem control register.
        !            98: 
        !            99: Arguments:
        !           100: 
        !           101:     Context - Really a pointer to the device extension.
        !           102: 
        !           103: Return Value:
        !           104: 
        !           105:     This routine always returns FALSE.
        !           106: 
        !           107: --*/
        !           108: 
        !           109: {
        !           110: 
        !           111:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           112:     UCHAR ModemControl;
        !           113: 
        !           114:     ModemControl = READ_MODEM_CONTROL(Extension->Controller);
        !           115: 
        !           116:     ModemControl &= ~SERIAL_MCR_DTR;
        !           117: 
        !           118:     SerialDump(
        !           119:         SERFLOW,
        !           120:         ("SERIAL: Clearing DTR for %x\n",
        !           121:          Extension->Controller)
        !           122:         );
        !           123:     WRITE_MODEM_CONTROL(
        !           124:         Extension->Controller,
        !           125:         ModemControl
        !           126:         );
        !           127: 
        !           128:     return FALSE;
        !           129: 
        !           130: }
        !           131: 
        !           132: BOOLEAN
        !           133: SerialSetRTS(
        !           134:     IN PVOID Context
        !           135:     )
        !           136: 
        !           137: /*++
        !           138: 
        !           139: Routine Description:
        !           140: 
        !           141:     This routine which is only called at interrupt level is used
        !           142:     to set the RTS in the modem control register.
        !           143: 
        !           144: Arguments:
        !           145: 
        !           146:     Context - Really a pointer to the device extension.
        !           147: 
        !           148: Return Value:
        !           149: 
        !           150:     This routine always returns FALSE.
        !           151: 
        !           152: --*/
        !           153: 
        !           154: {
        !           155: 
        !           156:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           157:     UCHAR ModemControl;
        !           158: 
        !           159:     ModemControl = READ_MODEM_CONTROL(Extension->Controller);
        !           160: 
        !           161:     ModemControl |= SERIAL_MCR_RTS;
        !           162: 
        !           163:     SerialDump(
        !           164:         SERFLOW,
        !           165:         ("SERIAL: Setting Rts for %x\n",
        !           166:          Extension->Controller)
        !           167:         );
        !           168:     WRITE_MODEM_CONTROL(
        !           169:         Extension->Controller,
        !           170:         ModemControl
        !           171:         );
        !           172: 
        !           173:     return FALSE;
        !           174: 
        !           175: }
        !           176: 
        !           177: BOOLEAN
        !           178: SerialClrRTS(
        !           179:     IN PVOID Context
        !           180:     )
        !           181: 
        !           182: /*++
        !           183: 
        !           184: Routine Description:
        !           185: 
        !           186:     This routine which is only called at interrupt level is used
        !           187:     to clear the RTS in the modem control register.
        !           188: 
        !           189: Arguments:
        !           190: 
        !           191:     Context - Really a pointer to the device extension.
        !           192: 
        !           193: Return Value:
        !           194: 
        !           195:     This routine always returns FALSE.
        !           196: 
        !           197: --*/
        !           198: 
        !           199: {
        !           200: 
        !           201:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           202:     UCHAR ModemControl;
        !           203: 
        !           204:     ModemControl = READ_MODEM_CONTROL(Extension->Controller);
        !           205: 
        !           206:     ModemControl &= ~SERIAL_MCR_RTS;
        !           207: 
        !           208:     SerialDump(
        !           209:         SERFLOW,
        !           210:         ("SERIAL: Clearing Rts for %x\n",
        !           211:          Extension->Controller)
        !           212:         );
        !           213:     WRITE_MODEM_CONTROL(
        !           214:         Extension->Controller,
        !           215:         ModemControl
        !           216:         );
        !           217: 
        !           218:     return FALSE;
        !           219: 
        !           220: }
        !           221: 
        !           222: BOOLEAN
        !           223: SerialSetupNewHandFlow(
        !           224:     IN PSERIAL_DEVICE_EXTENSION Extension,
        !           225:     IN PSERIAL_HANDFLOW NewHandFlow
        !           226:     )
        !           227: 
        !           228: /*++
        !           229: 
        !           230: Routine Description:
        !           231: 
        !           232:     This routine adjusts the flow control based on new
        !           233:     control flow.
        !           234: 
        !           235: Arguments:
        !           236: 
        !           237:     Extension - A pointer to the serial device extension.
        !           238: 
        !           239:     NewHandFlow - A pointer to a serial handflow structure
        !           240:                   that is to become the new setup for flow
        !           241:                   control.
        !           242: 
        !           243: Return Value:
        !           244: 
        !           245:     This routine always returns FALSE.
        !           246: 
        !           247: --*/
        !           248: 
        !           249: {
        !           250: 
        !           251:     SERIAL_HANDFLOW New = *NewHandFlow;
        !           252: 
        !           253:     //
        !           254:     // If the Extension->DeviceIsOpened is FALSE that means
        !           255:     // we are entering this routine in response to an open request.
        !           256:     // If that is so, then we always proceed with the work regardless
        !           257:     // of whether things have changed.
        !           258:     //
        !           259: 
        !           260:     //
        !           261:     // First we take care of the DTR flow control.  We only
        !           262:     // do work if something has changed.
        !           263:     //
        !           264: 
        !           265:     if ((!Extension->DeviceIsOpened) ||
        !           266:         ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) !=
        !           267:          (New.ControlHandShake & SERIAL_DTR_MASK))) {
        !           268: 
        !           269:         SerialDump(
        !           270:             SERFLOW,
        !           271:             ("SERIAL: Processing DTR flow for %x\n",
        !           272:              Extension->Controller)
        !           273:             );
        !           274: 
        !           275:         if (New.ControlHandShake & SERIAL_DTR_MASK) {
        !           276: 
        !           277:             //
        !           278:             // Well we might want to set DTR.
        !           279:             //
        !           280:             // Before we do, we need to check whether we are doing
        !           281:             // dtr flow control.  If we are then we need to check
        !           282:             // if then number of characters in the interrupt buffer
        !           283:             // exceeds the XoffLimit.  If it does then we don't
        !           284:             // enable DTR AND we set the RXHolding to record that
        !           285:             // we are holding because of the dtr.
        !           286:             //
        !           287: 
        !           288:             if ((New.ControlHandShake & SERIAL_DTR_MASK)
        !           289:                 == SERIAL_DTR_HANDSHAKE) {
        !           290: 
        !           291:                 if ((Extension->BufferSize - New.XoffLimit) >
        !           292:                     Extension->CharsInInterruptBuffer) {
        !           293: 
        !           294:                     //
        !           295:                     // However if we are already holding we don't want
        !           296:                     // to turn it back on unless we exceed the Xon
        !           297:                     // limit.
        !           298:                     //
        !           299: 
        !           300:                     if (Extension->RXHolding & SERIAL_RX_DTR) {
        !           301: 
        !           302:                         //
        !           303:                         // We can assume that its DTR line is already low.
        !           304:                         //
        !           305: 
        !           306:                         if (Extension->CharsInInterruptBuffer >
        !           307:                             (ULONG)New.XonLimit) {
        !           308: 
        !           309:                             SerialDump(
        !           310:                                 SERFLOW,
        !           311:                                 ("SERIAL: Removing DTR block on reception for %x\n",
        !           312:                                  Extension->Controller)
        !           313:                                 );
        !           314:                             Extension->RXHolding &= ~SERIAL_RX_DTR;
        !           315:                             SerialSetDTR(Extension);
        !           316: 
        !           317:                         }
        !           318: 
        !           319:                     } else {
        !           320: 
        !           321:                         SerialSetDTR(Extension);
        !           322: 
        !           323:                     }
        !           324: 
        !           325:                 } else {
        !           326: 
        !           327:                     SerialDump(
        !           328:                         SERFLOW,
        !           329:                         ("SERIAL: Setting DTR block on reception for %x\n",
        !           330:                          Extension->Controller)
        !           331:                         );
        !           332:                     Extension->RXHolding |= SERIAL_RX_DTR;
        !           333:                     SerialClrDTR(Extension);
        !           334: 
        !           335:                 }
        !           336: 
        !           337:             } else {
        !           338: 
        !           339:                 //
        !           340:                 // Note that if we aren't currently doing dtr flow control then
        !           341:                 // we MIGHT have been.  So even if we aren't currently doing
        !           342:                 // DTR flow control, we should still check if RX is holding
        !           343:                 // because of DTR.  If it is, then we should clear the holding
        !           344:                 // of this bit.
        !           345:                 //
        !           346: 
        !           347:                 if (Extension->RXHolding & SERIAL_RX_DTR) {
        !           348: 
        !           349:                     SerialDump(
        !           350:                         SERFLOW,
        !           351:                         ("SERIAL: Removing dtr block of reception for %x\n",
        !           352:                         Extension->Controller)
        !           353:                         );
        !           354:                     Extension->RXHolding &= ~SERIAL_RX_DTR;
        !           355: 
        !           356:                 }
        !           357: 
        !           358:                 SerialSetDTR(Extension);
        !           359: 
        !           360:             }
        !           361: 
        !           362:         } else {
        !           363: 
        !           364:             //
        !           365:             // The end result here will be that DTR is cleared.
        !           366:             //
        !           367:             // We first need to check whether reception is being held
        !           368:             // up because of previous DTR flow control.  If it is then
        !           369:             // we should clear that reason in the RXHolding mask.
        !           370:             //
        !           371: 
        !           372:             if (Extension->RXHolding & SERIAL_RX_DTR) {
        !           373: 
        !           374:                 SerialDump(
        !           375:                     SERFLOW,
        !           376:                     ("SERIAL: removing dtr block of reception for %x\n",
        !           377:                     Extension->Controller)
        !           378:                     );
        !           379:                 Extension->RXHolding &= ~SERIAL_RX_DTR;
        !           380: 
        !           381:             }
        !           382: 
        !           383:             SerialClrDTR(Extension);
        !           384: 
        !           385:         }
        !           386: 
        !           387:     }
        !           388: 
        !           389:     //
        !           390:     // Time to take care of the RTS Flow control.
        !           391:     //
        !           392:     // First we only do work if something has changed.
        !           393:     //
        !           394: 
        !           395:     if ((!Extension->DeviceIsOpened) ||
        !           396:         ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) !=
        !           397:          (New.FlowReplace & SERIAL_RTS_MASK))) {
        !           398: 
        !           399:         SerialDump(
        !           400:             SERFLOW,
        !           401:             ("SERIAL: Processing RTS flow\n",
        !           402:              Extension->Controller)
        !           403:             );
        !           404: 
        !           405:         if ((New.FlowReplace & SERIAL_RTS_MASK) ==
        !           406:             SERIAL_RTS_HANDSHAKE) {
        !           407: 
        !           408:             //
        !           409:             // Well we might want to set RTS.
        !           410:             //
        !           411:             // Before we do, we need to check whether we are doing
        !           412:             // rts flow control.  If we are then we need to check
        !           413:             // if then number of characters in the interrupt buffer
        !           414:             // exceeds the XoffLimit.  If it does then we don't
        !           415:             // enable RTS AND we set the RXHolding to record that
        !           416:             // we are holding because of the rts.
        !           417:             //
        !           418: 
        !           419:             if ((Extension->BufferSize - New.XoffLimit) >
        !           420:                 Extension->CharsInInterruptBuffer) {
        !           421: 
        !           422:                 //
        !           423:                 // However if we are already holding we don't want
        !           424:                 // to turn it back on unless we exceed the Xon
        !           425:                 // limit.
        !           426:                 //
        !           427: 
        !           428:                 if (Extension->RXHolding & SERIAL_RX_RTS) {
        !           429: 
        !           430:                     //
        !           431:                     // We can assume that its RTS line is already low.
        !           432:                     //
        !           433: 
        !           434:                     if (Extension->CharsInInterruptBuffer >
        !           435:                         (ULONG)New.XonLimit) {
        !           436: 
        !           437:                        SerialDump(
        !           438:                            SERFLOW,
        !           439:                            ("SERIAL: Removing rts block of reception for %x\n",
        !           440:                            Extension->Controller)
        !           441:                            );
        !           442:                         Extension->RXHolding &= ~SERIAL_RX_RTS;
        !           443:                         SerialSetRTS(Extension);
        !           444: 
        !           445:                     }
        !           446: 
        !           447:                 } else {
        !           448: 
        !           449:                     SerialSetRTS(Extension);
        !           450: 
        !           451:                 }
        !           452: 
        !           453:             } else {
        !           454: 
        !           455:                 SerialDump(
        !           456:                     SERFLOW,
        !           457:                     ("SERIAL: Setting rts block of reception for %x\n",
        !           458:                     Extension->Controller)
        !           459:                     );
        !           460:                 Extension->RXHolding |= SERIAL_RX_RTS;
        !           461:                 SerialClrRTS(Extension);
        !           462: 
        !           463:             }
        !           464: 
        !           465:         } else if ((New.FlowReplace & SERIAL_RTS_MASK) ==
        !           466:                    SERIAL_RTS_CONTROL) {
        !           467: 
        !           468:             //
        !           469:             // Note that if we aren't currently doing rts flow control then
        !           470:             // we MIGHT have been.  So even if we aren't currently doing
        !           471:             // RTS flow control, we should still check if RX is holding
        !           472:             // because of RTS.  If it is, then we should clear the holding
        !           473:             // of this bit.
        !           474:             //
        !           475: 
        !           476:             if (Extension->RXHolding & SERIAL_RX_RTS) {
        !           477: 
        !           478:                 SerialDump(
        !           479:                     SERFLOW,
        !           480:                     ("SERIAL: Clearing rts block of reception for %x\n",
        !           481:                     Extension->Controller)
        !           482:                     );
        !           483:                 Extension->RXHolding &= ~SERIAL_RX_RTS;
        !           484: 
        !           485:             }
        !           486: 
        !           487:             SerialSetRTS(Extension);
        !           488: 
        !           489:         } else if ((New.FlowReplace & SERIAL_RTS_MASK) ==
        !           490:                    SERIAL_TRANSMIT_TOGGLE) {
        !           491: 
        !           492:             //
        !           493:             // We first need to check whether reception is being held
        !           494:             // up because of previous RTS flow control.  If it is then
        !           495:             // we should clear that reason in the RXHolding mask.
        !           496:             //
        !           497: 
        !           498:             if (Extension->RXHolding & SERIAL_RX_RTS) {
        !           499: 
        !           500:                 SerialDump(
        !           501:                     SERFLOW,
        !           502:                     ("SERIAL: TOGGLE Clearing rts block of reception for %x\n",
        !           503:                     Extension->Controller)
        !           504:                     );
        !           505:                 Extension->RXHolding &= ~SERIAL_RX_RTS;
        !           506: 
        !           507:             }
        !           508: 
        !           509:             //
        !           510:             // We have to place the rts value into the Extension
        !           511:             // now so that the code that tests whether the
        !           512:             // rts line should be lowered will find that we
        !           513:             // are "still" doing transmit toggling.  The code
        !           514:             // for lowering can be invoked later by a timer so
        !           515:             // it has to test whether it still needs to do its
        !           516:             // work.
        !           517:             //
        !           518: 
        !           519:             Extension->HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
        !           520:             Extension->HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;
        !           521: 
        !           522:             //
        !           523:             // The order of the tests is very important below.
        !           524:             //
        !           525:             // If there is a break then we should turn on the RTS.
        !           526:             //
        !           527:             // If there isn't a break but there are characters in
        !           528:             // the hardware, then turn on the RTS.
        !           529:             //
        !           530:             // If there are writes pending that aren't being held
        !           531:             // up, then turn on the RTS.
        !           532:             //
        !           533: 
        !           534:             if ((Extension->TXHolding & SERIAL_TX_BREAK) ||
        !           535:                 ((SerialProcessLSR(Extension) & (SERIAL_LSR_THRE |
        !           536:                                                  SERIAL_LSR_TEMT)) !=
        !           537:                                                 (SERIAL_LSR_THRE |
        !           538:                                                  SERIAL_LSR_TEMT)) ||
        !           539:                 (Extension->CurrentWriteIrp || Extension->TransmitImmediate ||
        !           540:                  (!IsListEmpty(&Extension->WriteQueue)) &&
        !           541:                  (!Extension->TXHolding))) {
        !           542: 
        !           543:                 SerialSetRTS(Extension);
        !           544: 
        !           545:             } else {
        !           546: 
        !           547:                 //
        !           548:                 // This routine will check to see if it is time
        !           549:                 // to lower the RTS because of transmit toggle
        !           550:                 // being on.  If it is ok to lower it, it will,
        !           551:                 // if it isn't ok, it will schedule things so
        !           552:                 // that it will get lowered later.
        !           553:                 //
        !           554: 
        !           555:                 Extension->CountOfTryingToLowerRTS++;
        !           556:                 SerialPerhapsLowerRTS(Extension);
        !           557: 
        !           558:             }
        !           559: 
        !           560:         } else {
        !           561: 
        !           562:             //
        !           563:             // The end result here will be that RTS is cleared.
        !           564:             //
        !           565:             // We first need to check whether reception is being held
        !           566:             // up because of previous RTS flow control.  If it is then
        !           567:             // we should clear that reason in the RXHolding mask.
        !           568:             //
        !           569: 
        !           570:             if (Extension->RXHolding & SERIAL_RX_RTS) {
        !           571: 
        !           572:                 SerialDump(
        !           573:                     SERFLOW,
        !           574:                     ("SERIAL: Clearing rts block of reception for %x\n",
        !           575:                     Extension->Controller)
        !           576:                     );
        !           577:                 Extension->RXHolding &= ~SERIAL_RX_RTS;
        !           578: 
        !           579:             }
        !           580: 
        !           581:             SerialClrRTS(Extension);
        !           582: 
        !           583:         }
        !           584: 
        !           585:     }
        !           586: 
        !           587:     //
        !           588:     // We now take care of automatic receive flow control.
        !           589:     // We only do work if things have changed.
        !           590:     //
        !           591: 
        !           592:     if ((!Extension->DeviceIsOpened) ||
        !           593:         ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) !=
        !           594:          (New.FlowReplace & SERIAL_AUTO_RECEIVE))) {
        !           595: 
        !           596:         if (New.FlowReplace & SERIAL_AUTO_RECEIVE) {
        !           597: 
        !           598:             //
        !           599:             // We wouldn't be here if it had been on before.
        !           600:             //
        !           601:             // We should check to see whether we exceed the turn
        !           602:             // off limits.
        !           603:             //
        !           604:             // Note that since we are following the OS/2 flow
        !           605:             // control rules we will never send an xon if
        !           606:             // when enabling xon/xoff flow control we discover that
        !           607:             // we could receive characters but we are held up do
        !           608:             // to a previous Xoff.
        !           609:             //
        !           610: 
        !           611:             if ((Extension->BufferSize - New.XoffLimit) <=
        !           612:                 Extension->CharsInInterruptBuffer) {
        !           613: 
        !           614:                 //
        !           615:                 // Cause the Xoff to be sent.
        !           616:                 //
        !           617: 
        !           618:                 Extension->RXHolding |= SERIAL_RX_XOFF;
        !           619: 
        !           620:                 SerialProdXonXoff(
        !           621:                     Extension,
        !           622:                     FALSE
        !           623:                     );
        !           624: 
        !           625:             }
        !           626: 
        !           627:         } else {
        !           628: 
        !           629:             //
        !           630:             // The app has disabled automatic receive flow control.
        !           631:             //
        !           632:             // If transmission was being held up because of
        !           633:             // an automatic receive Xoff, then we should
        !           634:             // cause an Xon to be sent.
        !           635:             //
        !           636: 
        !           637:             if (Extension->RXHolding & SERIAL_RX_XOFF) {
        !           638: 
        !           639:                 Extension->RXHolding &= ~SERIAL_RX_XOFF;
        !           640: 
        !           641:                 //
        !           642:                 // Cause the Xon to be sent.
        !           643:                 //
        !           644: 
        !           645:                 SerialProdXonXoff(
        !           646:                     Extension,
        !           647:                     TRUE
        !           648:                     );
        !           649: 
        !           650:             }
        !           651: 
        !           652:         }
        !           653: 
        !           654:     }
        !           655: 
        !           656:     //
        !           657:     // We now take care of automatic transmit flow control.
        !           658:     // We only do work if things have changed.
        !           659:     //
        !           660: 
        !           661:     if ((!Extension->DeviceIsOpened) ||
        !           662:         ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) !=
        !           663:          (New.FlowReplace & SERIAL_AUTO_TRANSMIT))) {
        !           664: 
        !           665:         if (New.FlowReplace & SERIAL_AUTO_TRANSMIT) {
        !           666: 
        !           667:             //
        !           668:             // We wouldn't be here if it had been on before.
        !           669:             //
        !           670:             // BUG BUG ??? There is some belief that if autotransmit
        !           671:             // was just enabled, I should go look in what we
        !           672:             // already received, and if we find the xoff character
        !           673:             // then we should stop transmitting.  I think this
        !           674:             // is an application bug.  For now we just care about
        !           675:             // what we see in the future.
        !           676:             //
        !           677: 
        !           678:             ;
        !           679: 
        !           680:         } else {
        !           681: 
        !           682:             //
        !           683:             // The app has disabled automatic transmit flow control.
        !           684:             //
        !           685:             // If transmission was being held up because of
        !           686:             // an automatic transmit Xoff, then we should
        !           687:             // cause an Xon to be sent.
        !           688:             //
        !           689: 
        !           690:             if (Extension->TXHolding & SERIAL_TX_XOFF) {
        !           691: 
        !           692:                 Extension->TXHolding &= ~SERIAL_TX_XOFF;
        !           693: 
        !           694:                 //
        !           695:                 // Cause the Xon to be sent.
        !           696:                 //
        !           697: 
        !           698:                 SerialProdXonXoff(
        !           699:                     Extension,
        !           700:                     TRUE
        !           701:                     );
        !           702: 
        !           703:             }
        !           704: 
        !           705:         }
        !           706: 
        !           707:     }
        !           708: 
        !           709:     //
        !           710:     // At this point we can simply make sure that entire
        !           711:     // handflow structure in the extension is updated.
        !           712:     //
        !           713: 
        !           714:     Extension->HandFlow = New;
        !           715: 
        !           716:     return FALSE;
        !           717: 
        !           718: }
        !           719: 
        !           720: BOOLEAN
        !           721: SerialSetHandFlow(
        !           722:     IN PVOID Context
        !           723:     )
        !           724: 
        !           725: /*++
        !           726: 
        !           727: Routine Description:
        !           728: 
        !           729:     This routine is used to set the handshake and control
        !           730:     flow in the device extension.
        !           731: 
        !           732: Arguments:
        !           733: 
        !           734:     Context - Pointer to a structure that contains a pointer to
        !           735:               the device extension and a pointer to a handflow
        !           736:               structure..
        !           737: 
        !           738: Return Value:
        !           739: 
        !           740:     This routine always returns FALSE.
        !           741: 
        !           742: --*/
        !           743: 
        !           744: {
        !           745: 
        !           746:     PSERIAL_IOCTL_SYNC S = Context;
        !           747:     PSERIAL_DEVICE_EXTENSION Extension = S->Extension;
        !           748:     PSERIAL_HANDFLOW HandFlow = S->Data;
        !           749: 
        !           750:     SerialSetupNewHandFlow(
        !           751:         Extension,
        !           752:         HandFlow
        !           753:         );
        !           754: 
        !           755:     SerialHandleModemUpdate(
        !           756:         Extension,
        !           757:         FALSE
        !           758:         );
        !           759: 
        !           760:     return FALSE;
        !           761: 
        !           762: }
        !           763: 
        !           764: BOOLEAN
        !           765: SerialTurnOnBreak(
        !           766:     IN PVOID Context
        !           767:     )
        !           768: 
        !           769: /*++
        !           770: 
        !           771: Routine Description:
        !           772: 
        !           773:     This routine will turn on break in the hardware and
        !           774:     record the fact the break is on, in the extension variable
        !           775:     that holds reasons that transmission is stopped.
        !           776: 
        !           777: Arguments:
        !           778: 
        !           779:     Context - Really a pointer to the device extension.
        !           780: 
        !           781: Return Value:
        !           782: 
        !           783:     This routine always returns FALSE.
        !           784: 
        !           785: --*/
        !           786: 
        !           787: {
        !           788: 
        !           789:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           790: 
        !           791:     UCHAR OldLineControl;
        !           792: 
        !           793:     if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        !           794:         SERIAL_TRANSMIT_TOGGLE) {
        !           795: 
        !           796:         SerialSetRTS(Extension);
        !           797: 
        !           798:     }
        !           799: 
        !           800:     OldLineControl = READ_LINE_CONTROL(Extension->Controller);
        !           801: 
        !           802:     OldLineControl |= SERIAL_LCR_BREAK;
        !           803: 
        !           804:     WRITE_LINE_CONTROL(
        !           805:         Extension->Controller,
        !           806:         OldLineControl
        !           807:         );
        !           808: 
        !           809:     Extension->TXHolding |= SERIAL_TX_BREAK;
        !           810: 
        !           811:     return FALSE;
        !           812: 
        !           813: }
        !           814: 
        !           815: BOOLEAN
        !           816: SerialTurnOffBreak(
        !           817:     IN PVOID Context
        !           818:     )
        !           819: 
        !           820: /*++
        !           821: 
        !           822: Routine Description:
        !           823: 
        !           824:     This routine will turn off break in the hardware and
        !           825:     record the fact the break is off, in the extension variable
        !           826:     that holds reasons that transmission is stopped.
        !           827: 
        !           828: Arguments:
        !           829: 
        !           830:     Context - Really a pointer to the device extension.
        !           831: 
        !           832: Return Value:
        !           833: 
        !           834:     This routine always returns FALSE.
        !           835: 
        !           836: --*/
        !           837: 
        !           838: {
        !           839: 
        !           840:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           841: 
        !           842:     UCHAR OldLineControl;
        !           843: 
        !           844:     if (Extension->TXHolding & SERIAL_TX_BREAK) {
        !           845: 
        !           846:         //
        !           847:         // We actually have a good reason for testing if transmission
        !           848:         // is holding instead of blindly clearing the bit.
        !           849:         //
        !           850:         // If transmission actually was holding and the result of
        !           851:         // clearing the bit is that we should restart transmission
        !           852:         // then we will poke the interrupt enable bit, which will
        !           853:         // cause an actual interrupt and transmission will then
        !           854:         // restart on its own.
        !           855:         //
        !           856:         // If transmission wasn't holding and we poked the bit
        !           857:         // then we would interrupt before a character actually made
        !           858:         // it out and we could end up over writing a character in
        !           859:         // the transmission hardware.
        !           860: 
        !           861:         OldLineControl = READ_LINE_CONTROL(Extension->Controller);
        !           862: 
        !           863:         OldLineControl &= ~SERIAL_LCR_BREAK;
        !           864: 
        !           865:         WRITE_LINE_CONTROL(
        !           866:             Extension->Controller,
        !           867:             OldLineControl
        !           868:             );
        !           869: 
        !           870:         Extension->TXHolding &= ~SERIAL_TX_BREAK;
        !           871: 
        !           872:         if (!Extension->TXHolding &&
        !           873:             (Extension->TransmitImmediate ||
        !           874:              Extension->WriteLength) &&
        !           875:              Extension->HoldingEmpty) {
        !           876: 
        !           877:             DISABLE_ALL_INTERRUPTS(Extension->Controller);
        !           878:             ENABLE_ALL_INTERRUPTS(Extension->Controller);
        !           879: 
        !           880:         } else {
        !           881: 
        !           882:             //
        !           883:             // The following routine will lower the rts if we
        !           884:             // are doing transmit toggleing and there is no
        !           885:             // reason to keep it up.
        !           886:             //
        !           887: 
        !           888:             Extension->CountOfTryingToLowerRTS++;
        !           889:             SerialPerhapsLowerRTS(Extension);
        !           890: 
        !           891:         }
        !           892: 
        !           893:     }
        !           894: 
        !           895:     return FALSE;
        !           896: 
        !           897: }
        !           898: 
        !           899: BOOLEAN
        !           900: SerialPretendXoff(
        !           901:     IN PVOID Context
        !           902:     )
        !           903: 
        !           904: /*++
        !           905: 
        !           906: Routine Description:
        !           907: 
        !           908:     This routine is used to process the Ioctl that request the
        !           909:     driver to act as if an Xoff was received.  Even if the
        !           910:     driver does not have automatic Xoff/Xon flowcontrol - This
        !           911:     still will stop the transmission.  This is the OS/2 behavior
        !           912:     and is not well specified for Windows.  Therefore we adopt
        !           913:     the OS/2 behavior.
        !           914: 
        !           915:     Note: If the driver does not have automatic Xoff/Xon enabled
        !           916:     then the only way to restart transmission is for the
        !           917:     application to request we "act" as if we saw the xon.
        !           918: 
        !           919: Arguments:
        !           920: 
        !           921:     Context - Really a pointer to the device extension.
        !           922: 
        !           923: Return Value:
        !           924: 
        !           925:     This routine always returns FALSE.
        !           926: 
        !           927: --*/
        !           928: 
        !           929: {
        !           930: 
        !           931:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           932: 
        !           933:     Extension->TXHolding |= SERIAL_TX_XOFF;
        !           934: 
        !           935:     if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        !           936:         SERIAL_TRANSMIT_TOGGLE) {
        !           937: 
        !           938:         KeInsertQueueDpc(
        !           939:             &Extension->StartTimerLowerRTSDpc,
        !           940:             NULL,
        !           941:             NULL
        !           942:             )?Extension->CountOfTryingToLowerRTS++:0;
        !           943: 
        !           944:     }
        !           945: 
        !           946:     return FALSE;
        !           947: 
        !           948: }
        !           949: 
        !           950: BOOLEAN
        !           951: SerialPretendXon(
        !           952:     IN PVOID Context
        !           953:     )
        !           954: 
        !           955: /*++
        !           956: 
        !           957: Routine Description:
        !           958: 
        !           959:     This routine is used to process the Ioctl that request the
        !           960:     driver to act as if an Xon was received.
        !           961: 
        !           962:     Note: If the driver does not have automatic Xoff/Xon enabled
        !           963:     then the only way to restart transmission is for the
        !           964:     application to request we "act" as if we saw the xon.
        !           965: 
        !           966: Arguments:
        !           967: 
        !           968:     Context - Really a pointer to the device extension.
        !           969: 
        !           970: Return Value:
        !           971: 
        !           972:     This routine always returns FALSE.
        !           973: 
        !           974: --*/
        !           975: 
        !           976: {
        !           977: 
        !           978:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !           979: 
        !           980:     if (Extension->TXHolding) {
        !           981: 
        !           982:         //
        !           983:         // We actually have a good reason for testing if transmission
        !           984:         // is holding instead of blindly clearing the bit.
        !           985:         //
        !           986:         // If transmission actually was holding and the result of
        !           987:         // clearing the bit is that we should restart transmission
        !           988:         // then we will poke the interrupt enable bit, which will
        !           989:         // cause an actual interrupt and transmission will then
        !           990:         // restart on its own.
        !           991:         //
        !           992:         // If transmission wasn't holding and we poked the bit
        !           993:         // then we would interrupt before a character actually made
        !           994:         // it out and we could end up over writing a character in
        !           995:         // the transmission hardware.
        !           996: 
        !           997:         Extension->TXHolding &= ~SERIAL_TX_XOFF;
        !           998: 
        !           999:         if (!Extension->TXHolding &&
        !          1000:             (Extension->TransmitImmediate ||
        !          1001:              Extension->WriteLength) &&
        !          1002:              Extension->HoldingEmpty) {
        !          1003: 
        !          1004:             DISABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1005:             ENABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1006: 
        !          1007:         }
        !          1008: 
        !          1009:     }
        !          1010: 
        !          1011:     return FALSE;
        !          1012: 
        !          1013: }
        !          1014: 
        !          1015: VOID
        !          1016: SerialHandleReducedIntBuffer(
        !          1017:     IN PSERIAL_DEVICE_EXTENSION Extension
        !          1018:     )
        !          1019: 
        !          1020: /*++
        !          1021: 
        !          1022: Routine Description:
        !          1023: 
        !          1024:     This routine is called to handle a reduction in the number
        !          1025:     of characters in the interrupt (typeahead) buffer.  It
        !          1026:     will check the current output flow control and re-enable transmission
        !          1027:     as needed.
        !          1028: 
        !          1029:     NOTE: This routine assumes that it is working at interrupt level.
        !          1030: 
        !          1031: Arguments:
        !          1032: 
        !          1033:     Extension - A pointer to the device extension.
        !          1034: 
        !          1035: Return Value:
        !          1036: 
        !          1037:     None.
        !          1038: 
        !          1039: --*/
        !          1040: 
        !          1041: {
        !          1042: 
        !          1043: 
        !          1044:     //
        !          1045:     // If we are doing receive side flow control and we are
        !          1046:     // currently "holding" then because we've emptied out
        !          1047:     // some characters from the interrupt buffer we need to
        !          1048:     // see if we can "re-enable" reception.
        !          1049:     //
        !          1050: 
        !          1051:     if (Extension->RXHolding) {
        !          1052: 
        !          1053:         if (Extension->CharsInInterruptBuffer <=
        !          1054:             (ULONG)Extension->HandFlow.XonLimit) {
        !          1055: 
        !          1056:             if (Extension->RXHolding & SERIAL_RX_DTR) {
        !          1057: 
        !          1058:                 Extension->RXHolding &= ~SERIAL_RX_DTR;
        !          1059:                 SerialSetDTR(Extension);
        !          1060: 
        !          1061:             }
        !          1062: 
        !          1063:             if (Extension->RXHolding & SERIAL_RX_RTS) {
        !          1064: 
        !          1065:                 Extension->RXHolding &= ~SERIAL_RX_RTS;
        !          1066:                 SerialSetRTS(Extension);
        !          1067: 
        !          1068:             }
        !          1069: 
        !          1070:             if (Extension->RXHolding & SERIAL_RX_XOFF) {
        !          1071: 
        !          1072:                 //
        !          1073:                 // Prod the transmit code to send xon.
        !          1074:                 //
        !          1075: 
        !          1076:                 SerialProdXonXoff(
        !          1077:                     Extension,
        !          1078:                     TRUE
        !          1079:                     );
        !          1080: 
        !          1081:             }
        !          1082: 
        !          1083:         }
        !          1084: 
        !          1085:     }
        !          1086: 
        !          1087: }
        !          1088: 
        !          1089: VOID
        !          1090: SerialProdXonXoff(
        !          1091:     IN PSERIAL_DEVICE_EXTENSION Extension,
        !          1092:     IN BOOLEAN SendXon
        !          1093:     )
        !          1094: 
        !          1095: /*++
        !          1096: 
        !          1097: Routine Description:
        !          1098: 
        !          1099:     This routine will set up the SendXxxxChar variables if
        !          1100:     necessary and determine if we are going to be interrupting
        !          1101:     because of current transmission state.  It will cause an
        !          1102:     interrupt to occur if neccessary, to send the xon/xoff char.
        !          1103: 
        !          1104:     NOTE: This routine assumes that it is called at interrupt
        !          1105:           level.
        !          1106: 
        !          1107: Arguments:
        !          1108: 
        !          1109:     Extension - A pointer to the serial device extension.
        !          1110: 
        !          1111:     SendXon - If a character is to be send, this indicates whether
        !          1112:               it should be an Xon or an Xoff.
        !          1113: 
        !          1114: Return Value:
        !          1115: 
        !          1116:     None.
        !          1117: 
        !          1118: --*/
        !          1119: 
        !          1120: {
        !          1121: 
        !          1122:     //
        !          1123:     // We assume that if the prodding is called more than
        !          1124:     // once that the last prod has set things up appropriately.
        !          1125:     //
        !          1126:     // We could get called before the character is sent out
        !          1127:     // because the send of the character was blocked because
        !          1128:     // of hardware flow control (or break).
        !          1129:     //
        !          1130: 
        !          1131:     if (!Extension->SendXonChar && !Extension->SendXoffChar
        !          1132:         && Extension->HoldingEmpty) {
        !          1133: 
        !          1134:         DISABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1135:         ENABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1136: 
        !          1137:     }
        !          1138: 
        !          1139:     if (SendXon) {
        !          1140: 
        !          1141:         Extension->SendXonChar = TRUE;
        !          1142:         Extension->SendXoffChar = FALSE;
        !          1143: 
        !          1144:     } else {
        !          1145: 
        !          1146:         Extension->SendXonChar = FALSE;
        !          1147:         Extension->SendXoffChar = TRUE;
        !          1148: 
        !          1149:     }
        !          1150: 
        !          1151: }
        !          1152: 
        !          1153: ULONG
        !          1154: SerialHandleModemUpdate(
        !          1155:     IN PSERIAL_DEVICE_EXTENSION Extension,
        !          1156:     IN BOOLEAN DoingTX
        !          1157:     )
        !          1158: 
        !          1159: /*++
        !          1160: 
        !          1161: Routine Description:
        !          1162: 
        !          1163:     This routine will be to check on the modem status, and
        !          1164:     handle any appropriate event notification as well as
        !          1165:     any flow control appropriate to modem status lines.
        !          1166: 
        !          1167:     NOTE: This routine assumes that it is called at interrupt
        !          1168:           level.
        !          1169: 
        !          1170: Arguments:
        !          1171: 
        !          1172:     Extension - A pointer to the serial device extension.
        !          1173: 
        !          1174:     DoingTX - This boolean is used to indicate that this call
        !          1175:               came from the transmit processing code.  If this
        !          1176:               is true then there is no need to cause a new interrupt
        !          1177:               since the code will be trying to send the next
        !          1178:               character as soon as this call finishes.
        !          1179: 
        !          1180: Return Value:
        !          1181: 
        !          1182:     This returns the old value of the modem status register
        !          1183:     (extended into a ULONG).
        !          1184: 
        !          1185: --*/
        !          1186: 
        !          1187: {
        !          1188: 
        !          1189:     //
        !          1190:     // We keep this local so that after we are done
        !          1191:     // examining the modem status and we've updated
        !          1192:     // the transmission holding value, we know whether
        !          1193:     // we've changed from needing to hold up transmission
        !          1194:     // to transmission being able to proceed.
        !          1195:     //
        !          1196:     ULONG OldTXHolding = Extension->TXHolding;
        !          1197: 
        !          1198:     //
        !          1199:     // Holds the value in the mode status register.
        !          1200:     //
        !          1201:     UCHAR ModemStatus;
        !          1202: 
        !          1203:     ModemStatus =
        !          1204:         READ_MODEM_STATUS(Extension->Controller);
        !          1205: 
        !          1206:     //
        !          1207:     // If we are placeing the modem status into the data stream
        !          1208:     // on every change, we should do it now.
        !          1209:     //
        !          1210: 
        !          1211:     if (Extension->EscapeChar) {
        !          1212: 
        !          1213:         if (ModemStatus & (SERIAL_MSR_DCTS |
        !          1214:                            SERIAL_MSR_DDSR |
        !          1215:                            SERIAL_MSR_TERI |
        !          1216:                            SERIAL_MSR_DDCD)) {
        !          1217: 
        !          1218:             SerialPutChar(
        !          1219:                 Extension,
        !          1220:                 Extension->EscapeChar
        !          1221:                 );
        !          1222:             SerialPutChar(
        !          1223:                 Extension,
        !          1224:                 SERIAL_LSRMST_MST
        !          1225:                 );
        !          1226:             SerialPutChar(
        !          1227:                 Extension,
        !          1228:                 ModemStatus
        !          1229:                 );
        !          1230: 
        !          1231:         }
        !          1232: 
        !          1233:     }
        !          1234: 
        !          1235: 
        !          1236:     //
        !          1237:     // Take care of input flow control based on sensitivity
        !          1238:     // to the DSR.  This is done so that the application won't
        !          1239:     // see spurious data generated by odd devices.
        !          1240:     //
        !          1241:     // Basically, if we are doing dsr sensitivity then the
        !          1242:     // driver should only accept data when the dsr bit is
        !          1243:     // set.
        !          1244:     //
        !          1245: 
        !          1246:     if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) {
        !          1247: 
        !          1248:         if (ModemStatus & SERIAL_MSR_DSR) {
        !          1249: 
        !          1250:             //
        !          1251:             // The line is high.  Simply make sure that
        !          1252:             // RXHolding does't have the DSR bit.
        !          1253:             //
        !          1254: 
        !          1255:             Extension->RXHolding &= ~SERIAL_RX_DSR;
        !          1256: 
        !          1257:         } else {
        !          1258: 
        !          1259:             Extension->RXHolding |= SERIAL_RX_DSR;
        !          1260: 
        !          1261:         }
        !          1262: 
        !          1263:     } else {
        !          1264: 
        !          1265:         //
        !          1266:         // We don't have sensitivity due to DSR.  Make sure we
        !          1267:         // arn't holding. (We might have been, but the app just
        !          1268:         // asked that we don't hold for this reason any more.)
        !          1269:         //
        !          1270: 
        !          1271:         Extension->RXHolding &= ~SERIAL_RX_DSR;
        !          1272: 
        !          1273:     }
        !          1274: 
        !          1275:     //
        !          1276:     // Check to see if we have a wait
        !          1277:     // pending on the modem status events.  If we
        !          1278:     // do then we schedule a dpc to satisfy
        !          1279:     // that wait.
        !          1280:     //
        !          1281: 
        !          1282:     if (Extension->IsrWaitMask) {
        !          1283: 
        !          1284:         if ((Extension->IsrWaitMask & SERIAL_EV_CTS) &&
        !          1285:             (ModemStatus & SERIAL_MSR_DCTS)) {
        !          1286: 
        !          1287:             Extension->HistoryMask |= SERIAL_EV_CTS;
        !          1288: 
        !          1289:         }
        !          1290: 
        !          1291:         if ((Extension->IsrWaitMask & SERIAL_EV_DSR) &&
        !          1292:             (ModemStatus & SERIAL_MSR_DDSR)) {
        !          1293: 
        !          1294:             Extension->HistoryMask |= SERIAL_EV_DSR;
        !          1295: 
        !          1296:         }
        !          1297: 
        !          1298:         if ((Extension->IsrWaitMask & SERIAL_EV_RING) &&
        !          1299:             (ModemStatus & SERIAL_MSR_TERI)) {
        !          1300: 
        !          1301:             Extension->HistoryMask |= SERIAL_EV_RING;
        !          1302: 
        !          1303:         }
        !          1304: 
        !          1305:         if ((Extension->IsrWaitMask & SERIAL_EV_RLSD) &&
        !          1306:             (ModemStatus & SERIAL_MSR_DDCD)) {
        !          1307: 
        !          1308:             Extension->HistoryMask |= SERIAL_EV_RLSD;
        !          1309: 
        !          1310:         }
        !          1311: 
        !          1312:         if (Extension->IrpMaskLocation &&
        !          1313:             Extension->HistoryMask) {
        !          1314: 
        !          1315:             *Extension->IrpMaskLocation =
        !          1316:              Extension->HistoryMask;
        !          1317:             Extension->IrpMaskLocation = NULL;
        !          1318:             Extension->HistoryMask = 0;
        !          1319: 
        !          1320:             Extension->CurrentWaitIrp->
        !          1321:                 IoStatus.Information = sizeof(ULONG);
        !          1322:             KeInsertQueueDpc(
        !          1323:                 &Extension->CommWaitDpc,
        !          1324:                 NULL,
        !          1325:                 NULL
        !          1326:                 );
        !          1327: 
        !          1328:         }
        !          1329: 
        !          1330:     }
        !          1331: 
        !          1332:     //
        !          1333:     // If the app has modem line flow control then
        !          1334:     // we check to see if we have to hold up transmission.
        !          1335:     //
        !          1336: 
        !          1337:     if (Extension->HandFlow.ControlHandShake &
        !          1338:         SERIAL_OUT_HANDSHAKEMASK) {
        !          1339: 
        !          1340:         if (Extension->HandFlow.ControlHandShake &
        !          1341:             SERIAL_CTS_HANDSHAKE) {
        !          1342: 
        !          1343:             if (ModemStatus & SERIAL_MSR_CTS) {
        !          1344: 
        !          1345:                 Extension->TXHolding &= ~SERIAL_TX_CTS;
        !          1346: 
        !          1347:             } else {
        !          1348: 
        !          1349:                 Extension->TXHolding |= SERIAL_TX_CTS;
        !          1350: 
        !          1351:             }
        !          1352: 
        !          1353:         } else {
        !          1354: 
        !          1355:             Extension->TXHolding &= ~SERIAL_TX_CTS;
        !          1356: 
        !          1357:         }
        !          1358: 
        !          1359:         if (Extension->HandFlow.ControlHandShake &
        !          1360:             SERIAL_DSR_HANDSHAKE) {
        !          1361: 
        !          1362:             if (ModemStatus & SERIAL_MSR_DSR) {
        !          1363: 
        !          1364:                 Extension->TXHolding &= ~SERIAL_TX_DSR;
        !          1365: 
        !          1366:             } else {
        !          1367: 
        !          1368:                 Extension->TXHolding |= SERIAL_TX_DSR;
        !          1369: 
        !          1370:             }
        !          1371: 
        !          1372:         } else {
        !          1373: 
        !          1374:             Extension->TXHolding &= ~SERIAL_TX_DSR;
        !          1375: 
        !          1376:         }
        !          1377: 
        !          1378:         if (Extension->HandFlow.ControlHandShake &
        !          1379:             SERIAL_DCD_HANDSHAKE) {
        !          1380: 
        !          1381:             if (ModemStatus & SERIAL_MSR_DCD) {
        !          1382: 
        !          1383:                 Extension->TXHolding &= ~SERIAL_TX_DCD;
        !          1384: 
        !          1385:             } else {
        !          1386: 
        !          1387:                 Extension->TXHolding |= SERIAL_TX_DCD;
        !          1388: 
        !          1389:             }
        !          1390: 
        !          1391:         } else {
        !          1392: 
        !          1393:             Extension->TXHolding &= ~SERIAL_TX_DCD;
        !          1394: 
        !          1395:         }
        !          1396: 
        !          1397:         //
        !          1398:         // If we hadn't been holding, and now we are then
        !          1399:         // queue off a dpc that will lower the RTS line
        !          1400:         // if we are doing transmit toggling.
        !          1401:         //
        !          1402: 
        !          1403:         if (!OldTXHolding && Extension->TXHolding  &&
        !          1404:             ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        !          1405:               SERIAL_TRANSMIT_TOGGLE)) {
        !          1406: 
        !          1407:             KeInsertQueueDpc(
        !          1408:                 &Extension->StartTimerLowerRTSDpc,
        !          1409:                 NULL,
        !          1410:                 NULL
        !          1411:                 )?Extension->CountOfTryingToLowerRTS++:0;
        !          1412: 
        !          1413:         }
        !          1414: 
        !          1415:         //
        !          1416:         // We've done any adjusting that needed to be
        !          1417:         // done to the holding mask given updates
        !          1418:         // to the modem status.  If the Holding mask
        !          1419:         // is clear (and it wasn't clear to start)
        !          1420:         // and we have "write" work to do set things
        !          1421:         // up so that the transmission code gets invoked.
        !          1422:         //
        !          1423: 
        !          1424:         if (!DoingTX && OldTXHolding && !Extension->TXHolding) {
        !          1425: 
        !          1426:             if (!Extension->TXHolding &&
        !          1427:                 (Extension->TransmitImmediate ||
        !          1428:                  Extension->WriteLength) &&
        !          1429:                  Extension->HoldingEmpty) {
        !          1430: 
        !          1431:                 DISABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1432:                 ENABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1433: 
        !          1434:             }
        !          1435: 
        !          1436:         }
        !          1437: 
        !          1438:     } else {
        !          1439: 
        !          1440:         //
        !          1441:         // We need to check if transmission is holding
        !          1442:         // up because of modem status lines.  What
        !          1443:         // could have occured is that for some strange
        !          1444:         // reason, the app has asked that we no longer
        !          1445:         // stop doing output flow control based on
        !          1446:         // the modem status lines.  If however, we
        !          1447:         // *had* been held up because of the status lines
        !          1448:         // then we need to clear up those reasons.
        !          1449:         //
        !          1450: 
        !          1451:         if (Extension->TXHolding & (SERIAL_TX_DCD |
        !          1452:                                     SERIAL_TX_DSR |
        !          1453:                                     SERIAL_TX_CTS)) {
        !          1454: 
        !          1455:             Extension->TXHolding &= ~(SERIAL_TX_DCD |
        !          1456:                                       SERIAL_TX_DSR |
        !          1457:                                       SERIAL_TX_CTS);
        !          1458: 
        !          1459: 
        !          1460:             if (!DoingTX && OldTXHolding && !Extension->TXHolding) {
        !          1461: 
        !          1462:                 if (!Extension->TXHolding &&
        !          1463:                     (Extension->TransmitImmediate ||
        !          1464:                      Extension->WriteLength) &&
        !          1465:                      Extension->HoldingEmpty) {
        !          1466: 
        !          1467:                     DISABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1468:                     ENABLE_ALL_INTERRUPTS(Extension->Controller);
        !          1469: 
        !          1470:                 }
        !          1471: 
        !          1472:             }
        !          1473: 
        !          1474:         }
        !          1475: 
        !          1476:     }
        !          1477: 
        !          1478:     return ((ULONG)ModemStatus);
        !          1479: }
        !          1480: 
        !          1481: BOOLEAN
        !          1482: SerialPerhapsLowerRTS(
        !          1483:     IN PVOID Context
        !          1484:     )
        !          1485: 
        !          1486: /*++
        !          1487: 
        !          1488: Routine Description:
        !          1489: 
        !          1490:     This routine checks that the software reasons for lowering
        !          1491:     the RTS lines are present.  If so, it will then cause the
        !          1492:     line status register to be read (and any needed processing
        !          1493:     implied by the status register to be done), and if the
        !          1494:     shift register is empty it will lower the line.  If the
        !          1495:     shift register isn't empty, this routine will queue off
        !          1496:     a dpc that will start a timer, that will basically call
        !          1497:     us back to try again.
        !          1498: 
        !          1499:     NOTE: This routine assumes that it is called at interrupt
        !          1500:           level.
        !          1501: 
        !          1502: Arguments:
        !          1503: 
        !          1504:     Context - Really a pointer to the device extension.
        !          1505: 
        !          1506: Return Value:
        !          1507: 
        !          1508:     Always FALSE.
        !          1509: 
        !          1510: --*/
        !          1511: 
        !          1512: {
        !          1513: 
        !          1514:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !          1515: 
        !          1516: 
        !          1517:     //
        !          1518:     // We first need to test if we are actually still doing
        !          1519:     // transmit toggle flow control.  If we aren't then
        !          1520:     // we have no reason to try be here.
        !          1521:     //
        !          1522: 
        !          1523:     if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        !          1524:         SERIAL_TRANSMIT_TOGGLE) {
        !          1525: 
        !          1526:         //
        !          1527:         // The order of the tests is very important below.
        !          1528:         //
        !          1529:         // If there is a break then we should leave on the RTS,
        !          1530:         // because when the break is turned off, it will submit
        !          1531:         // the code to shut down the RTS.
        !          1532:         //
        !          1533:         // If there are writes pending that aren't being held
        !          1534:         // up, then leave on the RTS, because the end of the write
        !          1535:         // code will cause this code to be reinvoked.  If the writes
        !          1536:         // are being held up, its ok to lower the RTS because the
        !          1537:         // upon trying to write the first character after transmission
        !          1538:         // is restarted, we will raise the RTS line.
        !          1539:         //
        !          1540: 
        !          1541:         if ((Extension->TXHolding & SERIAL_TX_BREAK) ||
        !          1542:             (Extension->CurrentWriteIrp || Extension->TransmitImmediate ||
        !          1543:              (!IsListEmpty(&Extension->WriteQueue)) &&
        !          1544:              (!Extension->TXHolding))) {
        !          1545: 
        !          1546:             NOTHING;
        !          1547: 
        !          1548:         } else {
        !          1549: 
        !          1550:             //
        !          1551:             // Looks good so far.  Call the line status check and processing
        !          1552:             // code, it will return the "current" line status value.  If
        !          1553:             // the holding and shift register are clear, lower the RTS line,
        !          1554:             // if they aren't clear, queue of a dpc that will cause a timer
        !          1555:             // to reinvoke us later.  We do this code here because no one
        !          1556:             // but this routine cares about the characters in the hardware,
        !          1557:             // so no routine by this routine will bother invoking to test
        !          1558:             // if the hardware is empty.
        !          1559:             //
        !          1560: 
        !          1561:             if ((SerialProcessLSR(Extension) &
        !          1562:                  (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
        !          1563:                  (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
        !          1564: 
        !          1565:                 //
        !          1566:                 // Well it's not empty, try again later.
        !          1567:                 //
        !          1568: 
        !          1569:                 KeInsertQueueDpc(
        !          1570:                     &Extension->StartTimerLowerRTSDpc,
        !          1571:                     NULL,
        !          1572:                     NULL
        !          1573:                     )?Extension->CountOfTryingToLowerRTS++:0;
        !          1574: 
        !          1575: 
        !          1576:             } else {
        !          1577: 
        !          1578:                 //
        !          1579:                 // Nothing in the hardware, Lower the RTS.
        !          1580:                 //
        !          1581: 
        !          1582:                 SerialClrRTS(Extension);
        !          1583: 
        !          1584: 
        !          1585:             }
        !          1586: 
        !          1587:         }
        !          1588: 
        !          1589:     }
        !          1590: 
        !          1591:     //
        !          1592:     // We decement the counter to indicate that we've reached
        !          1593:     // the end of the execution path that is trying to push
        !          1594:     // down the RTS line.
        !          1595:     //
        !          1596: 
        !          1597:     Extension->CountOfTryingToLowerRTS--;
        !          1598: 
        !          1599:     return FALSE;
        !          1600: }
        !          1601: 
        !          1602: VOID
        !          1603: SerialStartTimerLowerRTS(
        !          1604:     IN PKDPC Dpc,
        !          1605:     IN PVOID DeferredContext,
        !          1606:     IN PVOID SystemContext1,
        !          1607:     IN PVOID SystemContext2
        !          1608:     )
        !          1609: 
        !          1610: /*++
        !          1611: 
        !          1612: Routine Description:
        !          1613: 
        !          1614:     This routine starts a timer that when it expires will start
        !          1615:     a dpc that will check if it can lower the rts line because
        !          1616:     there are no characters in the hardware.
        !          1617: 
        !          1618: Arguments:
        !          1619: 
        !          1620:     Dpc - Not Used.
        !          1621: 
        !          1622:     DeferredContext - Really points to the device extension.
        !          1623: 
        !          1624:     SystemContext1 - Not Used.
        !          1625: 
        !          1626:     SystemContext2 - Not Used.
        !          1627: 
        !          1628: Return Value:
        !          1629: 
        !          1630:     None.
        !          1631: 
        !          1632: --*/
        !          1633: 
        !          1634: {
        !          1635: 
        !          1636:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
        !          1637:     LARGE_INTEGER CharTime;
        !          1638:     KIRQL OldIrql;
        !          1639: 
        !          1640:     UNREFERENCED_PARAMETER(Dpc);
        !          1641:     UNREFERENCED_PARAMETER(SystemContext1);
        !          1642:     UNREFERENCED_PARAMETER(SystemContext2);
        !          1643: 
        !          1644: 
        !          1645:     //
        !          1646:     // Take out the lock to prevent the line control
        !          1647:     // from changing out from under us while we calculate
        !          1648:     // a character time.
        !          1649:     //
        !          1650: 
        !          1651:     KeAcquireSpinLock(
        !          1652:         &Extension->ControlLock,
        !          1653:         &OldIrql
        !          1654:         );
        !          1655: 
        !          1656:     CharTime = SerialGetCharTime(Extension);
        !          1657: 
        !          1658:     KeReleaseSpinLock(
        !          1659:         &Extension->ControlLock,
        !          1660:         OldIrql
        !          1661:         );
        !          1662: 
        !          1663:     CharTime = RtlLargeIntegerNegate(CharTime);
        !          1664: 
        !          1665:     if (KeSetTimer(
        !          1666:             &Extension->LowerRTSTimer,
        !          1667:             CharTime,
        !          1668:             &Extension->PerhapsLowerRTSDpc
        !          1669:             )) {
        !          1670: 
        !          1671:         //
        !          1672:         // The timer was already in the timer queue.  This implies
        !          1673:         // that one path of execution that was trying to lower
        !          1674:         // the RTS has "died".  Synchronize with the ISR so that
        !          1675:         // we can lower the count.
        !          1676:         //
        !          1677: 
        !          1678:         KeSynchronizeExecution(
        !          1679:             Extension->Interrupt,
        !          1680:             SerialDecrementRTSCounter,
        !          1681:             Extension
        !          1682:             );
        !          1683: 
        !          1684:     }
        !          1685: 
        !          1686: }
        !          1687: 
        !          1688: VOID
        !          1689: SerialInvokePerhapsLowerRTS(
        !          1690:     IN PKDPC Dpc,
        !          1691:     IN PVOID DeferredContext,
        !          1692:     IN PVOID SystemContext1,
        !          1693:     IN PVOID SystemContext2
        !          1694:     )
        !          1695: 
        !          1696: /*++
        !          1697: 
        !          1698: Routine Description:
        !          1699: 
        !          1700:     This dpc routine exists solely to call the code that
        !          1701:     tests if the rts line should be lowered when TRANSMIT
        !          1702:     TOGGLE flow control is being used.
        !          1703: 
        !          1704: Arguments:
        !          1705: 
        !          1706:     Dpc - Not Used.
        !          1707: 
        !          1708:     DeferredContext - Really points to the device extension.
        !          1709: 
        !          1710:     SystemContext1 - Not Used.
        !          1711: 
        !          1712:     SystemContext2 - Not Used.
        !          1713: 
        !          1714: Return Value:
        !          1715: 
        !          1716:     None.
        !          1717: 
        !          1718: --*/
        !          1719: 
        !          1720: {
        !          1721: 
        !          1722:     PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
        !          1723: 
        !          1724:     UNREFERENCED_PARAMETER(Dpc);
        !          1725:     UNREFERENCED_PARAMETER(SystemContext1);
        !          1726:     UNREFERENCED_PARAMETER(SystemContext2);
        !          1727: 
        !          1728:     KeSynchronizeExecution(
        !          1729:         Extension->Interrupt,
        !          1730:         SerialPerhapsLowerRTS,
        !          1731:         Extension
        !          1732:         );
        !          1733: 
        !          1734: }
        !          1735: 
        !          1736: BOOLEAN
        !          1737: SerialDecrementRTSCounter(
        !          1738:     IN PVOID Context
        !          1739:     )
        !          1740: 
        !          1741: /*++
        !          1742: 
        !          1743: Routine Description:
        !          1744: 
        !          1745:     This routine checks that the software reasons for lowering
        !          1746:     the RTS lines are present.  If so, it will then cause the
        !          1747:     line status register to be read (and any needed processing
        !          1748:     implied by the status register to be done), and if the
        !          1749:     shift register is empty it will lower the line.  If the
        !          1750:     shift register isn't empty, this routine will queue off
        !          1751:     a dpc that will start a timer, that will basically call
        !          1752:     us back to try again.
        !          1753: 
        !          1754:     NOTE: This routine assumes that it is called at interrupt
        !          1755:           level.
        !          1756: 
        !          1757: Arguments:
        !          1758: 
        !          1759:     Context - Really a pointer to the device extension.
        !          1760: 
        !          1761: Return Value:
        !          1762: 
        !          1763:     Always FALSE.
        !          1764: 
        !          1765: --*/
        !          1766: 
        !          1767: {
        !          1768: 
        !          1769:     PSERIAL_DEVICE_EXTENSION Extension = Context;
        !          1770: 
        !          1771:     Extension->CountOfTryingToLowerRTS--;
        !          1772: 
        !          1773:     return FALSE;
        !          1774: 
        !          1775: }

unix.superglobalmegacorp.com

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