Changeset 18040d3 in rtems
- Timestamp:
- 03/31/99 23:35:22 (25 years ago)
- Branches:
- 4.10, 4.11, 4.8, 4.9, 5, master
- Children:
- 77a0067
- Parents:
- ecab6a39
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/exec/libcsupport/src/termios.c
recab6a39 r18040d3 126 126 */ 127 127 rtems_termios_callbacks device; 128 volatile unsigned int flow_ctrl; 129 unsigned int lowwater,highwater; 128 130 }; 131 132 /* fields for "flow_ctrl" status */ 133 #define FL_IREQXOF 1 /* input queue requests stop of incoming data */ 134 #define FL_ISNTXOF 2 /* XOFF has been sent to other side of line */ 135 #define FL_IRTSOFF 4 /* RTS has been turned off for other side.. */ 136 137 #define FL_ORCVXOF 0x10 /* XOFF has been received */ 138 #define FL_OSTOP 0x20 /* output has been stopped due to XOFF */ 139 140 #define FL_MDRTS 0x100 /* input controlled with RTS/CTS handshake */ 141 #define FL_MDXON 0x200 /* input controlled with XON/XOFF protocol */ 142 #define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */ 129 143 130 144 static struct rtems_termios_tty *ttyHead, *ttyTail; … … 271 285 tty->termios.c_cflag = B9600 | CS8 | CREAD; 272 286 tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL; 287 273 288 tty->termios.c_cc[VINTR] = '\003'; 274 289 tty->termios.c_cc[VQUIT] = '\034'; … … 286 301 tty->termios.c_cc[VLNEXT] = '\026'; 287 302 303 /* setup flow control mode, clear flow control flags */ 304 tty->flow_ctrl = FL_MDXON; 305 /* 306 * set low/highwater mark for XON/XOFF support 307 */ 308 tty->lowwater = RAW_INPUT_BUFFER_SIZE * 1/2; 309 tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4; 288 310 /* 289 311 * Bump name characer … … 291 313 if (c++ == 'z') 292 314 c = 'a'; 315 293 316 } 294 317 args->iop->data1 = tty; … … 357 380 } 358 381 382 static void 383 termios_set_flowctrl(struct rtems_termios_tty *tty) 384 { 385 rtems_interrupt_level level; 386 /* 387 * check for flow control options to be switched off 388 */ 389 390 /* check for outgoing XON/XOFF flow control switched off */ 391 if (( tty->flow_ctrl & FL_MDXON) && 392 !(tty->termios.c_iflag & IXON)) { 393 /* clear related flags in flow_ctrl */ 394 tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF); 395 396 /* has output been stopped due to received XOFF? */ 397 if (tty->flow_ctrl & FL_OSTOP) { 398 /* disable interrupts */ 399 rtems_interrupt_disable(level); 400 tty->flow_ctrl &= ~FL_OSTOP; 401 /* check for chars in output buffer (or rob_state?) */ 402 if (tty->rawOutBufState != rob_idle) { 403 /* if chars available, call write function... */ 404 (*tty->device.write)(tty->minor, 405 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 406 } 407 /* reenable interrupts */ 408 rtems_interrupt_enable(level); 409 } 410 } 411 /* check for incoming XON/XOFF flow control switched off */ 412 if (( tty->flow_ctrl & FL_MDXOF) && 413 !(tty->termios.c_iflag & IXOFF)) { 414 /* clear related flags in flow_ctrl */ 415 tty->flow_ctrl &= ~(FL_MDXOF); 416 /* FIXME: what happens, if we had sent XOFF but not yet XON? */ 417 tty->flow_ctrl &= ~(FL_ISNTXOF); 418 } 419 420 /* check for incoming RTS/CTS flow control switched off */ 421 if (( tty->flow_ctrl & FL_MDRTS) && 422 !(tty->termios.c_cflag & CRTSCTS)) { 423 /* clear related flags in flow_ctrl */ 424 tty->flow_ctrl &= ~(FL_MDRTS); 425 426 /* restart remote Tx, if it was stopped */ 427 if ((tty->flow_ctrl & FL_IRTSOFF) && 428 (tty->device.startRemoteTx != NULL)) { 429 tty->device.startRemoteTx(tty->minor); 430 } 431 tty->flow_ctrl &= ~(FL_IRTSOFF); 432 } 433 434 /* 435 * check for flow control options to be switched on 436 */ 437 /* check for incoming RTS/CTS flow control switched on */ 438 if (tty->termios.c_cflag & CRTSCTS) { 439 tty->flow_ctrl |= FL_MDRTS; 440 } 441 /* check for incoming XON/XOF flow control switched on */ 442 if (tty->termios.c_iflag & IXOFF) { 443 tty->flow_ctrl |= FL_MDXOF; 444 } 445 /* check for outgoing XON/XOF flow control switched on */ 446 if (tty->termios.c_iflag & IXON) { 447 tty->flow_ctrl |= FL_MDXON; 448 } 449 } 450 359 451 rtems_status_code 360 452 rtems_termios_ioctl (void *arg) … … 381 473 case RTEMS_IO_SET_ATTRIBUTES: 382 474 tty->termios = *(struct termios *)args->buffer; 475 476 /* check for and process change in flow control options */ 477 termios_set_flowctrl(tty); 478 383 479 if (tty->termios.c_lflag & ICANON) { 384 480 tty->rawInBufSemaphoreOptions = RTEMS_WAIT; … … 465 561 tty->rawOutBufHead = newHead; 466 562 if (tty->rawOutBufState == rob_idle) { 563 /* check, whether XOFF has been received */ 564 if (!(tty->flow_ctrl & FL_ORCVXOF)) { 467 565 (*tty->device.write)(tty->minor, 468 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 469 tty->rawOutBufState = rob_busy; 566 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1); 567 } 568 else { 569 /* remember that output has been stopped due to flow ctrl*/ 570 tty->flow_ctrl |= FL_OSTOP; 571 } 572 tty->rawOutBufState = rob_busy; 470 573 } 471 574 rtems_interrupt_enable (level); … … 808 911 c = tty->rawInBuf[newHead]; 809 912 tty->rawInBufHead = newHead; 913 if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE) 914 % RAW_INPUT_BUFFER_SIZE) 915 < tty->lowwater) { 916 tty->flow_ctrl &= ~FL_IREQXOF; 917 /* if tx stopped and XON should be sent... */ 918 if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF)) 919 == (FL_MDXON | FL_ISNTXOF)) 920 && ((tty->rawOutBufState == rob_idle) 921 || (tty->flow_ctrl & FL_OSTOP))) { 922 /* XON should be sent now... */ 923 (*tty->device.write)(tty->minor, 924 &(tty->termios.c_cc[VSTART]), 925 1); 926 } 927 else if (tty->flow_ctrl & FL_MDRTS) { 928 tty->flow_ctrl &= ~FL_IRTSOFF; 929 /* activate RTS line */ 930 if (tty->device.startRemoteTx != NULL) { 931 tty->device.startRemoteTx(tty->minor); 932 } 933 } 934 } 935 936 /* continue processing new character */ 810 937 if (tty->termios.c_lflag & ICANON) { 811 938 if (siproc (c, tty)) … … 867 994 * NOTE: This routine runs in the context of the 868 995 * device receive interrupt handler. 869 * Returns the number of characters dropped because of over low.996 * Returns the number of characters dropped because of overflow. 870 997 */ 871 998 int … … 874 1001 struct rtems_termios_tty *tty = ttyp; 875 1002 unsigned int newTail; 876 877 while (len) { 1003 char c; 1004 int dropped = 0; 1005 boolean flow_rcv = FALSE; /* TRUE, if flow control char received */ 1006 rtems_interrupt_level level; 1007 1008 while (len--) { 1009 c = *buf++; 1010 /* FIXME: implement IXANY: any character restarts output */ 1011 /* if incoming XON/XOFF controls outgoing stream: */ 1012 if (tty->flow_ctrl & FL_MDXON) { 1013 /* if received char is V_STOP and V_START (both are equal value) */ 1014 if (c == tty->termios.c_cc[VSTOP]) { 1015 if (c == tty->termios.c_cc[VSTART]) { 1016 /* received VSTOP and VSTART==VSTOP? */ 1017 /* then toggle "stop output" status */ 1018 tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF; 1019 } 1020 else { 1021 /* VSTOP received (other code than VSTART) */ 1022 /* stop output */ 1023 tty->flow_ctrl |= FL_ORCVXOF; 1024 } 1025 flow_rcv = TRUE; 1026 } 1027 else if (c == tty->termios.c_cc[VSTART]) { 1028 /* VSTART received */ 1029 /* restart output */ 1030 tty->flow_ctrl &= ~FL_ORCVXOF; 1031 flow_rcv = TRUE; 1032 } 1033 } 1034 if (flow_rcv) { 1035 /* restart output according to FL_ORCVXOF flag */ 1036 if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) { 1037 /* disable interrupts */ 1038 rtems_interrupt_disable(level); 1039 tty->flow_ctrl &= ~FL_OSTOP; 1040 /* check for chars in output buffer (or rob_state?) */ 1041 if (tty->rawOutBufState != rob_idle) { 1042 /* if chars available, call write function... */ 1043 (*tty->device.write)(tty->minor, 1044 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 1045 } 1046 /* reenable interrupts */ 1047 rtems_interrupt_enable(level); 1048 } 1049 } 1050 else { 878 1051 newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE; 1052 /* if chars_in_buffer > highwater */ 1053 rtems_interrupt_disable(level); 1054 if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE) 1055 % RAW_INPUT_BUFFER_SIZE) 1056 > tty->highwater) && 1057 !(tty->flow_ctrl & FL_IREQXOF)) { 1058 /* incoming data stream should be stopped */ 1059 tty->flow_ctrl |= FL_IREQXOF; 1060 if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF)) 1061 == (FL_MDXOF ) ){ 1062 if ((tty->flow_ctrl & FL_OSTOP) || 1063 (tty->rawOutBufState == rob_idle)) { 1064 /* if tx is stopped due to XOFF or out of data */ 1065 /* call write function here */ 1066 tty->flow_ctrl |= FL_ISNTXOF; 1067 (*tty->device.write)(tty->minor, 1068 &(tty->termios.c_cc[VSTOP]), 1069 1); 1070 } 1071 } 1072 else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) 1073 == (FL_MDRTS ) ) { 1074 tty->flow_ctrl |= FL_IRTSOFF; 1075 /* deactivate RTS line */ 1076 if (tty->device.stopRemoteTx != NULL) { 1077 tty->device.stopRemoteTx(tty->minor); 1078 } 1079 } 1080 } 1081 /* reenable interrupts */ 1082 rtems_interrupt_enable(level); 1083 879 1084 if (newTail == tty->rawInBufHead) { 880 tty->rawInBufDropped += len; 881 break; 882 } 883 tty->rawInBuf[newTail] = *buf++; 884 len--; 885 tty->rawInBufTail = newTail; 886 } 1085 dropped++; 1086 } 1087 else { 1088 tty->rawInBuf[newTail] = c; 1089 tty->rawInBufTail = newTail; 1090 } 1091 } 1092 } 1093 tty->rawInBufDropped += dropped; 887 1094 rtems_semaphore_release (tty->rawInBufSemaphore); 888 return len;1095 return dropped; 889 1096 } 890 1097 … … 905 1112 int nToSend; 906 1113 907 if (tty->rawOutBufState == rob_wait) 908 rtems_semaphore_release (tty->rawOutBufSemaphore); 909 if ( tty->rawOutBufHead == tty->rawOutBufTail ) 910 return 0; 911 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 912 if (newTail == tty->rawOutBufHead) { 913 /* 914 * Buffer empty 915 */ 916 tty->rawOutBufState = rob_idle; 917 nToSend = 0; 1114 /* check for XOF/XON to send */ 1115 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1116 == (FL_MDXOF | FL_IREQXOF)) { 1117 /* XOFF should be sent now... */ 1118 (*tty->device.write)(tty->minor, 1119 &(tty->termios.c_cc[VSTOP]), 1); 1120 tty->flow_ctrl |= FL_ISNTXOF; 1121 nToSend = 1; 1122 } 1123 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1124 == FL_ISNTXOF) { 1125 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1126 /* XON should be sent now... */ 1127 (*tty->device.write)(tty->minor, 1128 &(tty->termios.c_cc[VSTART]), 1); 1129 tty->flow_ctrl &= ~FL_ISNTXOF; 1130 nToSend = 1; 918 1131 } 919 1132 else { 920 /* 921 * Buffer not empty, start tranmitter 922 */ 923 if (newTail > tty->rawOutBufHead) 924 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 925 else 926 nToSend = tty->rawOutBufHead - newTail; 927 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 928 tty->rawOutBufState = rob_busy; 929 } 930 tty->rawOutBufTail = newTail; 931 1133 if (tty->rawOutBufState == rob_wait) 1134 rtems_semaphore_release (tty->rawOutBufSemaphore); 1135 if ( tty->rawOutBufHead == tty->rawOutBufTail ) 1136 return 0; 1137 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 1138 if (newTail == tty->rawOutBufHead) { 1139 /* 1140 * Buffer empty 1141 */ 1142 tty->rawOutBufState = rob_idle; 1143 nToSend = 0; 1144 } 1145 /* check, whether output should stop due to received XOFF */ 1146 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1147 == (FL_MDXON | FL_ORCVXOF)) { 1148 /* Buffer not empty, but output stops due to XOFF */ 1149 /* set flag, that output has been stopped */ 1150 tty->flow_ctrl |= FL_OSTOP; 1151 nToSend = 0; 1152 } 1153 else { 1154 /* 1155 * Buffer not empty, start tranmitter 1156 */ 1157 if (newTail > tty->rawOutBufHead) 1158 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 1159 else 1160 nToSend = tty->rawOutBufHead - newTail; 1161 /* when flow control XON or XOF, don't send blocks of data */ 1162 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1163 /* for outgoing flow control */ 1164 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { 1165 nToSend = 1; 1166 } 1167 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 1168 tty->rawOutBufState = rob_busy; 1169 } 1170 tty->rawOutBufTail = newTail; 1171 } 932 1172 return nToSend; 933 1173 } -
c/src/lib/libc/termios.c
recab6a39 r18040d3 126 126 */ 127 127 rtems_termios_callbacks device; 128 volatile unsigned int flow_ctrl; 129 unsigned int lowwater,highwater; 128 130 }; 131 132 /* fields for "flow_ctrl" status */ 133 #define FL_IREQXOF 1 /* input queue requests stop of incoming data */ 134 #define FL_ISNTXOF 2 /* XOFF has been sent to other side of line */ 135 #define FL_IRTSOFF 4 /* RTS has been turned off for other side.. */ 136 137 #define FL_ORCVXOF 0x10 /* XOFF has been received */ 138 #define FL_OSTOP 0x20 /* output has been stopped due to XOFF */ 139 140 #define FL_MDRTS 0x100 /* input controlled with RTS/CTS handshake */ 141 #define FL_MDXON 0x200 /* input controlled with XON/XOFF protocol */ 142 #define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */ 129 143 130 144 static struct rtems_termios_tty *ttyHead, *ttyTail; … … 271 285 tty->termios.c_cflag = B9600 | CS8 | CREAD; 272 286 tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL; 287 273 288 tty->termios.c_cc[VINTR] = '\003'; 274 289 tty->termios.c_cc[VQUIT] = '\034'; … … 286 301 tty->termios.c_cc[VLNEXT] = '\026'; 287 302 303 /* setup flow control mode, clear flow control flags */ 304 tty->flow_ctrl = FL_MDXON; 305 /* 306 * set low/highwater mark for XON/XOFF support 307 */ 308 tty->lowwater = RAW_INPUT_BUFFER_SIZE * 1/2; 309 tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4; 288 310 /* 289 311 * Bump name characer … … 291 313 if (c++ == 'z') 292 314 c = 'a'; 315 293 316 } 294 317 args->iop->data1 = tty; … … 357 380 } 358 381 382 static void 383 termios_set_flowctrl(struct rtems_termios_tty *tty) 384 { 385 rtems_interrupt_level level; 386 /* 387 * check for flow control options to be switched off 388 */ 389 390 /* check for outgoing XON/XOFF flow control switched off */ 391 if (( tty->flow_ctrl & FL_MDXON) && 392 !(tty->termios.c_iflag & IXON)) { 393 /* clear related flags in flow_ctrl */ 394 tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF); 395 396 /* has output been stopped due to received XOFF? */ 397 if (tty->flow_ctrl & FL_OSTOP) { 398 /* disable interrupts */ 399 rtems_interrupt_disable(level); 400 tty->flow_ctrl &= ~FL_OSTOP; 401 /* check for chars in output buffer (or rob_state?) */ 402 if (tty->rawOutBufState != rob_idle) { 403 /* if chars available, call write function... */ 404 (*tty->device.write)(tty->minor, 405 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 406 } 407 /* reenable interrupts */ 408 rtems_interrupt_enable(level); 409 } 410 } 411 /* check for incoming XON/XOFF flow control switched off */ 412 if (( tty->flow_ctrl & FL_MDXOF) && 413 !(tty->termios.c_iflag & IXOFF)) { 414 /* clear related flags in flow_ctrl */ 415 tty->flow_ctrl &= ~(FL_MDXOF); 416 /* FIXME: what happens, if we had sent XOFF but not yet XON? */ 417 tty->flow_ctrl &= ~(FL_ISNTXOF); 418 } 419 420 /* check for incoming RTS/CTS flow control switched off */ 421 if (( tty->flow_ctrl & FL_MDRTS) && 422 !(tty->termios.c_cflag & CRTSCTS)) { 423 /* clear related flags in flow_ctrl */ 424 tty->flow_ctrl &= ~(FL_MDRTS); 425 426 /* restart remote Tx, if it was stopped */ 427 if ((tty->flow_ctrl & FL_IRTSOFF) && 428 (tty->device.startRemoteTx != NULL)) { 429 tty->device.startRemoteTx(tty->minor); 430 } 431 tty->flow_ctrl &= ~(FL_IRTSOFF); 432 } 433 434 /* 435 * check for flow control options to be switched on 436 */ 437 /* check for incoming RTS/CTS flow control switched on */ 438 if (tty->termios.c_cflag & CRTSCTS) { 439 tty->flow_ctrl |= FL_MDRTS; 440 } 441 /* check for incoming XON/XOF flow control switched on */ 442 if (tty->termios.c_iflag & IXOFF) { 443 tty->flow_ctrl |= FL_MDXOF; 444 } 445 /* check for outgoing XON/XOF flow control switched on */ 446 if (tty->termios.c_iflag & IXON) { 447 tty->flow_ctrl |= FL_MDXON; 448 } 449 } 450 359 451 rtems_status_code 360 452 rtems_termios_ioctl (void *arg) … … 381 473 case RTEMS_IO_SET_ATTRIBUTES: 382 474 tty->termios = *(struct termios *)args->buffer; 475 476 /* check for and process change in flow control options */ 477 termios_set_flowctrl(tty); 478 383 479 if (tty->termios.c_lflag & ICANON) { 384 480 tty->rawInBufSemaphoreOptions = RTEMS_WAIT; … … 465 561 tty->rawOutBufHead = newHead; 466 562 if (tty->rawOutBufState == rob_idle) { 563 /* check, whether XOFF has been received */ 564 if (!(tty->flow_ctrl & FL_ORCVXOF)) { 467 565 (*tty->device.write)(tty->minor, 468 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 469 tty->rawOutBufState = rob_busy; 566 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1); 567 } 568 else { 569 /* remember that output has been stopped due to flow ctrl*/ 570 tty->flow_ctrl |= FL_OSTOP; 571 } 572 tty->rawOutBufState = rob_busy; 470 573 } 471 574 rtems_interrupt_enable (level); … … 808 911 c = tty->rawInBuf[newHead]; 809 912 tty->rawInBufHead = newHead; 913 if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE) 914 % RAW_INPUT_BUFFER_SIZE) 915 < tty->lowwater) { 916 tty->flow_ctrl &= ~FL_IREQXOF; 917 /* if tx stopped and XON should be sent... */ 918 if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF)) 919 == (FL_MDXON | FL_ISNTXOF)) 920 && ((tty->rawOutBufState == rob_idle) 921 || (tty->flow_ctrl & FL_OSTOP))) { 922 /* XON should be sent now... */ 923 (*tty->device.write)(tty->minor, 924 &(tty->termios.c_cc[VSTART]), 925 1); 926 } 927 else if (tty->flow_ctrl & FL_MDRTS) { 928 tty->flow_ctrl &= ~FL_IRTSOFF; 929 /* activate RTS line */ 930 if (tty->device.startRemoteTx != NULL) { 931 tty->device.startRemoteTx(tty->minor); 932 } 933 } 934 } 935 936 /* continue processing new character */ 810 937 if (tty->termios.c_lflag & ICANON) { 811 938 if (siproc (c, tty)) … … 867 994 * NOTE: This routine runs in the context of the 868 995 * device receive interrupt handler. 869 * Returns the number of characters dropped because of over low.996 * Returns the number of characters dropped because of overflow. 870 997 */ 871 998 int … … 874 1001 struct rtems_termios_tty *tty = ttyp; 875 1002 unsigned int newTail; 876 877 while (len) { 1003 char c; 1004 int dropped = 0; 1005 boolean flow_rcv = FALSE; /* TRUE, if flow control char received */ 1006 rtems_interrupt_level level; 1007 1008 while (len--) { 1009 c = *buf++; 1010 /* FIXME: implement IXANY: any character restarts output */ 1011 /* if incoming XON/XOFF controls outgoing stream: */ 1012 if (tty->flow_ctrl & FL_MDXON) { 1013 /* if received char is V_STOP and V_START (both are equal value) */ 1014 if (c == tty->termios.c_cc[VSTOP]) { 1015 if (c == tty->termios.c_cc[VSTART]) { 1016 /* received VSTOP and VSTART==VSTOP? */ 1017 /* then toggle "stop output" status */ 1018 tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF; 1019 } 1020 else { 1021 /* VSTOP received (other code than VSTART) */ 1022 /* stop output */ 1023 tty->flow_ctrl |= FL_ORCVXOF; 1024 } 1025 flow_rcv = TRUE; 1026 } 1027 else if (c == tty->termios.c_cc[VSTART]) { 1028 /* VSTART received */ 1029 /* restart output */ 1030 tty->flow_ctrl &= ~FL_ORCVXOF; 1031 flow_rcv = TRUE; 1032 } 1033 } 1034 if (flow_rcv) { 1035 /* restart output according to FL_ORCVXOF flag */ 1036 if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) { 1037 /* disable interrupts */ 1038 rtems_interrupt_disable(level); 1039 tty->flow_ctrl &= ~FL_OSTOP; 1040 /* check for chars in output buffer (or rob_state?) */ 1041 if (tty->rawOutBufState != rob_idle) { 1042 /* if chars available, call write function... */ 1043 (*tty->device.write)(tty->minor, 1044 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 1045 } 1046 /* reenable interrupts */ 1047 rtems_interrupt_enable(level); 1048 } 1049 } 1050 else { 878 1051 newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE; 1052 /* if chars_in_buffer > highwater */ 1053 rtems_interrupt_disable(level); 1054 if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE) 1055 % RAW_INPUT_BUFFER_SIZE) 1056 > tty->highwater) && 1057 !(tty->flow_ctrl & FL_IREQXOF)) { 1058 /* incoming data stream should be stopped */ 1059 tty->flow_ctrl |= FL_IREQXOF; 1060 if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF)) 1061 == (FL_MDXOF ) ){ 1062 if ((tty->flow_ctrl & FL_OSTOP) || 1063 (tty->rawOutBufState == rob_idle)) { 1064 /* if tx is stopped due to XOFF or out of data */ 1065 /* call write function here */ 1066 tty->flow_ctrl |= FL_ISNTXOF; 1067 (*tty->device.write)(tty->minor, 1068 &(tty->termios.c_cc[VSTOP]), 1069 1); 1070 } 1071 } 1072 else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) 1073 == (FL_MDRTS ) ) { 1074 tty->flow_ctrl |= FL_IRTSOFF; 1075 /* deactivate RTS line */ 1076 if (tty->device.stopRemoteTx != NULL) { 1077 tty->device.stopRemoteTx(tty->minor); 1078 } 1079 } 1080 } 1081 /* reenable interrupts */ 1082 rtems_interrupt_enable(level); 1083 879 1084 if (newTail == tty->rawInBufHead) { 880 tty->rawInBufDropped += len; 881 break; 882 } 883 tty->rawInBuf[newTail] = *buf++; 884 len--; 885 tty->rawInBufTail = newTail; 886 } 1085 dropped++; 1086 } 1087 else { 1088 tty->rawInBuf[newTail] = c; 1089 tty->rawInBufTail = newTail; 1090 } 1091 } 1092 } 1093 tty->rawInBufDropped += dropped; 887 1094 rtems_semaphore_release (tty->rawInBufSemaphore); 888 return len;1095 return dropped; 889 1096 } 890 1097 … … 905 1112 int nToSend; 906 1113 907 if (tty->rawOutBufState == rob_wait) 908 rtems_semaphore_release (tty->rawOutBufSemaphore); 909 if ( tty->rawOutBufHead == tty->rawOutBufTail ) 910 return 0; 911 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 912 if (newTail == tty->rawOutBufHead) { 913 /* 914 * Buffer empty 915 */ 916 tty->rawOutBufState = rob_idle; 917 nToSend = 0; 1114 /* check for XOF/XON to send */ 1115 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1116 == (FL_MDXOF | FL_IREQXOF)) { 1117 /* XOFF should be sent now... */ 1118 (*tty->device.write)(tty->minor, 1119 &(tty->termios.c_cc[VSTOP]), 1); 1120 tty->flow_ctrl |= FL_ISNTXOF; 1121 nToSend = 1; 1122 } 1123 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1124 == FL_ISNTXOF) { 1125 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1126 /* XON should be sent now... */ 1127 (*tty->device.write)(tty->minor, 1128 &(tty->termios.c_cc[VSTART]), 1); 1129 tty->flow_ctrl &= ~FL_ISNTXOF; 1130 nToSend = 1; 918 1131 } 919 1132 else { 920 /* 921 * Buffer not empty, start tranmitter 922 */ 923 if (newTail > tty->rawOutBufHead) 924 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 925 else 926 nToSend = tty->rawOutBufHead - newTail; 927 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 928 tty->rawOutBufState = rob_busy; 929 } 930 tty->rawOutBufTail = newTail; 931 1133 if (tty->rawOutBufState == rob_wait) 1134 rtems_semaphore_release (tty->rawOutBufSemaphore); 1135 if ( tty->rawOutBufHead == tty->rawOutBufTail ) 1136 return 0; 1137 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 1138 if (newTail == tty->rawOutBufHead) { 1139 /* 1140 * Buffer empty 1141 */ 1142 tty->rawOutBufState = rob_idle; 1143 nToSend = 0; 1144 } 1145 /* check, whether output should stop due to received XOFF */ 1146 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1147 == (FL_MDXON | FL_ORCVXOF)) { 1148 /* Buffer not empty, but output stops due to XOFF */ 1149 /* set flag, that output has been stopped */ 1150 tty->flow_ctrl |= FL_OSTOP; 1151 nToSend = 0; 1152 } 1153 else { 1154 /* 1155 * Buffer not empty, start tranmitter 1156 */ 1157 if (newTail > tty->rawOutBufHead) 1158 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 1159 else 1160 nToSend = tty->rawOutBufHead - newTail; 1161 /* when flow control XON or XOF, don't send blocks of data */ 1162 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1163 /* for outgoing flow control */ 1164 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { 1165 nToSend = 1; 1166 } 1167 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 1168 tty->rawOutBufState = rob_busy; 1169 } 1170 tty->rawOutBufTail = newTail; 1171 } 932 1172 return nToSend; 933 1173 } -
cpukit/libcsupport/src/termios.c
recab6a39 r18040d3 126 126 */ 127 127 rtems_termios_callbacks device; 128 volatile unsigned int flow_ctrl; 129 unsigned int lowwater,highwater; 128 130 }; 131 132 /* fields for "flow_ctrl" status */ 133 #define FL_IREQXOF 1 /* input queue requests stop of incoming data */ 134 #define FL_ISNTXOF 2 /* XOFF has been sent to other side of line */ 135 #define FL_IRTSOFF 4 /* RTS has been turned off for other side.. */ 136 137 #define FL_ORCVXOF 0x10 /* XOFF has been received */ 138 #define FL_OSTOP 0x20 /* output has been stopped due to XOFF */ 139 140 #define FL_MDRTS 0x100 /* input controlled with RTS/CTS handshake */ 141 #define FL_MDXON 0x200 /* input controlled with XON/XOFF protocol */ 142 #define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */ 129 143 130 144 static struct rtems_termios_tty *ttyHead, *ttyTail; … … 271 285 tty->termios.c_cflag = B9600 | CS8 | CREAD; 272 286 tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL; 287 273 288 tty->termios.c_cc[VINTR] = '\003'; 274 289 tty->termios.c_cc[VQUIT] = '\034'; … … 286 301 tty->termios.c_cc[VLNEXT] = '\026'; 287 302 303 /* setup flow control mode, clear flow control flags */ 304 tty->flow_ctrl = FL_MDXON; 305 /* 306 * set low/highwater mark for XON/XOFF support 307 */ 308 tty->lowwater = RAW_INPUT_BUFFER_SIZE * 1/2; 309 tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4; 288 310 /* 289 311 * Bump name characer … … 291 313 if (c++ == 'z') 292 314 c = 'a'; 315 293 316 } 294 317 args->iop->data1 = tty; … … 357 380 } 358 381 382 static void 383 termios_set_flowctrl(struct rtems_termios_tty *tty) 384 { 385 rtems_interrupt_level level; 386 /* 387 * check for flow control options to be switched off 388 */ 389 390 /* check for outgoing XON/XOFF flow control switched off */ 391 if (( tty->flow_ctrl & FL_MDXON) && 392 !(tty->termios.c_iflag & IXON)) { 393 /* clear related flags in flow_ctrl */ 394 tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF); 395 396 /* has output been stopped due to received XOFF? */ 397 if (tty->flow_ctrl & FL_OSTOP) { 398 /* disable interrupts */ 399 rtems_interrupt_disable(level); 400 tty->flow_ctrl &= ~FL_OSTOP; 401 /* check for chars in output buffer (or rob_state?) */ 402 if (tty->rawOutBufState != rob_idle) { 403 /* if chars available, call write function... */ 404 (*tty->device.write)(tty->minor, 405 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 406 } 407 /* reenable interrupts */ 408 rtems_interrupt_enable(level); 409 } 410 } 411 /* check for incoming XON/XOFF flow control switched off */ 412 if (( tty->flow_ctrl & FL_MDXOF) && 413 !(tty->termios.c_iflag & IXOFF)) { 414 /* clear related flags in flow_ctrl */ 415 tty->flow_ctrl &= ~(FL_MDXOF); 416 /* FIXME: what happens, if we had sent XOFF but not yet XON? */ 417 tty->flow_ctrl &= ~(FL_ISNTXOF); 418 } 419 420 /* check for incoming RTS/CTS flow control switched off */ 421 if (( tty->flow_ctrl & FL_MDRTS) && 422 !(tty->termios.c_cflag & CRTSCTS)) { 423 /* clear related flags in flow_ctrl */ 424 tty->flow_ctrl &= ~(FL_MDRTS); 425 426 /* restart remote Tx, if it was stopped */ 427 if ((tty->flow_ctrl & FL_IRTSOFF) && 428 (tty->device.startRemoteTx != NULL)) { 429 tty->device.startRemoteTx(tty->minor); 430 } 431 tty->flow_ctrl &= ~(FL_IRTSOFF); 432 } 433 434 /* 435 * check for flow control options to be switched on 436 */ 437 /* check for incoming RTS/CTS flow control switched on */ 438 if (tty->termios.c_cflag & CRTSCTS) { 439 tty->flow_ctrl |= FL_MDRTS; 440 } 441 /* check for incoming XON/XOF flow control switched on */ 442 if (tty->termios.c_iflag & IXOFF) { 443 tty->flow_ctrl |= FL_MDXOF; 444 } 445 /* check for outgoing XON/XOF flow control switched on */ 446 if (tty->termios.c_iflag & IXON) { 447 tty->flow_ctrl |= FL_MDXON; 448 } 449 } 450 359 451 rtems_status_code 360 452 rtems_termios_ioctl (void *arg) … … 381 473 case RTEMS_IO_SET_ATTRIBUTES: 382 474 tty->termios = *(struct termios *)args->buffer; 475 476 /* check for and process change in flow control options */ 477 termios_set_flowctrl(tty); 478 383 479 if (tty->termios.c_lflag & ICANON) { 384 480 tty->rawInBufSemaphoreOptions = RTEMS_WAIT; … … 465 561 tty->rawOutBufHead = newHead; 466 562 if (tty->rawOutBufState == rob_idle) { 563 /* check, whether XOFF has been received */ 564 if (!(tty->flow_ctrl & FL_ORCVXOF)) { 467 565 (*tty->device.write)(tty->minor, 468 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 469 tty->rawOutBufState = rob_busy; 566 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1); 567 } 568 else { 569 /* remember that output has been stopped due to flow ctrl*/ 570 tty->flow_ctrl |= FL_OSTOP; 571 } 572 tty->rawOutBufState = rob_busy; 470 573 } 471 574 rtems_interrupt_enable (level); … … 808 911 c = tty->rawInBuf[newHead]; 809 912 tty->rawInBufHead = newHead; 913 if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE) 914 % RAW_INPUT_BUFFER_SIZE) 915 < tty->lowwater) { 916 tty->flow_ctrl &= ~FL_IREQXOF; 917 /* if tx stopped and XON should be sent... */ 918 if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF)) 919 == (FL_MDXON | FL_ISNTXOF)) 920 && ((tty->rawOutBufState == rob_idle) 921 || (tty->flow_ctrl & FL_OSTOP))) { 922 /* XON should be sent now... */ 923 (*tty->device.write)(tty->minor, 924 &(tty->termios.c_cc[VSTART]), 925 1); 926 } 927 else if (tty->flow_ctrl & FL_MDRTS) { 928 tty->flow_ctrl &= ~FL_IRTSOFF; 929 /* activate RTS line */ 930 if (tty->device.startRemoteTx != NULL) { 931 tty->device.startRemoteTx(tty->minor); 932 } 933 } 934 } 935 936 /* continue processing new character */ 810 937 if (tty->termios.c_lflag & ICANON) { 811 938 if (siproc (c, tty)) … … 867 994 * NOTE: This routine runs in the context of the 868 995 * device receive interrupt handler. 869 * Returns the number of characters dropped because of over low.996 * Returns the number of characters dropped because of overflow. 870 997 */ 871 998 int … … 874 1001 struct rtems_termios_tty *tty = ttyp; 875 1002 unsigned int newTail; 876 877 while (len) { 1003 char c; 1004 int dropped = 0; 1005 boolean flow_rcv = FALSE; /* TRUE, if flow control char received */ 1006 rtems_interrupt_level level; 1007 1008 while (len--) { 1009 c = *buf++; 1010 /* FIXME: implement IXANY: any character restarts output */ 1011 /* if incoming XON/XOFF controls outgoing stream: */ 1012 if (tty->flow_ctrl & FL_MDXON) { 1013 /* if received char is V_STOP and V_START (both are equal value) */ 1014 if (c == tty->termios.c_cc[VSTOP]) { 1015 if (c == tty->termios.c_cc[VSTART]) { 1016 /* received VSTOP and VSTART==VSTOP? */ 1017 /* then toggle "stop output" status */ 1018 tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF; 1019 } 1020 else { 1021 /* VSTOP received (other code than VSTART) */ 1022 /* stop output */ 1023 tty->flow_ctrl |= FL_ORCVXOF; 1024 } 1025 flow_rcv = TRUE; 1026 } 1027 else if (c == tty->termios.c_cc[VSTART]) { 1028 /* VSTART received */ 1029 /* restart output */ 1030 tty->flow_ctrl &= ~FL_ORCVXOF; 1031 flow_rcv = TRUE; 1032 } 1033 } 1034 if (flow_rcv) { 1035 /* restart output according to FL_ORCVXOF flag */ 1036 if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) { 1037 /* disable interrupts */ 1038 rtems_interrupt_disable(level); 1039 tty->flow_ctrl &= ~FL_OSTOP; 1040 /* check for chars in output buffer (or rob_state?) */ 1041 if (tty->rawOutBufState != rob_idle) { 1042 /* if chars available, call write function... */ 1043 (*tty->device.write)(tty->minor, 1044 (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1); 1045 } 1046 /* reenable interrupts */ 1047 rtems_interrupt_enable(level); 1048 } 1049 } 1050 else { 878 1051 newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE; 1052 /* if chars_in_buffer > highwater */ 1053 rtems_interrupt_disable(level); 1054 if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE) 1055 % RAW_INPUT_BUFFER_SIZE) 1056 > tty->highwater) && 1057 !(tty->flow_ctrl & FL_IREQXOF)) { 1058 /* incoming data stream should be stopped */ 1059 tty->flow_ctrl |= FL_IREQXOF; 1060 if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF)) 1061 == (FL_MDXOF ) ){ 1062 if ((tty->flow_ctrl & FL_OSTOP) || 1063 (tty->rawOutBufState == rob_idle)) { 1064 /* if tx is stopped due to XOFF or out of data */ 1065 /* call write function here */ 1066 tty->flow_ctrl |= FL_ISNTXOF; 1067 (*tty->device.write)(tty->minor, 1068 &(tty->termios.c_cc[VSTOP]), 1069 1); 1070 } 1071 } 1072 else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) 1073 == (FL_MDRTS ) ) { 1074 tty->flow_ctrl |= FL_IRTSOFF; 1075 /* deactivate RTS line */ 1076 if (tty->device.stopRemoteTx != NULL) { 1077 tty->device.stopRemoteTx(tty->minor); 1078 } 1079 } 1080 } 1081 /* reenable interrupts */ 1082 rtems_interrupt_enable(level); 1083 879 1084 if (newTail == tty->rawInBufHead) { 880 tty->rawInBufDropped += len; 881 break; 882 } 883 tty->rawInBuf[newTail] = *buf++; 884 len--; 885 tty->rawInBufTail = newTail; 886 } 1085 dropped++; 1086 } 1087 else { 1088 tty->rawInBuf[newTail] = c; 1089 tty->rawInBufTail = newTail; 1090 } 1091 } 1092 } 1093 tty->rawInBufDropped += dropped; 887 1094 rtems_semaphore_release (tty->rawInBufSemaphore); 888 return len;1095 return dropped; 889 1096 } 890 1097 … … 905 1112 int nToSend; 906 1113 907 if (tty->rawOutBufState == rob_wait) 908 rtems_semaphore_release (tty->rawOutBufSemaphore); 909 if ( tty->rawOutBufHead == tty->rawOutBufTail ) 910 return 0; 911 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 912 if (newTail == tty->rawOutBufHead) { 913 /* 914 * Buffer empty 915 */ 916 tty->rawOutBufState = rob_idle; 917 nToSend = 0; 1114 /* check for XOF/XON to send */ 1115 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) 1116 == (FL_MDXOF | FL_IREQXOF)) { 1117 /* XOFF should be sent now... */ 1118 (*tty->device.write)(tty->minor, 1119 &(tty->termios.c_cc[VSTOP]), 1); 1120 tty->flow_ctrl |= FL_ISNTXOF; 1121 nToSend = 1; 1122 } 1123 else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) 1124 == FL_ISNTXOF) { 1125 /* NOTE: send XON even, if no longer in XON/XOFF mode... */ 1126 /* XON should be sent now... */ 1127 (*tty->device.write)(tty->minor, 1128 &(tty->termios.c_cc[VSTART]), 1); 1129 tty->flow_ctrl &= ~FL_ISNTXOF; 1130 nToSend = 1; 918 1131 } 919 1132 else { 920 /* 921 * Buffer not empty, start tranmitter 922 */ 923 if (newTail > tty->rawOutBufHead) 924 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 925 else 926 nToSend = tty->rawOutBufHead - newTail; 927 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 928 tty->rawOutBufState = rob_busy; 929 } 930 tty->rawOutBufTail = newTail; 931 1133 if (tty->rawOutBufState == rob_wait) 1134 rtems_semaphore_release (tty->rawOutBufSemaphore); 1135 if ( tty->rawOutBufHead == tty->rawOutBufTail ) 1136 return 0; 1137 newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE; 1138 if (newTail == tty->rawOutBufHead) { 1139 /* 1140 * Buffer empty 1141 */ 1142 tty->rawOutBufState = rob_idle; 1143 nToSend = 0; 1144 } 1145 /* check, whether output should stop due to received XOFF */ 1146 else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 1147 == (FL_MDXON | FL_ORCVXOF)) { 1148 /* Buffer not empty, but output stops due to XOFF */ 1149 /* set flag, that output has been stopped */ 1150 tty->flow_ctrl |= FL_OSTOP; 1151 nToSend = 0; 1152 } 1153 else { 1154 /* 1155 * Buffer not empty, start tranmitter 1156 */ 1157 if (newTail > tty->rawOutBufHead) 1158 nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail; 1159 else 1160 nToSend = tty->rawOutBufHead - newTail; 1161 /* when flow control XON or XOF, don't send blocks of data */ 1162 /* to allow fast reaction on incoming flow ctrl and low latency*/ 1163 /* for outgoing flow control */ 1164 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { 1165 nToSend = 1; 1166 } 1167 (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend); 1168 tty->rawOutBufState = rob_busy; 1169 } 1170 tty->rawOutBufTail = newTail; 1171 } 932 1172 return nToSend; 933 1173 }
Note: See TracChangeset
for help on using the changeset viewer.