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