Annotation of ntddk/src/comm/serial/modmflow.c, revision 1.1.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.