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