|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.