Changeset 18040d3 in rtems


Ignore:
Timestamp:
Mar 31, 1999, 11:35:22 PM (21 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, master
Children:
77a0067
Parents:
ecab6a39
Message:

Patch from Thomas Doerfler <td@…> to add flow control:

Some lines for "documentation":
======================================
One thing should be noted: when XON/XOFF is enabled, the serial
device will always work with one-character buffers, so the interrupt
load for the CPU might get higer, especially on devices like MC68360
and MPC860, where the serial channels are capable of using big
buffers. But, once again, this only happens when XON/XOFF is actually
selected.

Please note that the flag IXON is set by default, so outgoing
XON/XOFF flow control is enabled by default.

XON/XOFF is controlled using the "standard" fields IXON/IXOFF in the
termios structure. The termios flag IXANY is not (yet) supported.

Hardware handshake for the incoming data stream is controlled using
the standard flag CRTSCTS. If this flag is set, whenever the receive
buffer is almost full, the driver function "device.stopRemoteTx()" is
called, when the receive buffer has more space available,
"device.startRemoteTx()" is called again. If the driver does not
provide these interface functions (entries in device structure are
NULL pointers), then these calls are suppressed.

Changes of the flow control options during operation should work at
any time, but this has not been extensively tested.

No changes to the device driver interface are needed.
================================================

One critical point when using this patch might be, that any BSP using
this version of termios will now have outgoing flow control enabled
by default, so the behaviour of these BSPs will change here. The
option IXON has already been set in older termios by default, but it
did not work until this patch. Maybe this option should be switched
off by default, what do you think?

Files:
3 edited

Legend:

Unmodified
Added
Removed
  • c/src/exec/libcsupport/src/termios.c

    recab6a39 r18040d3  
    126126         */
    127127        rtems_termios_callbacks device;
     128        volatile unsigned int   flow_ctrl;
     129        unsigned int            lowwater,highwater;
    128130};
     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   */
    129143
    130144static struct rtems_termios_tty *ttyHead, *ttyTail;
     
    271285                tty->termios.c_cflag = B9600 | CS8 | CREAD;
    272286                tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
     287
    273288                tty->termios.c_cc[VINTR] = '\003';
    274289                tty->termios.c_cc[VQUIT] = '\034';
     
    286301                tty->termios.c_cc[VLNEXT] = '\026';
    287302
     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;
    288310                /*
    289311                 * Bump name characer
     
    291313                if (c++ == 'z')
    292314                        c = 'a';
     315
    293316        }
    294317        args->iop->data1 = tty;
     
    357380}
    358381
     382static void
     383termios_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
    359451rtems_status_code
    360452rtems_termios_ioctl (void *arg)
     
    381473        case RTEMS_IO_SET_ATTRIBUTES:
    382474                tty->termios = *(struct termios *)args->buffer;
     475
     476                /* check for and process change in flow control options */
     477                termios_set_flowctrl(tty);
     478
    383479                if (tty->termios.c_lflag & ICANON) {
    384480                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
     
    465561                tty->rawOutBufHead = newHead;
    466562                if (tty->rawOutBufState == rob_idle) {
     563                  /* check, whether XOFF has been received */
     564                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
    467565                        (*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;
    470573                }
    471574                rtems_interrupt_enable (level);
     
    808911                        c = tty->rawInBuf[newHead];
    809912                        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 */
    810937                        if (tty->termios.c_lflag & ICANON) {
    811938                                if  (siproc (c, tty))
     
    867994 * NOTE: This routine runs in the context of the
    868995 *       device receive interrupt handler.
    869  * Returns the number of characters dropped because of overlow.
     996 * Returns the number of characters dropped because of overflow.
    870997 */
    871998int
     
    8741001        struct rtems_termios_tty *tty = ttyp;
    8751002        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 {
    8781051                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
    8791084                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;
    8871094        rtems_semaphore_release (tty->rawInBufSemaphore);
    888         return len;
     1095        return dropped;
    8891096}
    8901097
     
    9051112        int nToSend;
    9061113
    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;
    9181131        }
    9191132        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        }
    9321172        return nToSend;
    9331173}
  • c/src/lib/libc/termios.c

    recab6a39 r18040d3  
    126126         */
    127127        rtems_termios_callbacks device;
     128        volatile unsigned int   flow_ctrl;
     129        unsigned int            lowwater,highwater;
    128130};
     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   */
    129143
    130144static struct rtems_termios_tty *ttyHead, *ttyTail;
     
    271285                tty->termios.c_cflag = B9600 | CS8 | CREAD;
    272286                tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
     287
    273288                tty->termios.c_cc[VINTR] = '\003';
    274289                tty->termios.c_cc[VQUIT] = '\034';
     
    286301                tty->termios.c_cc[VLNEXT] = '\026';
    287302
     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;
    288310                /*
    289311                 * Bump name characer
     
    291313                if (c++ == 'z')
    292314                        c = 'a';
     315
    293316        }
    294317        args->iop->data1 = tty;
     
    357380}
    358381
     382static void
     383termios_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
    359451rtems_status_code
    360452rtems_termios_ioctl (void *arg)
     
    381473        case RTEMS_IO_SET_ATTRIBUTES:
    382474                tty->termios = *(struct termios *)args->buffer;
     475
     476                /* check for and process change in flow control options */
     477                termios_set_flowctrl(tty);
     478
    383479                if (tty->termios.c_lflag & ICANON) {
    384480                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
     
    465561                tty->rawOutBufHead = newHead;
    466562                if (tty->rawOutBufState == rob_idle) {
     563                  /* check, whether XOFF has been received */
     564                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
    467565                        (*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;
    470573                }
    471574                rtems_interrupt_enable (level);
     
    808911                        c = tty->rawInBuf[newHead];
    809912                        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 */
    810937                        if (tty->termios.c_lflag & ICANON) {
    811938                                if  (siproc (c, tty))
     
    867994 * NOTE: This routine runs in the context of the
    868995 *       device receive interrupt handler.
    869  * Returns the number of characters dropped because of overlow.
     996 * Returns the number of characters dropped because of overflow.
    870997 */
    871998int
     
    8741001        struct rtems_termios_tty *tty = ttyp;
    8751002        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 {
    8781051                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
    8791084                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;
    8871094        rtems_semaphore_release (tty->rawInBufSemaphore);
    888         return len;
     1095        return dropped;
    8891096}
    8901097
     
    9051112        int nToSend;
    9061113
    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;
    9181131        }
    9191132        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        }
    9321172        return nToSend;
    9331173}
  • cpukit/libcsupport/src/termios.c

    recab6a39 r18040d3  
    126126         */
    127127        rtems_termios_callbacks device;
     128        volatile unsigned int   flow_ctrl;
     129        unsigned int            lowwater,highwater;
    128130};
     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   */
    129143
    130144static struct rtems_termios_tty *ttyHead, *ttyTail;
     
    271285                tty->termios.c_cflag = B9600 | CS8 | CREAD;
    272286                tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
     287
    273288                tty->termios.c_cc[VINTR] = '\003';
    274289                tty->termios.c_cc[VQUIT] = '\034';
     
    286301                tty->termios.c_cc[VLNEXT] = '\026';
    287302
     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;
    288310                /*
    289311                 * Bump name characer
     
    291313                if (c++ == 'z')
    292314                        c = 'a';
     315
    293316        }
    294317        args->iop->data1 = tty;
     
    357380}
    358381
     382static void
     383termios_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
    359451rtems_status_code
    360452rtems_termios_ioctl (void *arg)
     
    381473        case RTEMS_IO_SET_ATTRIBUTES:
    382474                tty->termios = *(struct termios *)args->buffer;
     475
     476                /* check for and process change in flow control options */
     477                termios_set_flowctrl(tty);
     478
    383479                if (tty->termios.c_lflag & ICANON) {
    384480                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
     
    465561                tty->rawOutBufHead = newHead;
    466562                if (tty->rawOutBufState == rob_idle) {
     563                  /* check, whether XOFF has been received */
     564                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
    467565                        (*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;
    470573                }
    471574                rtems_interrupt_enable (level);
     
    808911                        c = tty->rawInBuf[newHead];
    809912                        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 */
    810937                        if (tty->termios.c_lflag & ICANON) {
    811938                                if  (siproc (c, tty))
     
    867994 * NOTE: This routine runs in the context of the
    868995 *       device receive interrupt handler.
    869  * Returns the number of characters dropped because of overlow.
     996 * Returns the number of characters dropped because of overflow.
    870997 */
    871998int
     
    8741001        struct rtems_termios_tty *tty = ttyp;
    8751002        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 {
    8781051                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
    8791084                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;
    8871094        rtems_semaphore_release (tty->rawInBufSemaphore);
    888         return len;
     1095        return dropped;
    8891096}
    8901097
     
    9051112        int nToSend;
    9061113
    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;
    9181131        }
    9191132        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        }
    9321172        return nToSend;
    9331173}
Note: See TracChangeset for help on using the changeset viewer.