Annotation of ntddk/src/comm/serial/isr.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:     isr.c
                      8: 
                      9: Abstract:
                     10: 
                     11:     This module contains the interrupt service routine for the
                     12:     serial driver.
                     13: 
                     14: Author:
                     15: 
                     16:     Anthony V. Ercolano 26-Sep-1991
                     17: 
                     18: Environment:
                     19: 
                     20:     Kernel mode
                     21: 
                     22: Revision History :
                     23: 
                     24: --*/
                     25: 
                     26: #include <stddef.h>
                     27: #include "ntddk.h"
                     28: #include "ntddser.h"
                     29: #include "serial.h"
                     30: #include "serialp.h"
                     31: 
                     32: 
                     33: 
                     34: BOOLEAN
                     35: SerialSharerIsr(
                     36:     IN PKINTERRUPT InterruptObject,
                     37:     IN PVOID Context
                     38:     )
                     39: 
                     40: /*++
                     41: 
                     42: Routine Description:
                     43: 
                     44:     This is the isr that the system will call if there are any
                     45:     serial devices sharing the same interrupt and they aren't
                     46:     all confined to one multiport card.  This routine traverses
                     47:     a linked list structure that contains a pointer to a more
                     48:     refined isr and context that will indicate whether one of
                     49:     the ports on this interrupt actually was interrupting.
                     50: 
                     51: Arguments:
                     52: 
                     53:     InterruptObject - Points to the interrupt object declared for this
                     54:     device.  We *do not* use this parameter.
                     55: 
                     56:     Context - Pointer to a linked list of contextes and isrs.
                     57:     device.
                     58: 
                     59: Return Value:
                     60: 
                     61:     This function will return TRUE if a serial port using this
                     62:     interrupt was the source of this interrupt, FALSE otherwise.
                     63: 
                     64: --*/
                     65: 
                     66: {
                     67: 
                     68:     BOOLEAN servicedAnInterrupt = FALSE;
                     69:     BOOLEAN thisPassServiced;
                     70:     PLIST_ENTRY interruptEntry = Context;
                     71:     PLIST_ENTRY firstInterruptEntry = interruptEntry;
                     72: 
                     73:     do {
                     74: 
                     75:         thisPassServiced = FALSE;
                     76:         do {
                     77: 
                     78:             PSERIAL_DEVICE_EXTENSION extension = CONTAINING_RECORD(
                     79:                                                      interruptEntry,
                     80:                                                      SERIAL_DEVICE_EXTENSION,
                     81:                                                      TopLevelSharers
                     82:                                                      );
                     83: 
                     84:             thisPassServiced |= extension->TopLevelOurIsr(
                     85:                                     InterruptObject,
                     86:                                     extension->TopLevelOurIsrContext
                     87:                                     );
                     88: 
                     89:             servicedAnInterrupt |= thisPassServiced;
                     90:             interruptEntry = interruptEntry->Flink;
                     91: 
                     92:         } while (interruptEntry != firstInterruptEntry);
                     93: 
                     94:     } while (thisPassServiced);
                     95: 
                     96:     return servicedAnInterrupt;
                     97: 
                     98: }
                     99: 
                    100: BOOLEAN
                    101: SerialIndexedMultiportIsr(
                    102:     IN PKINTERRUPT InterruptObject,
                    103:     IN PVOID Context
                    104:     )
                    105: 
                    106: /*++
                    107: 
                    108: Routine Description:
                    109: 
                    110:     This routine is used to figure out if a port on a multiport
                    111:     card is the source of an interrupt.  If so, this routine
                    112:     uses a dispatch structure to actually call the normal isr
                    113:     to process the interrupt.
                    114: 
                    115:     NOTE: This routine is peculiar to Digiboard interrupt status registers.
                    116: 
                    117: Arguments:
                    118: 
                    119:     InterruptObject - Points to the interrupt object declared for this
                    120:     device.  We *do not* use this parameter.
                    121: 
                    122:     Context - Points to a dispatch structure that contains the
                    123:     device extension of each port on this multiport card.
                    124: 
                    125: Return Value:
                    126: 
                    127: 
                    128:     This function will return TRUE if a serial port using this
                    129:     interrupt was the source of this interrupt, FALSE otherwise.
                    130: 
                    131: --*/
                    132: 
                    133: {
                    134: 
                    135:     BOOLEAN servicedAnInterrupt = FALSE;
                    136:     BOOLEAN thisStatusReadServiced;
                    137:     PSERIAL_MULTIPORT_DISPATCH dispatch = Context;
                    138:     ULONG whichPort;
                    139:     UCHAR statusRegister;
                    140: 
                    141:     do {
                    142: 
                    143:         thisStatusReadServiced = FALSE;
                    144:         statusRegister = READ_PORT_UCHAR(
                    145:                              dispatch->InterruptStatus
                    146:                              );
                    147: 
                    148:         whichPort = statusRegister & 0x07;
                    149: 
                    150:         //
                    151:         // We test against 0xff, which signals that no port
                    152:         // is interruping. The reason 0xff (rather than 0)
                    153:         // is that that would indicate the 0th (first) port
                    154:         // or the 0th daisy chained card.
                    155:         //
                    156: 
                    157:         if (statusRegister != 0xff) {
                    158: 
                    159:             if (dispatch->Extensions[whichPort]) {
                    160: 
                    161:                 thisStatusReadServiced = SerialISR(
                    162:                                              InterruptObject,
                    163:                                               dispatch->Extensions[whichPort]
                    164:                                               );
                    165: 
                    166:                 servicedAnInterrupt |= thisStatusReadServiced;
                    167: 
                    168:             }
                    169: 
                    170:         }
                    171: 
                    172:     } while (thisStatusReadServiced);
                    173: 
                    174:     return servicedAnInterrupt;
                    175: 
                    176: }
                    177: 
                    178: BOOLEAN
                    179: SerialBitMappedMultiportIsr(
                    180:     IN PKINTERRUPT InterruptObject,
                    181:     IN PVOID Context
                    182:     )
                    183: 
                    184: /*++
                    185: 
                    186: Routine Description:
                    187: 
                    188:     This routine is used to figure out if a port on a multiport
                    189:     card is the source of an interrupt.  If so, this routine
                    190:     uses a dispatch structure to actually call the normal isr
                    191:     to process the interrupt.
                    192: 
                    193:     NOTE: This routine is peculiar to status registers that use
                    194:     a bitmask to denote the interrupting port.
                    195: 
                    196: Arguments:
                    197: 
                    198:     InterruptObject - Points to the interrupt object declared for this
                    199:     device.  We *do not* use this parameter.
                    200: 
                    201:     Context - Points to a dispatch structure that contains the
                    202:     device extension of each port on this multiport card.
                    203: 
                    204: Return Value:
                    205: 
                    206: 
                    207:     This function will return TRUE if a serial port using this
                    208:     interrupt was the source of this interrupt, FALSE otherwise.
                    209: 
                    210: --*/
                    211: 
                    212: {
                    213: 
                    214:     BOOLEAN servicedAnInterrupt = FALSE;
                    215:     PSERIAL_MULTIPORT_DISPATCH dispatch = Context;
                    216:     ULONG whichPort;
                    217:     UCHAR statusRegister;
                    218: 
                    219:     do {
                    220: 
                    221:         statusRegister = READ_PORT_UCHAR(
                    222:                              dispatch->InterruptStatus
                    223:                              );
                    224:         statusRegister &= dispatch->UsablePortMask;
                    225: 
                    226:         if (statusRegister) {
                    227: 
                    228:             if (statusRegister & 0x0f) {
                    229: 
                    230:                 if (statusRegister & 0x03) {
                    231: 
                    232:                     if (statusRegister & 1) {
                    233: 
                    234:                         whichPort = 0;
                    235: 
                    236:                     } else {
                    237: 
                    238:                         whichPort = 1;
                    239: 
                    240:                     }
                    241: 
                    242:                 } else {
                    243: 
                    244:                     if (statusRegister & 0x04) {
                    245: 
                    246:                         whichPort = 2;
                    247: 
                    248:                     } else {
                    249: 
                    250:                         whichPort = 3;
                    251: 
                    252:                     }
                    253: 
                    254:                 }
                    255: 
                    256:             } else {
                    257: 
                    258:                 if (statusRegister & 0x30) {
                    259: 
                    260:                     if (statusRegister & 0x10) {
                    261: 
                    262:                         whichPort = 4;
                    263: 
                    264:                     } else {
                    265: 
                    266:                         whichPort = 5;
                    267: 
                    268:                     }
                    269: 
                    270:                 } else {
                    271: 
                    272:                     if (statusRegister & 0x40) {
                    273: 
                    274:                         whichPort = 6;
                    275: 
                    276:                     } else {
                    277: 
                    278:                         whichPort = 7;
                    279: 
                    280:                     }
                    281: 
                    282:                 }
                    283: 
                    284:             }
                    285: 
                    286:             if (dispatch->Extensions[whichPort]) {
                    287: 
                    288:                 if (SerialISR(
                    289:                         InterruptObject,
                    290:                         dispatch->Extensions[whichPort]
                    291:                         )) {
                    292: 
                    293:                     servicedAnInterrupt = TRUE;
                    294: 
                    295:                 }
                    296: 
                    297:             }
                    298: 
                    299:         }
                    300: 
                    301:     } while (statusRegister);
                    302: 
                    303:     return servicedAnInterrupt;
                    304: 
                    305: }
                    306: 
                    307: BOOLEAN
                    308: SerialISR(
                    309:     IN PKINTERRUPT InterruptObject,
                    310:     IN PVOID Context
                    311:     )
                    312: 
                    313: /*++
                    314: 
                    315: Routine Description:
                    316: 
                    317:     This is the interrupt service routine for the serial port driver.
                    318:     It will determine whether the serial port is the source of this
                    319:     interrupt.  If it is, then this routine will do the minimum of
                    320:     processing to quiet the interrupt.  It will store any information
                    321:     necessary for later processing.
                    322: 
                    323: Arguments:
                    324: 
                    325:     InterruptObject - Points to the interrupt object declared for this
                    326:     device.  We *do not* use this parameter.
                    327: 
                    328:     Context - This is really a pointer to the device extension for this
                    329:     device.
                    330: 
                    331: Return Value:
                    332: 
                    333:     This function will return TRUE if the serial port is the source
                    334:     of this interrupt, FALSE otherwise.
                    335: 
                    336: --*/
                    337: 
                    338: {
                    339: 
                    340:     //
                    341:     // Holds the information specific to handling this device.
                    342:     //
                    343:     PSERIAL_DEVICE_EXTENSION Extension = Context;
                    344: 
                    345:     //
                    346:     // Holds the contents of the interrupt identification record.
                    347:     // A low bit of zero in this register indicates that there is
                    348:     // an interrupt pending on this device.
                    349:     //
                    350:     UCHAR InterruptIdReg;
                    351: 
                    352:     //
                    353:     // Will hold whether we've serviced any interrupt causes in this
                    354:     // routine.
                    355:     //
                    356:     BOOLEAN ServicedAnInterrupt;
                    357: 
                    358:     UNREFERENCED_PARAMETER(InterruptObject);
                    359: 
                    360:     //
                    361:     // Make sure we have an interrupt pending.  If we do then
                    362:     // we need to make sure that the device is open.  If the
                    363:     // device isn't open then quiet the device.  Note that
                    364:     // if the device isn't opened when we enter this routine
                    365:     // it can't open while we're in it.
                    366:     //
                    367: 
                    368:     InterruptIdReg = READ_INTERRUPT_ID_REG(Extension->Controller);
                    369: 
                    370:     if (InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING) {
                    371: 
                    372:         ServicedAnInterrupt = FALSE;
                    373: 
                    374:     } else if (!Extension->DeviceIsOpened) {
                    375: 
                    376:         //
                    377:         // We got an interrupt with the device being closed.  This
                    378:         // is not unlikely with a serial device.  We just quite
                    379:         // keep servicing the causes until it calms down.
                    380:         //
                    381: 
                    382:         ServicedAnInterrupt = TRUE;
                    383:         do {
                    384: 
                    385:             InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);
                    386:             switch (InterruptIdReg) {
                    387: 
                    388:                 case SERIAL_IIR_RLS: {
                    389: 
                    390:                     READ_LINE_STATUS(Extension->Controller);
                    391:                     break;
                    392: 
                    393:                 }
                    394: 
                    395:                 case SERIAL_IIR_RDA:
                    396:                 case SERIAL_IIR_CTI: {
                    397: 
                    398: 
                    399:                     READ_RECEIVE_BUFFER(Extension->Controller);
                    400:                     break;
                    401: 
                    402:                 }
                    403: 
                    404:                 case SERIAL_IIR_THR: {
                    405: 
                    406:                     //
                    407:                     // Alread clear from reading the iir.
                    408:                     //
                    409:                     // We want to keep close track of whether
                    410:                     // the holding register is empty.
                    411:                     //
                    412: 
                    413:                     Extension->HoldingEmpty = TRUE;
                    414:                     break;
                    415: 
                    416:                 }
                    417: 
                    418:                 case SERIAL_IIR_MS: {
                    419: 
                    420:                     READ_MODEM_STATUS(Extension->Controller);
                    421:                     break;
                    422: 
                    423:                 }
                    424: 
                    425:                 default: {
                    426: 
                    427:                     ASSERT(FALSE);
                    428:                     break;
                    429: 
                    430:                 }
                    431: 
                    432:             }
                    433: 
                    434:         } while (!((InterruptIdReg =
                    435:                     READ_INTERRUPT_ID_REG(Extension->Controller))
                    436:                     & SERIAL_IIR_NO_INTERRUPT_PENDING));
                    437:     } else {
                    438: 
                    439:         ServicedAnInterrupt = TRUE;
                    440:         do {
                    441: 
                    442:             //
                    443:             // We only care about bits that can denote an interrupt.
                    444:             //
                    445: 
                    446:             InterruptIdReg &= SERIAL_IIR_RLS | SERIAL_IIR_RDA |
                    447:                               SERIAL_IIR_CTI | SERIAL_IIR_THR |
                    448:                               SERIAL_IIR_MS;
                    449: 
                    450:             //
                    451:             // We have an interrupt.  We look for interrupt causes
                    452:             // in priority order.  The presence of a higher interrupt
                    453:             // will mask out causes of a lower priority.  When we service
                    454:             // and quiet a higher priority interrupt we then need to check
                    455:             // the interrupt causes to see if a new interrupt cause is
                    456:             // present.
                    457:             //
                    458: 
                    459:             switch (InterruptIdReg) {
                    460: 
                    461:                 case SERIAL_IIR_RLS: {
                    462: 
                    463:                     SerialProcessLSR(Extension);
                    464: 
                    465:                     break;
                    466: 
                    467:                 }
                    468: 
                    469:                 case SERIAL_IIR_RDA:
                    470:                 case SERIAL_IIR_CTI:
                    471: 
                    472:                 {
                    473: 
                    474:                     //
                    475:                     // Reading the receive buffer will quiet this interrupt.
                    476:                     //
                    477:                     // It may also reveal a new interrupt cause.
                    478:                     //
                    479:                     UCHAR ReceivedChar;
                    480: 
                    481:                     do {
                    482: 
                    483:                         ReceivedChar =
                    484:                             READ_RECEIVE_BUFFER(Extension->Controller);
                    485: 
                    486:                         ReceivedChar &= Extension->ValidDataMask;
                    487: 
                    488:                         if (!ReceivedChar &&
                    489:                             (Extension->HandFlow.FlowReplace &
                    490:                              SERIAL_NULL_STRIPPING)) {
                    491: 
                    492:                             //
                    493:                             // If what we got is a null character
                    494:                             // and we're doing null stripping, then
                    495:                             // we simply act as if we didn't see it.
                    496:                             //
                    497: 
                    498:                             goto ReceiveDoLineStatus;
                    499: 
                    500:                         }
                    501: 
                    502:                         if ((Extension->HandFlow.FlowReplace &
                    503:                              SERIAL_AUTO_TRANSMIT) &&
                    504:                             ((ReceivedChar ==
                    505:                               Extension->SpecialChars.XonChar) ||
                    506:                              (ReceivedChar ==
                    507:                               Extension->SpecialChars.XoffChar))) {
                    508: 
                    509:                             //
                    510:                             // No matter what happens this character
                    511:                             // will never get seen by the app.
                    512:                             //
                    513: 
                    514:                             if (ReceivedChar ==
                    515:                                 Extension->SpecialChars.XoffChar) {
                    516: 
                    517:                                 Extension->TXHolding |= SERIAL_TX_XOFF;
                    518: 
                    519:                                 if ((Extension->HandFlow.FlowReplace &
                    520:                                      SERIAL_RTS_MASK) ==
                    521:                                      SERIAL_TRANSMIT_TOGGLE) {
                    522: 
                    523:                                     KeInsertQueueDpc(
                    524:                                         &Extension->StartTimerLowerRTSDpc,
                    525:                                         NULL,
                    526:                                         NULL
                    527:                                         )?Extension->CountOfTryingToLowerRTS++:0;
                    528: 
                    529:                                 }
                    530: 
                    531:                             } else {
                    532: 
                    533:                                 if (Extension->TXHolding & SERIAL_TX_XOFF) {
                    534: 
                    535:                                     //
                    536:                                     // We've got the xon.  Cause the
                    537:                                     // transmission to restart.
                    538:                                     //
                    539:                                     // Prod the transmit.
                    540:                                     //
                    541: 
                    542:                                     SerialProdXonXoff(
                    543:                                         Extension,
                    544:                                         TRUE
                    545:                                         );
                    546: 
                    547:                                 }
                    548: 
                    549:                             }
                    550: 
                    551:                             goto ReceiveDoLineStatus;
                    552: 
                    553:                         }
                    554: 
                    555:                         //
                    556:                         // Check to see if we should note
                    557:                         // the receive character or special
                    558:                         // character event.
                    559:                         //
                    560: 
                    561:                         if (Extension->IsrWaitMask) {
                    562: 
                    563:                             if (Extension->IsrWaitMask &
                    564:                                 SERIAL_EV_RXCHAR) {
                    565: 
                    566:                                 Extension->HistoryMask |= SERIAL_EV_RXCHAR;
                    567: 
                    568:                             }
                    569: 
                    570:                             if ((Extension->IsrWaitMask &
                    571:                                  SERIAL_EV_RXFLAG) &&
                    572:                                 (Extension->SpecialChars.EventChar ==
                    573:                                  ReceivedChar)) {
                    574: 
                    575:                                 Extension->HistoryMask |= SERIAL_EV_RXFLAG;
                    576: 
                    577:                             }
                    578: 
                    579:                             if (Extension->IrpMaskLocation &&
                    580:                                 Extension->HistoryMask) {
                    581: 
                    582:                                 *Extension->IrpMaskLocation =
                    583:                                  Extension->HistoryMask;
                    584:                                 Extension->IrpMaskLocation = NULL;
                    585:                                 Extension->HistoryMask = 0;
                    586: 
                    587:                                 Extension->CurrentWaitIrp->
                    588:                                     IoStatus.Information = sizeof(ULONG);
                    589:                                 KeInsertQueueDpc(
                    590:                                     &Extension->CommWaitDpc,
                    591:                                     NULL,
                    592:                                     NULL
                    593:                                     );
                    594: 
                    595:                             }
                    596: 
                    597:                         }
                    598: 
                    599:                         SerialPutChar(
                    600:                             Extension,
                    601:                             ReceivedChar
                    602:                             );
                    603: 
                    604:                         //
                    605:                         // If we're doing line status and modem
                    606:                         // status insertion then we need to insert
                    607:                         // a zero following the character we just
                    608:                         // placed into the buffer to mark that this
                    609:                         // was reception of what we are using to
                    610:                         // escape.
                    611:                         //
                    612: 
                    613:                         if (Extension->EscapeChar &&
                    614:                             (Extension->EscapeChar ==
                    615:                              ReceivedChar)) {
                    616: 
                    617:                             SerialPutChar(
                    618:                                 Extension,
                    619:                                 SERIAL_LSRMST_ESCAPE
                    620:                                 );
                    621: 
                    622:                         }
                    623: 
                    624: 
                    625: ReceiveDoLineStatus:    ;
                    626: 
                    627:                         if (!(SerialProcessLSR(Extension) &
                    628:                               SERIAL_LSR_DR)) {
                    629: 
                    630:                             //
                    631:                             // No more characters, get out of the
                    632:                             // loop.
                    633:                             //
                    634: 
                    635:                             break;
                    636: 
                    637:                         }
                    638: 
                    639:                     } while (TRUE);
                    640: 
                    641:                     break;
                    642: 
                    643:                 }
                    644: 
                    645:                 case SERIAL_IIR_THR: {
                    646: 
                    647:                     Extension->HoldingEmpty = TRUE;
                    648: 
                    649:                     if (Extension->WriteLength |
                    650:                         Extension->TransmitImmediate |
                    651:                         Extension->SendXoffChar |
                    652:                         Extension->SendXonChar) {
                    653: 
                    654:                         //
                    655:                         // Even though all of the characters being
                    656:                         // sent haven't all been sent, this variable
                    657:                         // will be checked when the transmit queue is
                    658:                         // empty.  If it is still true and there is a
                    659:                         // wait on the transmit queue being empty then
                    660:                         // we know we finished transmitting all characters
                    661:                         // following the initiation of the wait since
                    662:                         // the code that initiates the wait will set
                    663:                         // this variable to false.
                    664:                         //
                    665:                         // One reason it could be false is that
                    666:                         // the writes were cancelled before they
                    667:                         // actually started, or that the writes
                    668:                         // failed due to timeouts.  This variable
                    669:                         // basically says a character was written
                    670:                         // by the isr at some point following the
                    671:                         // initiation of the wait.
                    672:                         //
                    673: 
                    674:                         Extension->EmptiedTransmit = TRUE;
                    675: 
                    676:                         //
                    677:                         // If we have output flow control based on
                    678:                         // the modem status lines, then we have to do
                    679:                         // all the modem work before we output each
                    680:                         // character. (Otherwise we might miss a
                    681:                         // status line change.)
                    682:                         //
                    683: 
                    684:                         if (Extension->HandFlow.ControlHandShake &
                    685:                             SERIAL_OUT_HANDSHAKEMASK) {
                    686: 
                    687:                             SerialHandleModemUpdate(
                    688:                                 Extension,
                    689:                                 TRUE
                    690:                                 );
                    691: 
                    692:                         }
                    693: 
                    694:                         //
                    695:                         // We can only send the xon character if
                    696:                         // the only reason we are holding is because
                    697:                         // of the xoff.  (Hardware flow control or
                    698:                         // sending break preclude putting a new character
                    699:                         // on the wire.)
                    700:                         //
                    701: 
                    702:                         if (Extension->SendXonChar &&
                    703:                             !(Extension->TXHolding & ~SERIAL_TX_XOFF)) {
                    704: 
                    705:                             if ((Extension->HandFlow.FlowReplace &
                    706:                                  SERIAL_RTS_MASK) ==
                    707:                                  SERIAL_TRANSMIT_TOGGLE) {
                    708: 
                    709:                                 //
                    710:                                 // We have to raise if we're sending
                    711:                                 // this character.
                    712:                                 //
                    713: 
                    714:                                 SerialSetRTS(Extension);
                    715: 
                    716:                                 WRITE_TRANSMIT_HOLDING(
                    717:                                     Extension->Controller,
                    718:                                     Extension->SpecialChars.XonChar
                    719:                                     );
                    720: 
                    721:                                 KeInsertQueueDpc(
                    722:                                     &Extension->StartTimerLowerRTSDpc,
                    723:                                     NULL,
                    724:                                     NULL
                    725:                                     )?Extension->CountOfTryingToLowerRTS++:0;
                    726: 
                    727:                             } else {
                    728: 
                    729:                                 WRITE_TRANSMIT_HOLDING(
                    730:                                     Extension->Controller,
                    731:                                     Extension->SpecialChars.XonChar
                    732:                                     );
                    733: 
                    734:                             }
                    735: 
                    736: 
                    737:                             Extension->SendXonChar = FALSE;
                    738:                             Extension->HoldingEmpty = FALSE;
                    739: 
                    740:                             //
                    741:                             // If we send an xon, by definition we
                    742:                             // can't be holding by Xoff.
                    743:                             //
                    744: 
                    745:                             Extension->TXHolding &= ~SERIAL_TX_XOFF;
                    746: 
                    747:                             //
                    748:                             // If we are sending an xon char then
                    749:                             // by definition we can't be "holding"
                    750:                             // up reception by Xoff.
                    751:                             //
                    752: 
                    753:                             Extension->RXHolding &= ~SERIAL_RX_XOFF;
                    754: 
                    755:                         } else if (Extension->SendXoffChar &&
                    756:                               !Extension->TXHolding) {
                    757: 
                    758:                             if ((Extension->HandFlow.FlowReplace &
                    759:                                  SERIAL_RTS_MASK) ==
                    760:                                  SERIAL_TRANSMIT_TOGGLE) {
                    761: 
                    762:                                 //
                    763:                                 // We have to raise if we're sending
                    764:                                 // this character.
                    765:                                 //
                    766: 
                    767:                                 SerialSetRTS(Extension);
                    768: 
                    769:                                 WRITE_TRANSMIT_HOLDING(
                    770:                                     Extension->Controller,
                    771:                                     Extension->SpecialChars.XoffChar
                    772:                                     );
                    773: 
                    774:                                 KeInsertQueueDpc(
                    775:                                     &Extension->StartTimerLowerRTSDpc,
                    776:                                     NULL,
                    777:                                     NULL
                    778:                                     )?Extension->CountOfTryingToLowerRTS++:0;
                    779: 
                    780:                             } else {
                    781: 
                    782:                                 WRITE_TRANSMIT_HOLDING(
                    783:                                     Extension->Controller,
                    784:                                     Extension->SpecialChars.XoffChar
                    785:                                     );
                    786: 
                    787:                             }
                    788: 
                    789:                             //
                    790:                             // We can't be sending an Xoff character
                    791:                             // if the transmission is already held
                    792:                             // up because of Xoff.  Therefore, if we
                    793:                             // are holding then we can't send the char.
                    794:                             //
                    795: 
                    796:                             //
                    797:                             // If the application has set xoff continue
                    798:                             // mode then we don't actually stop sending
                    799:                             // characters if we send an xoff to the other
                    800:                             // side.
                    801:                             //
                    802: 
                    803:                             if (!(Extension->HandFlow.FlowReplace &
                    804:                                   SERIAL_XOFF_CONTINUE)) {
                    805: 
                    806:                                 Extension->TXHolding |= SERIAL_TX_XOFF;
                    807: 
                    808:                                 if ((Extension->HandFlow.FlowReplace &
                    809:                                      SERIAL_RTS_MASK) ==
                    810:                                      SERIAL_TRANSMIT_TOGGLE) {
                    811: 
                    812:                                     KeInsertQueueDpc(
                    813:                                         &Extension->StartTimerLowerRTSDpc,
                    814:                                         NULL,
                    815:                                         NULL
                    816:                                         )?Extension->CountOfTryingToLowerRTS++:0;
                    817: 
                    818:                                 }
                    819: 
                    820:                             }
                    821: 
                    822:                             Extension->SendXoffChar = FALSE;
                    823:                             Extension->HoldingEmpty = FALSE;
                    824: 
                    825:                         //
                    826:                         // Even if transmission is being held
                    827:                         // up, we should still transmit an immediate
                    828:                         // character if all that is holding us
                    829:                         // up is xon/xoff (OS/2 rules).
                    830:                         //
                    831: 
                    832:                         } else if (Extension->TransmitImmediate &&
                    833:                             (!Extension->TXHolding ||
                    834:                              (Extension->TXHolding == SERIAL_TX_XOFF)
                    835:                             )) {
                    836: 
                    837:                             Extension->TransmitImmediate = FALSE;
                    838: 
                    839:                             if ((Extension->HandFlow.FlowReplace &
                    840:                                  SERIAL_RTS_MASK) ==
                    841:                                  SERIAL_TRANSMIT_TOGGLE) {
                    842: 
                    843:                                 //
                    844:                                 // We have to raise if we're sending
                    845:                                 // this character.
                    846:                                 //
                    847: 
                    848:                                 SerialSetRTS(Extension);
                    849: 
                    850:                                 WRITE_TRANSMIT_HOLDING(
                    851:                                     Extension->Controller,
                    852:                                     Extension->ImmediateChar
                    853:                                     );
                    854: 
                    855:                                 KeInsertQueueDpc(
                    856:                                     &Extension->StartTimerLowerRTSDpc,
                    857:                                     NULL,
                    858:                                     NULL
                    859:                                     )?Extension->CountOfTryingToLowerRTS++:0;
                    860: 
                    861:                             } else {
                    862: 
                    863:                                 WRITE_TRANSMIT_HOLDING(
                    864:                                     Extension->Controller,
                    865:                                     Extension->ImmediateChar
                    866:                                     );
                    867: 
                    868:                             }
                    869: 
                    870:                             Extension->HoldingEmpty = FALSE;
                    871: 
                    872:                             KeInsertQueueDpc(
                    873:                                 &Extension->CompleteImmediateDpc,
                    874:                                 NULL,
                    875:                                 NULL
                    876:                                 );
                    877: 
                    878:                         } else if (!Extension->TXHolding) {
                    879: 
                    880:                             if ((Extension->HandFlow.FlowReplace &
                    881:                                  SERIAL_RTS_MASK) ==
                    882:                                  SERIAL_TRANSMIT_TOGGLE) {
                    883: 
                    884:                                 //
                    885:                                 // We have to raise if we're sending
                    886:                                 // this character.
                    887:                                 //
                    888: 
                    889:                                 SerialSetRTS(Extension);
                    890: 
                    891:                                 WRITE_TRANSMIT_HOLDING(
                    892:                                     Extension->Controller,
                    893:                                     *(Extension->WriteCurrentChar)
                    894:                                     );
                    895: 
                    896:                                 KeInsertQueueDpc(
                    897:                                     &Extension->StartTimerLowerRTSDpc,
                    898:                                     NULL,
                    899:                                     NULL
                    900:                                     )?Extension->CountOfTryingToLowerRTS++:0;
                    901: 
                    902:                             } else {
                    903: 
                    904:                                 WRITE_TRANSMIT_HOLDING(
                    905:                                     Extension->Controller,
                    906:                                     *(Extension->WriteCurrentChar)
                    907:                                     );
                    908: 
                    909:                             }
                    910: 
                    911:                             Extension->HoldingEmpty = FALSE;
                    912:                             Extension->WriteCurrentChar++;
                    913:                             Extension->WriteLength--;
                    914: 
                    915:                             if (!Extension->WriteLength) {
                    916: 
                    917:                                 PIO_STACK_LOCATION IrpSp;
                    918:                                 //
                    919:                                 // No More characters left.  This
                    920:                                 // write is complete.  Take care
                    921:                                 // when updating the information field,
                    922:                                 // we could have an xoff counter masquerading
                    923:                                 // as a write irp.
                    924:                                 //
                    925: 
                    926:                                 IrpSp = IoGetCurrentIrpStackLocation(
                    927:                                             Extension->CurrentWriteIrp
                    928:                                             );
                    929: 
                    930:                                 Extension->CurrentWriteIrp->
                    931:                                     IoStatus.Information =
                    932:                                     (IrpSp->MajorFunction == IRP_MJ_WRITE)?
                    933:                                         (IrpSp->Parameters.Write.Length):
                    934:                                         (1);
                    935: 
                    936:                                 KeInsertQueueDpc(
                    937:                                     &Extension->CompleteWriteDpc,
                    938:                                     NULL,
                    939:                                     NULL
                    940:                                     );
                    941: 
                    942:                             }
                    943: 
                    944:                         }
                    945: 
                    946:                     }
                    947: 
                    948:                     break;
                    949: 
                    950:                 }
                    951: 
                    952:                 case SERIAL_IIR_MS: {
                    953: 
                    954:                     SerialHandleModemUpdate(
                    955:                         Extension,
                    956:                         FALSE
                    957:                         );
                    958: 
                    959:                     break;
                    960: 
                    961:                 }
                    962: 
                    963:             }
                    964: 
                    965:         } while (!((InterruptIdReg =
                    966:                     READ_INTERRUPT_ID_REG(Extension->Controller))
                    967:                     & SERIAL_IIR_NO_INTERRUPT_PENDING));
                    968: 
                    969:     }
                    970: 
                    971:     return ServicedAnInterrupt;
                    972: 
                    973: }
                    974: 
                    975: VOID
                    976: SerialPutChar(
                    977:     IN PSERIAL_DEVICE_EXTENSION Extension,
                    978:     IN UCHAR CharToPut
                    979:     )
                    980: 
                    981: /*++
                    982: 
                    983: Routine Description:
                    984: 
                    985:     This routine, which only runs at device level, takes care of
                    986:     placing a character into the typeahead (receive) buffer.
                    987: 
                    988: Arguments:
                    989: 
                    990:     Extension - The serial device extension.
                    991: 
                    992: Return Value:
                    993: 
                    994:     None.
                    995: 
                    996: --*/
                    997: 
                    998: {
                    999: 
                   1000:     //
                   1001:     // If we have dsr sensitivity enabled then
                   1002:     // we need to check the modem status register
                   1003:     // to see if it has changed.
                   1004:     //
                   1005: 
                   1006:     if (Extension->HandFlow.ControlHandShake &
                   1007:         SERIAL_DSR_SENSITIVITY) {
                   1008: 
                   1009:         SerialHandleModemUpdate(
                   1010:             Extension,
                   1011:             FALSE
                   1012:             );
                   1013: 
                   1014:         if (Extension->RXHolding & SERIAL_RX_DSR) {
                   1015: 
                   1016:             //
                   1017:             // We simply act as if we haven't
                   1018:             // seen the character if we have dsr
                   1019:             // sensitivity and the dsr line is low.
                   1020:             //
                   1021: 
                   1022:             return;
                   1023: 
                   1024:         }
                   1025: 
                   1026:     }
                   1027: 
                   1028:     //
                   1029:     // If the xoff counter is non-zero then decrement it.
                   1030:     // If the counter then goes to zero, complete that irp.
                   1031:     //
                   1032: 
                   1033:     if (Extension->CountSinceXoff) {
                   1034: 
                   1035:         Extension->CountSinceXoff--;
                   1036: 
                   1037:         if (!Extension->CountSinceXoff) {
                   1038: 
                   1039:             Extension->CurrentXoffIrp->IoStatus.Status = STATUS_SUCCESS;
                   1040:             Extension->CurrentXoffIrp->IoStatus.Information = 0;
                   1041:             KeInsertQueueDpc(
                   1042:                 &Extension->XoffCountCompleteDpc,
                   1043:                 NULL,
                   1044:                 NULL
                   1045:                 );
                   1046: 
                   1047:         }
                   1048: 
                   1049:     }
                   1050: 
                   1051:     //
                   1052:     // Check to see if we are copying into the
                   1053:     // users buffer or into the interrupt buffer.
                   1054:     //
                   1055:     // If we are copying into the user buffer
                   1056:     // then we know there is always room for one more.
                   1057:     // (We know this because if there wasn't room
                   1058:     // then that read would have completed and we
                   1059:     // would be using the interrupt buffer.)
                   1060:     //
                   1061:     // If we are copying into the interrupt buffer
                   1062:     // then we will need to check if we have enough
                   1063:     // room.
                   1064:     //
                   1065: 
                   1066:     if (Extension->ReadBufferBase !=
                   1067:         Extension->InterruptReadBuffer) {
                   1068: 
                   1069:         //
                   1070:         // Increment the following value so
                   1071:         // that the interval timer (if one exists
                   1072:         // for this read) can know that a character
                   1073:         // has been read.
                   1074:         //
                   1075: 
                   1076:         Extension->ReadByIsr++;
                   1077: 
                   1078:         //
                   1079:         // We are in the user buffer.  Place the
                   1080:         // character into the buffer.  See if the
                   1081:         // read is complete.
                   1082:         //
                   1083: 
                   1084:         *Extension->CurrentCharSlot = CharToPut;
                   1085: 
                   1086:         if (Extension->CurrentCharSlot ==
                   1087:             Extension->LastCharSlot) {
                   1088: 
                   1089:             //
                   1090:             // We've filled up the users buffer.
                   1091:             // Switch back to the interrupt buffer
                   1092:             // and send off a DPC to Complete the read.
                   1093:             //
                   1094:             // It is inherent that when we were using
                   1095:             // a user buffer that the interrupt buffer
                   1096:             // was empty.
                   1097:             //
                   1098: 
                   1099:             Extension->ReadBufferBase =
                   1100:                 Extension->InterruptReadBuffer;
                   1101:             Extension->CurrentCharSlot =
                   1102:                 Extension->InterruptReadBuffer;
                   1103:             Extension->FirstReadableChar =
                   1104:                 Extension->InterruptReadBuffer;
                   1105:             Extension->LastCharSlot =
                   1106:                 Extension->InterruptReadBuffer +
                   1107:                 (Extension->BufferSize - 1);
                   1108:             Extension->CharsInInterruptBuffer = 0;
                   1109: 
                   1110:             Extension->CurrentReadIrp->IoStatus.Information =
                   1111:                 IoGetCurrentIrpStackLocation(
                   1112:                     Extension->CurrentReadIrp
                   1113:                     )->Parameters.Read.Length;
                   1114: 
                   1115:             KeInsertQueueDpc(
                   1116:                 &Extension->CompleteReadDpc,
                   1117:                 NULL,
                   1118:                 NULL
                   1119:                 );
                   1120: 
                   1121:         } else {
                   1122: 
                   1123:             //
                   1124:             // Not done with the users read.
                   1125:             //
                   1126: 
                   1127:             Extension->CurrentCharSlot++;
                   1128: 
                   1129:         }
                   1130: 
                   1131:     } else {
                   1132: 
                   1133:         //
                   1134:         // We need to see if we reached our flow
                   1135:         // control threshold.  If we have then
                   1136:         // we turn on whatever flow control the
                   1137:         // owner has specified.  If no flow
                   1138:         // control was specified, well..., we keep
                   1139:         // trying to receive characters and hope that
                   1140:         // we have enough room.  Note that no matter
                   1141:         // what flow control protocol we are using, it
                   1142:         // will not prevent us from reading whatever
                   1143:         // characters are available.
                   1144:         //
                   1145: 
                   1146:         if ((Extension->HandFlow.ControlHandShake
                   1147:              & SERIAL_DTR_MASK) ==
                   1148:             SERIAL_DTR_HANDSHAKE) {
                   1149: 
                   1150:             //
                   1151:             // If we are already doing a
                   1152:             // dtr hold then we don't have
                   1153:             // to do anything else.
                   1154:             //
                   1155: 
                   1156:             if (!(Extension->RXHolding &
                   1157:                   SERIAL_RX_DTR)) {
                   1158: 
                   1159:                 if ((Extension->BufferSize -
                   1160:                      Extension->HandFlow.XoffLimit)
                   1161:                     <= (Extension->CharsInInterruptBuffer+1)) {
                   1162: 
                   1163:                     Extension->RXHolding |= SERIAL_RX_DTR;
                   1164: 
                   1165:                     SerialClrDTR(Extension);
                   1166: 
                   1167:                 }
                   1168: 
                   1169:             }
                   1170: 
                   1171:         }
                   1172: 
                   1173:         if ((Extension->HandFlow.FlowReplace
                   1174:              & SERIAL_RTS_MASK) ==
                   1175:             SERIAL_RTS_HANDSHAKE) {
                   1176: 
                   1177:             //
                   1178:             // If we are already doing a
                   1179:             // rts hold then we don't have
                   1180:             // to do anything else.
                   1181:             //
                   1182: 
                   1183:             if (!(Extension->RXHolding &
                   1184:                   SERIAL_RX_RTS)) {
                   1185: 
                   1186:                 if ((Extension->BufferSize -
                   1187:                      Extension->HandFlow.XoffLimit)
                   1188:                     <= (Extension->CharsInInterruptBuffer+1)) {
                   1189: 
                   1190:                     Extension->RXHolding |= SERIAL_RX_RTS;
                   1191: 
                   1192:                     SerialClrRTS(Extension);
                   1193: 
                   1194:                 }
                   1195: 
                   1196:             }
                   1197: 
                   1198:         }
                   1199: 
                   1200:         if (Extension->HandFlow.FlowReplace &
                   1201:             SERIAL_AUTO_RECEIVE) {
                   1202: 
                   1203:             //
                   1204:             // If we are already doing a
                   1205:             // xoff hold then we don't have
                   1206:             // to do anything else.
                   1207:             //
                   1208: 
                   1209:             if (!(Extension->RXHolding &
                   1210:                   SERIAL_RX_XOFF)) {
                   1211: 
                   1212:                 if ((Extension->BufferSize -
                   1213:                      Extension->HandFlow.XoffLimit)
                   1214:                     <= (Extension->CharsInInterruptBuffer+1)) {
                   1215: 
                   1216:                     Extension->RXHolding |= SERIAL_RX_XOFF;
                   1217: 
                   1218:                     //
                   1219:                     // If necessary cause an
                   1220:                     // off to be sent.
                   1221:                     //
                   1222: 
                   1223:                     SerialProdXonXoff(
                   1224:                         Extension,
                   1225:                         FALSE
                   1226:                         );
                   1227: 
                   1228:                 }
                   1229: 
                   1230:             }
                   1231: 
                   1232:         }
                   1233: 
                   1234:         if (Extension->CharsInInterruptBuffer <
                   1235:             Extension->BufferSize) {
                   1236: 
                   1237:             *Extension->CurrentCharSlot = CharToPut;
                   1238:             Extension->CharsInInterruptBuffer++;
                   1239: 
                   1240:             //
                   1241:             // If we've become 80% full on this character
                   1242:             // and this is an interesting event, note it.
                   1243:             //
                   1244: 
                   1245:             if (Extension->CharsInInterruptBuffer ==
                   1246:                 Extension->BufferSizePt8) {
                   1247: 
                   1248:                 if (Extension->IsrWaitMask &
                   1249:                     SERIAL_EV_RX80FULL) {
                   1250: 
                   1251:                     Extension->HistoryMask |= SERIAL_EV_RX80FULL;
                   1252: 
                   1253:                     if (Extension->IrpMaskLocation) {
                   1254: 
                   1255:                         *Extension->IrpMaskLocation =
                   1256:                          Extension->HistoryMask;
                   1257:                         Extension->IrpMaskLocation = NULL;
                   1258:                         Extension->HistoryMask = 0;
                   1259: 
                   1260:                         Extension->CurrentWaitIrp->
                   1261:                             IoStatus.Information = sizeof(ULONG);
                   1262:                         KeInsertQueueDpc(
                   1263:                             &Extension->CommWaitDpc,
                   1264:                             NULL,
                   1265:                             NULL
                   1266:                             );
                   1267: 
                   1268:                     }
                   1269: 
                   1270:                 }
                   1271: 
                   1272:             }
                   1273: 
                   1274:             //
                   1275:             // Point to the next available space
                   1276:             // for a received character.  Make sure
                   1277:             // that we wrap around to the beginning
                   1278:             // of the buffer if this last character
                   1279:             // received was placed at the last slot
                   1280:             // in the buffer.
                   1281:             //
                   1282: 
                   1283:             if (Extension->CurrentCharSlot ==
                   1284:                 Extension->LastCharSlot) {
                   1285: 
                   1286:                 Extension->CurrentCharSlot =
                   1287:                     Extension->InterruptReadBuffer;
                   1288: 
                   1289:             } else {
                   1290: 
                   1291:                 Extension->CurrentCharSlot++;
                   1292: 
                   1293:             }
                   1294: 
                   1295:         } else {
                   1296: 
                   1297:             //
                   1298:             // We have a new character but no room for it.
                   1299:             //
                   1300: 
                   1301:             Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
                   1302: 
                   1303:             if (Extension->HandFlow.FlowReplace &
                   1304:                 SERIAL_ERROR_CHAR) {
                   1305: 
                   1306:                 //
                   1307:                 // Place the error character into the last
                   1308:                 // valid place for a character.  Be careful!,
                   1309:                 // that place might not be the previous location!
                   1310:                 //
                   1311: 
                   1312:                 if (Extension->CurrentCharSlot ==
                   1313:                     Extension->InterruptReadBuffer) {
                   1314: 
                   1315:                     *(Extension->InterruptReadBuffer+
                   1316:                       (Extension->BufferSize-1)) =
                   1317:                       Extension->SpecialChars.ErrorChar;
                   1318: 
                   1319:                 } else {
                   1320: 
                   1321:                     *(Extension->CurrentCharSlot-1) =
                   1322:                      Extension->SpecialChars.ErrorChar;
                   1323: 
                   1324:                 }
                   1325: 
                   1326:             }
                   1327: 
                   1328:             //
                   1329:             // If the application has requested it, abort all reads
                   1330:             // and writes on an error.
                   1331:             //
                   1332: 
                   1333:             if (Extension->HandFlow.ControlHandShake &
                   1334:                 SERIAL_ERROR_ABORT) {
                   1335: 
                   1336:                 KeInsertQueueDpc(
                   1337:                     &Extension->CommErrorDpc,
                   1338:                     NULL,
                   1339:                     NULL
                   1340:                     );
                   1341: 
                   1342:             }
                   1343: 
                   1344:         }
                   1345: 
                   1346:     }
                   1347: 
                   1348: }
                   1349: 
                   1350: UCHAR
                   1351: SerialProcessLSR(
                   1352:     IN PSERIAL_DEVICE_EXTENSION Extension
                   1353:     )
                   1354: 
                   1355: /*++
                   1356: 
                   1357: Routine Description:
                   1358: 
                   1359:     This routine, which only runs at device level, reads the
                   1360:     ISR and totally processes everything that might have
                   1361:     changed.
                   1362: 
                   1363: Arguments:
                   1364: 
                   1365:     Extension - The serial device extension.
                   1366: 
                   1367: Return Value:
                   1368: 
                   1369:     The value of the line status register.
                   1370: 
                   1371: --*/
                   1372: 
                   1373: {
                   1374: 
                   1375:     UCHAR LineStatus = READ_LINE_STATUS(Extension->Controller);
                   1376: 
                   1377:     Extension->HoldingEmpty = !!(LineStatus & SERIAL_LSR_THRE);
                   1378: 
                   1379:     //
                   1380:     // If the line status register is just the fact that
                   1381:     // the trasmit registers are empty or a character is
                   1382:     // received then we want to reread the interrupt
                   1383:     // identification register so that we just pick up that.
                   1384:     //
                   1385: 
                   1386:     if (LineStatus & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT
                   1387:                        | SERIAL_LSR_DR)) {
                   1388: 
                   1389:         //
                   1390:         // We have some sort of data problem in the receive.
                   1391:         // For any of these errors we may abort all current
                   1392:         // reads and writes.
                   1393:         //
                   1394:         //
                   1395:         // If we are inserting the value of the line status
                   1396:         // into the data stream then we should put the escape
                   1397:         // character in now.
                   1398:         //
                   1399: 
                   1400:         if (Extension->EscapeChar) {
                   1401: 
                   1402:             SerialPutChar(
                   1403:                 Extension,
                   1404:                 Extension->EscapeChar
                   1405:                 );
                   1406: 
                   1407:             SerialPutChar(
                   1408:                 Extension,
                   1409:                 (UCHAR)((LineStatus & SERIAL_LSR_DR)?
                   1410:                     (SERIAL_LSRMST_LSR_DATA):(SERIAL_LSRMST_LSR_NODATA))
                   1411:                 );
                   1412: 
                   1413:             SerialPutChar(
                   1414:                 Extension,
                   1415:                 LineStatus
                   1416:                 );
                   1417: 
                   1418:             if (LineStatus & SERIAL_LSR_DR) {
                   1419: 
                   1420:                 SerialPutChar(
                   1421:                     Extension,
                   1422:                     READ_RECEIVE_BUFFER(Extension->Controller)
                   1423:                     );
                   1424: 
                   1425:             }
                   1426: 
                   1427:         }
                   1428: 
                   1429:         if (LineStatus & SERIAL_LSR_OE) {
                   1430: 
                   1431:             Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
                   1432: 
                   1433:             if (Extension->HandFlow.FlowReplace &
                   1434:                 SERIAL_ERROR_CHAR) {
                   1435: 
                   1436:                 SerialPutChar(
                   1437:                     Extension,
                   1438:                     Extension->SpecialChars.ErrorChar
                   1439:                     );
                   1440: 
                   1441:             }
                   1442: 
                   1443:             if (LineStatus & SERIAL_LSR_DR) {
                   1444: 
                   1445:                 SerialPutChar(
                   1446:                     Extension,
                   1447:                     READ_RECEIVE_BUFFER(
                   1448:                         Extension->Controller
                   1449:                         )
                   1450:                     );
                   1451: 
                   1452:             }
                   1453: 
                   1454:         }
                   1455: 
                   1456:         if (LineStatus & SERIAL_LSR_BI) {
                   1457: 
                   1458:             Extension->ErrorWord |= SERIAL_ERROR_BREAK;
                   1459: 
                   1460:             if (Extension->HandFlow.FlowReplace &
                   1461:                 SERIAL_BREAK_CHAR) {
                   1462: 
                   1463:                 SerialPutChar(
                   1464:                     Extension,
                   1465:                     Extension->SpecialChars.BreakChar
                   1466:                     );
                   1467: 
                   1468:             }
                   1469: 
                   1470:         } else {
                   1471: 
                   1472:             //
                   1473:             // Framing errors only count if they
                   1474:             // occur exclusive of a break being
                   1475:             // received.
                   1476:             //
                   1477: 
                   1478:             if (LineStatus & SERIAL_LSR_PE) {
                   1479: 
                   1480:                 Extension->ErrorWord |= SERIAL_ERROR_PARITY;
                   1481: 
                   1482:                 if (Extension->HandFlow.FlowReplace &
                   1483:                     SERIAL_ERROR_CHAR) {
                   1484: 
                   1485:                     SerialPutChar(
                   1486:                         Extension,
                   1487:                         Extension->SpecialChars.ErrorChar
                   1488:                         );
                   1489: 
                   1490:                 }
                   1491: 
                   1492:             }
                   1493: 
                   1494:             if (LineStatus & SERIAL_LSR_FE) {
                   1495: 
                   1496:                 Extension->ErrorWord |= SERIAL_ERROR_FRAMING;
                   1497: 
                   1498: 
                   1499:                 if (Extension->HandFlow.FlowReplace &
                   1500:                     SERIAL_ERROR_CHAR) {
                   1501: 
                   1502:                     SerialPutChar(
                   1503:                         Extension,
                   1504:                         Extension->SpecialChars.ErrorChar
                   1505:                         );
                   1506: 
                   1507:                 }
                   1508: 
                   1509:             }
                   1510: 
                   1511:         }
                   1512: 
                   1513:         //
                   1514:         // If the application has requested it,
                   1515:         // abort all the reads and writes
                   1516:         // on an error.
                   1517:         //
                   1518: 
                   1519:         if (Extension->HandFlow.ControlHandShake &
                   1520:             SERIAL_ERROR_ABORT) {
                   1521: 
                   1522:             KeInsertQueueDpc(
                   1523:                 &Extension->CommErrorDpc,
                   1524:                 NULL,
                   1525:                 NULL
                   1526:                 );
                   1527: 
                   1528:         }
                   1529: 
                   1530:         //
                   1531:         // Check to see if we have a wait
                   1532:         // pending on the comm error events.  If we
                   1533:         // do then we schedule a dpc to satisfy
                   1534:         // that wait.
                   1535:         //
                   1536: 
                   1537:         if (Extension->IsrWaitMask) {
                   1538: 
                   1539:             if ((Extension->IsrWaitMask & SERIAL_EV_ERR) &&
                   1540:                 (LineStatus & (SERIAL_LSR_OE |
                   1541:                                SERIAL_LSR_PE |
                   1542:                                SERIAL_LSR_FE))) {
                   1543: 
                   1544:                 Extension->HistoryMask |= SERIAL_EV_ERR;
                   1545: 
                   1546:             }
                   1547: 
                   1548:             if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) &&
                   1549:                 (LineStatus & SERIAL_LSR_BI)) {
                   1550: 
                   1551:                 Extension->HistoryMask |= SERIAL_EV_BREAK;
                   1552: 
                   1553:             }
                   1554: 
                   1555:             if (Extension->IrpMaskLocation &&
                   1556:                 Extension->HistoryMask) {
                   1557: 
                   1558:                 *Extension->IrpMaskLocation =
                   1559:                  Extension->HistoryMask;
                   1560:                 Extension->IrpMaskLocation = NULL;
                   1561:                 Extension->HistoryMask = 0;
                   1562: 
                   1563:                 Extension->CurrentWaitIrp->IoStatus.Information =
                   1564:                     sizeof(ULONG);
                   1565:                 KeInsertQueueDpc(
                   1566:                     &Extension->CommWaitDpc,
                   1567:                     NULL,
                   1568:                     NULL
                   1569:                     );
                   1570: 
                   1571:             }
                   1572: 
                   1573:         }
                   1574: 
                   1575:         if (LineStatus & SERIAL_LSR_THRE) {
                   1576: 
                   1577:             //
                   1578:             // There is a hardware bug in some versions
                   1579:             // of the 16450 and 550.  If THRE interrupt
                   1580:             // is pending, but a higher interrupt comes
                   1581:             // in it will only return the higher and
                   1582:             // *forget* about the THRE.
                   1583:             //
                   1584:             // A suitable workaround - whenever we
                   1585:             // are *all* done reading line status
                   1586:             // of the device we check to see if the
                   1587:             // transmit holding register is empty.  If it is
                   1588:             // AND we are currently transmitting data
                   1589:             // enable the interrupts which should cause
                   1590:             // an interrupt indication which we quiet
                   1591:             // when we read the interrupt id register.
                   1592:             //
                   1593: 
                   1594:             if (Extension->WriteLength |
                   1595:                 Extension->TransmitImmediate) {
                   1596: 
                   1597:                 DISABLE_ALL_INTERRUPTS(
                   1598:                     Extension->Controller
                   1599:                     );
                   1600:                 ENABLE_ALL_INTERRUPTS(
                   1601:                     Extension->Controller
                   1602:                     );
                   1603: 
                   1604:             }
                   1605: 
                   1606:         }
                   1607: 
                   1608:     }
                   1609: 
                   1610:     return LineStatus;
                   1611: 
                   1612: }

unix.superglobalmegacorp.com

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