summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--c/src/exec/libcsupport/src/termios.c304
-rw-r--r--c/src/lib/libc/termios.c304
-rw-r--r--cpukit/libcsupport/src/termios.c304
3 files changed, 816 insertions, 96 deletions
diff --git a/c/src/exec/libcsupport/src/termios.c b/c/src/exec/libcsupport/src/termios.c
index c2a43c7707..e783e54753 100644
--- a/c/src/exec/libcsupport/src/termios.c
+++ b/c/src/exec/libcsupport/src/termios.c
@@ -125,8 +125,22 @@ struct rtems_termios_tty {
* Callbacks to device-specific routines
*/
rtems_termios_callbacks device;
+ volatile unsigned int flow_ctrl;
+ unsigned int lowwater,highwater;
};
+/* fields for "flow_ctrl" status */
+#define FL_IREQXOF 1 /* input queue requests stop of incoming data */
+#define FL_ISNTXOF 2 /* XOFF has been sent to other side of line */
+#define FL_IRTSOFF 4 /* RTS has been turned off for other side.. */
+
+#define FL_ORCVXOF 0x10 /* XOFF has been received */
+#define FL_OSTOP 0x20 /* output has been stopped due to XOFF */
+
+#define FL_MDRTS 0x100 /* input controlled with RTS/CTS handshake */
+#define FL_MDXON 0x200 /* input controlled with XON/XOFF protocol */
+#define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */
+
static struct rtems_termios_tty *ttyHead, *ttyTail;
static rtems_id ttyMutex;
@@ -270,6 +284,7 @@ rtems_termios_open (
tty->termios.c_oflag = OPOST | ONLCR | XTABS;
tty->termios.c_cflag = B9600 | CS8 | CREAD;
tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
+
tty->termios.c_cc[VINTR] = '\003';
tty->termios.c_cc[VQUIT] = '\034';
tty->termios.c_cc[VERASE] = '\177';
@@ -285,11 +300,19 @@ rtems_termios_open (
tty->termios.c_cc[VWERASE] = '\027';
tty->termios.c_cc[VLNEXT] = '\026';
+ /* setup flow control mode, clear flow control flags */
+ tty->flow_ctrl = FL_MDXON;
+ /*
+ * set low/highwater mark for XON/XOFF support
+ */
+ tty->lowwater = RAW_INPUT_BUFFER_SIZE * 1/2;
+ tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4;
/*
* Bump name characer
*/
if (c++ == 'z')
c = 'a';
+
}
args->iop->data1 = tty;
if (!tty->refcount++ && tty->device.firstOpen)
@@ -356,6 +379,75 @@ rtems_termios_close (void *arg)
return RTEMS_SUCCESSFUL;
}
+static void
+termios_set_flowctrl(struct rtems_termios_tty *tty)
+{
+ rtems_interrupt_level level;
+ /*
+ * check for flow control options to be switched off
+ */
+
+ /* check for outgoing XON/XOFF flow control switched off */
+ if (( tty->flow_ctrl & FL_MDXON) &&
+ !(tty->termios.c_iflag & IXON)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);
+
+ /* has output been stopped due to received XOFF? */
+ if (tty->flow_ctrl & FL_OSTOP) {
+ /* disable interrupts */
+ rtems_interrupt_disable(level);
+ tty->flow_ctrl &= ~FL_OSTOP;
+ /* check for chars in output buffer (or rob_state?) */
+ if (tty->rawOutBufState != rob_idle) {
+ /* if chars available, call write function... */
+ (*tty->device.write)(tty->minor,
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+ }
+ }
+ /* check for incoming XON/XOFF flow control switched off */
+ if (( tty->flow_ctrl & FL_MDXOF) &&
+ !(tty->termios.c_iflag & IXOFF)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDXOF);
+ /* FIXME: what happens, if we had sent XOFF but not yet XON? */
+ tty->flow_ctrl &= ~(FL_ISNTXOF);
+ }
+
+ /* check for incoming RTS/CTS flow control switched off */
+ if (( tty->flow_ctrl & FL_MDRTS) &&
+ !(tty->termios.c_cflag & CRTSCTS)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDRTS);
+
+ /* restart remote Tx, if it was stopped */
+ if ((tty->flow_ctrl & FL_IRTSOFF) &&
+ (tty->device.startRemoteTx != NULL)) {
+ tty->device.startRemoteTx(tty->minor);
+ }
+ tty->flow_ctrl &= ~(FL_IRTSOFF);
+ }
+
+ /*
+ * check for flow control options to be switched on
+ */
+ /* check for incoming RTS/CTS flow control switched on */
+ if (tty->termios.c_cflag & CRTSCTS) {
+ tty->flow_ctrl |= FL_MDRTS;
+ }
+ /* check for incoming XON/XOF flow control switched on */
+ if (tty->termios.c_iflag & IXOFF) {
+ tty->flow_ctrl |= FL_MDXOF;
+ }
+ /* check for outgoing XON/XOF flow control switched on */
+ if (tty->termios.c_iflag & IXON) {
+ tty->flow_ctrl |= FL_MDXON;
+ }
+}
+
rtems_status_code
rtems_termios_ioctl (void *arg)
{
@@ -380,6 +472,10 @@ rtems_termios_ioctl (void *arg)
case RTEMS_IO_SET_ATTRIBUTES:
tty->termios = *(struct termios *)args->buffer;
+
+ /* check for and process change in flow control options */
+ termios_set_flowctrl(tty);
+
if (tty->termios.c_lflag & ICANON) {
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
@@ -464,9 +560,16 @@ osend (const char *buf, int len, struct rtems_termios_tty *tty)
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
tty->rawOutBufHead = newHead;
if (tty->rawOutBufState == rob_idle) {
+ /* check, whether XOFF has been received */
+ if (!(tty->flow_ctrl & FL_ORCVXOF)) {
(*tty->device.write)(tty->minor,
- (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
- tty->rawOutBufState = rob_busy;
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);
+ }
+ else {
+ /* remember that output has been stopped due to flow ctrl*/
+ tty->flow_ctrl |= FL_OSTOP;
+ }
+ tty->rawOutBufState = rob_busy;
}
rtems_interrupt_enable (level);
len--;
@@ -807,6 +910,30 @@ fillBufferQueue (struct rtems_termios_tty *tty)
newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
c = tty->rawInBuf[newHead];
tty->rawInBufHead = newHead;
+ if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE)
+ % RAW_INPUT_BUFFER_SIZE)
+ < tty->lowwater) {
+ tty->flow_ctrl &= ~FL_IREQXOF;
+ /* if tx stopped and XON should be sent... */
+ if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
+ == (FL_MDXON | FL_ISNTXOF))
+ && ((tty->rawOutBufState == rob_idle)
+ || (tty->flow_ctrl & FL_OSTOP))) {
+ /* XON should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTART]),
+ 1);
+ }
+ else if (tty->flow_ctrl & FL_MDRTS) {
+ tty->flow_ctrl &= ~FL_IRTSOFF;
+ /* activate RTS line */
+ if (tty->device.startRemoteTx != NULL) {
+ tty->device.startRemoteTx(tty->minor);
+ }
+ }
+ }
+
+ /* continue processing new character */
if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty))
return RTEMS_SUCCESSFUL;
@@ -866,26 +993,106 @@ rtems_termios_read (void *arg)
* Place characters on raw queue.
* NOTE: This routine runs in the context of the
* device receive interrupt handler.
- * Returns the number of characters dropped because of overlow.
+ * Returns the number of characters dropped because of overflow.
*/
int
rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
{
struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
+ char c;
+ int dropped = 0;
+ boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
+ rtems_interrupt_level level;
- while (len) {
+ while (len--) {
+ c = *buf++;
+ /* FIXME: implement IXANY: any character restarts output */
+ /* if incoming XON/XOFF controls outgoing stream: */
+ if (tty->flow_ctrl & FL_MDXON) {
+ /* if received char is V_STOP and V_START (both are equal value) */
+ if (c == tty->termios.c_cc[VSTOP]) {
+ if (c == tty->termios.c_cc[VSTART]) {
+ /* received VSTOP and VSTART==VSTOP? */
+ /* then toggle "stop output" status */
+ tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
+ }
+ else {
+ /* VSTOP received (other code than VSTART) */
+ /* stop output */
+ tty->flow_ctrl |= FL_ORCVXOF;
+ }
+ flow_rcv = TRUE;
+ }
+ else if (c == tty->termios.c_cc[VSTART]) {
+ /* VSTART received */
+ /* restart output */
+ tty->flow_ctrl &= ~FL_ORCVXOF;
+ flow_rcv = TRUE;
+ }
+ }
+ if (flow_rcv) {
+ /* restart output according to FL_ORCVXOF flag */
+ if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
+ /* disable interrupts */
+ rtems_interrupt_disable(level);
+ tty->flow_ctrl &= ~FL_OSTOP;
+ /* check for chars in output buffer (or rob_state?) */
+ if (tty->rawOutBufState != rob_idle) {
+ /* if chars available, call write function... */
+ (*tty->device.write)(tty->minor,
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+ }
+ }
+ else {
newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
+ /* if chars_in_buffer > highwater */
+ rtems_interrupt_disable(level);
+ if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE)
+ % RAW_INPUT_BUFFER_SIZE)
+ > tty->highwater) &&
+ !(tty->flow_ctrl & FL_IREQXOF)) {
+ /* incoming data stream should be stopped */
+ tty->flow_ctrl |= FL_IREQXOF;
+ if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
+ == (FL_MDXOF ) ){
+ if ((tty->flow_ctrl & FL_OSTOP) ||
+ (tty->rawOutBufState == rob_idle)) {
+ /* if tx is stopped due to XOFF or out of data */
+ /* call write function here */
+ tty->flow_ctrl |= FL_ISNTXOF;
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTOP]),
+ 1);
+ }
+ }
+ else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF))
+ == (FL_MDRTS ) ) {
+ tty->flow_ctrl |= FL_IRTSOFF;
+ /* deactivate RTS line */
+ if (tty->device.stopRemoteTx != NULL) {
+ tty->device.stopRemoteTx(tty->minor);
+ }
+ }
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+
if (newTail == tty->rawInBufHead) {
- tty->rawInBufDropped += len;
- break;
+ dropped++;
}
- tty->rawInBuf[newTail] = *buf++;
- len--;
- tty->rawInBufTail = newTail;
+ else {
+ tty->rawInBuf[newTail] = c;
+ tty->rawInBufTail = newTail;
+ }
+ }
}
+ tty->rawInBufDropped += dropped;
rtems_semaphore_release (tty->rawInBufSemaphore);
- return len;
+ return dropped;
}
/*
@@ -904,31 +1111,64 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
unsigned int newTail;
int nToSend;
- if (tty->rawOutBufState == rob_wait)
- rtems_semaphore_release (tty->rawOutBufSemaphore);
- if ( tty->rawOutBufHead == tty->rawOutBufTail )
- return 0;
- newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
- if (newTail == tty->rawOutBufHead) {
- /*
- * Buffer empty
- */
- tty->rawOutBufState = rob_idle;
- nToSend = 0;
+ /* check for XOF/XON to send */
+ if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
+ == (FL_MDXOF | FL_IREQXOF)) {
+ /* XOFF should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTOP]), 1);
+ tty->flow_ctrl |= FL_ISNTXOF;
+ nToSend = 1;
+ }
+ else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
+ == FL_ISNTXOF) {
+ /* NOTE: send XON even, if no longer in XON/XOFF mode... */
+ /* XON should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTART]), 1);
+ tty->flow_ctrl &= ~FL_ISNTXOF;
+ nToSend = 1;
}
else {
- /*
- * Buffer not empty, start tranmitter
- */
- if (newTail > tty->rawOutBufHead)
- nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
- else
- nToSend = tty->rawOutBufHead - newTail;
- (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
- tty->rawOutBufState = rob_busy;
+ if (tty->rawOutBufState == rob_wait)
+ rtems_semaphore_release (tty->rawOutBufSemaphore);
+ if ( tty->rawOutBufHead == tty->rawOutBufTail )
+ return 0;
+ newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
+ if (newTail == tty->rawOutBufHead) {
+ /*
+ * Buffer empty
+ */
+ tty->rawOutBufState = rob_idle;
+ nToSend = 0;
+ }
+ /* check, whether output should stop due to received XOFF */
+ else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
+ == (FL_MDXON | FL_ORCVXOF)) {
+ /* Buffer not empty, but output stops due to XOFF */
+ /* set flag, that output has been stopped */
+ tty->flow_ctrl |= FL_OSTOP;
+ nToSend = 0;
+ }
+ else {
+ /*
+ * Buffer not empty, start tranmitter
+ */
+ if (newTail > tty->rawOutBufHead)
+ nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
+ else
+ nToSend = tty->rawOutBufHead - newTail;
+ /* when flow control XON or XOF, don't send blocks of data */
+ /* to allow fast reaction on incoming flow ctrl and low latency*/
+ /* for outgoing flow control */
+ if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
+ nToSend = 1;
+ }
+ (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
+ tty->rawOutBufState = rob_busy;
+ }
+ tty->rawOutBufTail = newTail;
}
- tty->rawOutBufTail = newTail;
-
return nToSend;
}
diff --git a/c/src/lib/libc/termios.c b/c/src/lib/libc/termios.c
index c2a43c7707..e783e54753 100644
--- a/c/src/lib/libc/termios.c
+++ b/c/src/lib/libc/termios.c
@@ -125,8 +125,22 @@ struct rtems_termios_tty {
* Callbacks to device-specific routines
*/
rtems_termios_callbacks device;
+ volatile unsigned int flow_ctrl;
+ unsigned int lowwater,highwater;
};
+/* fields for "flow_ctrl" status */
+#define FL_IREQXOF 1 /* input queue requests stop of incoming data */
+#define FL_ISNTXOF 2 /* XOFF has been sent to other side of line */
+#define FL_IRTSOFF 4 /* RTS has been turned off for other side.. */
+
+#define FL_ORCVXOF 0x10 /* XOFF has been received */
+#define FL_OSTOP 0x20 /* output has been stopped due to XOFF */
+
+#define FL_MDRTS 0x100 /* input controlled with RTS/CTS handshake */
+#define FL_MDXON 0x200 /* input controlled with XON/XOFF protocol */
+#define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */
+
static struct rtems_termios_tty *ttyHead, *ttyTail;
static rtems_id ttyMutex;
@@ -270,6 +284,7 @@ rtems_termios_open (
tty->termios.c_oflag = OPOST | ONLCR | XTABS;
tty->termios.c_cflag = B9600 | CS8 | CREAD;
tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
+
tty->termios.c_cc[VINTR] = '\003';
tty->termios.c_cc[VQUIT] = '\034';
tty->termios.c_cc[VERASE] = '\177';
@@ -285,11 +300,19 @@ rtems_termios_open (
tty->termios.c_cc[VWERASE] = '\027';
tty->termios.c_cc[VLNEXT] = '\026';
+ /* setup flow control mode, clear flow control flags */
+ tty->flow_ctrl = FL_MDXON;
+ /*
+ * set low/highwater mark for XON/XOFF support
+ */
+ tty->lowwater = RAW_INPUT_BUFFER_SIZE * 1/2;
+ tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4;
/*
* Bump name characer
*/
if (c++ == 'z')
c = 'a';
+
}
args->iop->data1 = tty;
if (!tty->refcount++ && tty->device.firstOpen)
@@ -356,6 +379,75 @@ rtems_termios_close (void *arg)
return RTEMS_SUCCESSFUL;
}
+static void
+termios_set_flowctrl(struct rtems_termios_tty *tty)
+{
+ rtems_interrupt_level level;
+ /*
+ * check for flow control options to be switched off
+ */
+
+ /* check for outgoing XON/XOFF flow control switched off */
+ if (( tty->flow_ctrl & FL_MDXON) &&
+ !(tty->termios.c_iflag & IXON)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);
+
+ /* has output been stopped due to received XOFF? */
+ if (tty->flow_ctrl & FL_OSTOP) {
+ /* disable interrupts */
+ rtems_interrupt_disable(level);
+ tty->flow_ctrl &= ~FL_OSTOP;
+ /* check for chars in output buffer (or rob_state?) */
+ if (tty->rawOutBufState != rob_idle) {
+ /* if chars available, call write function... */
+ (*tty->device.write)(tty->minor,
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+ }
+ }
+ /* check for incoming XON/XOFF flow control switched off */
+ if (( tty->flow_ctrl & FL_MDXOF) &&
+ !(tty->termios.c_iflag & IXOFF)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDXOF);
+ /* FIXME: what happens, if we had sent XOFF but not yet XON? */
+ tty->flow_ctrl &= ~(FL_ISNTXOF);
+ }
+
+ /* check for incoming RTS/CTS flow control switched off */
+ if (( tty->flow_ctrl & FL_MDRTS) &&
+ !(tty->termios.c_cflag & CRTSCTS)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDRTS);
+
+ /* restart remote Tx, if it was stopped */
+ if ((tty->flow_ctrl & FL_IRTSOFF) &&
+ (tty->device.startRemoteTx != NULL)) {
+ tty->device.startRemoteTx(tty->minor);
+ }
+ tty->flow_ctrl &= ~(FL_IRTSOFF);
+ }
+
+ /*
+ * check for flow control options to be switched on
+ */
+ /* check for incoming RTS/CTS flow control switched on */
+ if (tty->termios.c_cflag & CRTSCTS) {
+ tty->flow_ctrl |= FL_MDRTS;
+ }
+ /* check for incoming XON/XOF flow control switched on */
+ if (tty->termios.c_iflag & IXOFF) {
+ tty->flow_ctrl |= FL_MDXOF;
+ }
+ /* check for outgoing XON/XOF flow control switched on */
+ if (tty->termios.c_iflag & IXON) {
+ tty->flow_ctrl |= FL_MDXON;
+ }
+}
+
rtems_status_code
rtems_termios_ioctl (void *arg)
{
@@ -380,6 +472,10 @@ rtems_termios_ioctl (void *arg)
case RTEMS_IO_SET_ATTRIBUTES:
tty->termios = *(struct termios *)args->buffer;
+
+ /* check for and process change in flow control options */
+ termios_set_flowctrl(tty);
+
if (tty->termios.c_lflag & ICANON) {
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
@@ -464,9 +560,16 @@ osend (const char *buf, int len, struct rtems_termios_tty *tty)
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
tty->rawOutBufHead = newHead;
if (tty->rawOutBufState == rob_idle) {
+ /* check, whether XOFF has been received */
+ if (!(tty->flow_ctrl & FL_ORCVXOF)) {
(*tty->device.write)(tty->minor,
- (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
- tty->rawOutBufState = rob_busy;
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);
+ }
+ else {
+ /* remember that output has been stopped due to flow ctrl*/
+ tty->flow_ctrl |= FL_OSTOP;
+ }
+ tty->rawOutBufState = rob_busy;
}
rtems_interrupt_enable (level);
len--;
@@ -807,6 +910,30 @@ fillBufferQueue (struct rtems_termios_tty *tty)
newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
c = tty->rawInBuf[newHead];
tty->rawInBufHead = newHead;
+ if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE)
+ % RAW_INPUT_BUFFER_SIZE)
+ < tty->lowwater) {
+ tty->flow_ctrl &= ~FL_IREQXOF;
+ /* if tx stopped and XON should be sent... */
+ if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
+ == (FL_MDXON | FL_ISNTXOF))
+ && ((tty->rawOutBufState == rob_idle)
+ || (tty->flow_ctrl & FL_OSTOP))) {
+ /* XON should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTART]),
+ 1);
+ }
+ else if (tty->flow_ctrl & FL_MDRTS) {
+ tty->flow_ctrl &= ~FL_IRTSOFF;
+ /* activate RTS line */
+ if (tty->device.startRemoteTx != NULL) {
+ tty->device.startRemoteTx(tty->minor);
+ }
+ }
+ }
+
+ /* continue processing new character */
if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty))
return RTEMS_SUCCESSFUL;
@@ -866,26 +993,106 @@ rtems_termios_read (void *arg)
* Place characters on raw queue.
* NOTE: This routine runs in the context of the
* device receive interrupt handler.
- * Returns the number of characters dropped because of overlow.
+ * Returns the number of characters dropped because of overflow.
*/
int
rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
{
struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
+ char c;
+ int dropped = 0;
+ boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
+ rtems_interrupt_level level;
- while (len) {
+ while (len--) {
+ c = *buf++;
+ /* FIXME: implement IXANY: any character restarts output */
+ /* if incoming XON/XOFF controls outgoing stream: */
+ if (tty->flow_ctrl & FL_MDXON) {
+ /* if received char is V_STOP and V_START (both are equal value) */
+ if (c == tty->termios.c_cc[VSTOP]) {
+ if (c == tty->termios.c_cc[VSTART]) {
+ /* received VSTOP and VSTART==VSTOP? */
+ /* then toggle "stop output" status */
+ tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
+ }
+ else {
+ /* VSTOP received (other code than VSTART) */
+ /* stop output */
+ tty->flow_ctrl |= FL_ORCVXOF;
+ }
+ flow_rcv = TRUE;
+ }
+ else if (c == tty->termios.c_cc[VSTART]) {
+ /* VSTART received */
+ /* restart output */
+ tty->flow_ctrl &= ~FL_ORCVXOF;
+ flow_rcv = TRUE;
+ }
+ }
+ if (flow_rcv) {
+ /* restart output according to FL_ORCVXOF flag */
+ if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
+ /* disable interrupts */
+ rtems_interrupt_disable(level);
+ tty->flow_ctrl &= ~FL_OSTOP;
+ /* check for chars in output buffer (or rob_state?) */
+ if (tty->rawOutBufState != rob_idle) {
+ /* if chars available, call write function... */
+ (*tty->device.write)(tty->minor,
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+ }
+ }
+ else {
newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
+ /* if chars_in_buffer > highwater */
+ rtems_interrupt_disable(level);
+ if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE)
+ % RAW_INPUT_BUFFER_SIZE)
+ > tty->highwater) &&
+ !(tty->flow_ctrl & FL_IREQXOF)) {
+ /* incoming data stream should be stopped */
+ tty->flow_ctrl |= FL_IREQXOF;
+ if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
+ == (FL_MDXOF ) ){
+ if ((tty->flow_ctrl & FL_OSTOP) ||
+ (tty->rawOutBufState == rob_idle)) {
+ /* if tx is stopped due to XOFF or out of data */
+ /* call write function here */
+ tty->flow_ctrl |= FL_ISNTXOF;
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTOP]),
+ 1);
+ }
+ }
+ else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF))
+ == (FL_MDRTS ) ) {
+ tty->flow_ctrl |= FL_IRTSOFF;
+ /* deactivate RTS line */
+ if (tty->device.stopRemoteTx != NULL) {
+ tty->device.stopRemoteTx(tty->minor);
+ }
+ }
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+
if (newTail == tty->rawInBufHead) {
- tty->rawInBufDropped += len;
- break;
+ dropped++;
}
- tty->rawInBuf[newTail] = *buf++;
- len--;
- tty->rawInBufTail = newTail;
+ else {
+ tty->rawInBuf[newTail] = c;
+ tty->rawInBufTail = newTail;
+ }
+ }
}
+ tty->rawInBufDropped += dropped;
rtems_semaphore_release (tty->rawInBufSemaphore);
- return len;
+ return dropped;
}
/*
@@ -904,31 +1111,64 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
unsigned int newTail;
int nToSend;
- if (tty->rawOutBufState == rob_wait)
- rtems_semaphore_release (tty->rawOutBufSemaphore);
- if ( tty->rawOutBufHead == tty->rawOutBufTail )
- return 0;
- newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
- if (newTail == tty->rawOutBufHead) {
- /*
- * Buffer empty
- */
- tty->rawOutBufState = rob_idle;
- nToSend = 0;
+ /* check for XOF/XON to send */
+ if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
+ == (FL_MDXOF | FL_IREQXOF)) {
+ /* XOFF should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTOP]), 1);
+ tty->flow_ctrl |= FL_ISNTXOF;
+ nToSend = 1;
+ }
+ else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
+ == FL_ISNTXOF) {
+ /* NOTE: send XON even, if no longer in XON/XOFF mode... */
+ /* XON should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTART]), 1);
+ tty->flow_ctrl &= ~FL_ISNTXOF;
+ nToSend = 1;
}
else {
- /*
- * Buffer not empty, start tranmitter
- */
- if (newTail > tty->rawOutBufHead)
- nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
- else
- nToSend = tty->rawOutBufHead - newTail;
- (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
- tty->rawOutBufState = rob_busy;
+ if (tty->rawOutBufState == rob_wait)
+ rtems_semaphore_release (tty->rawOutBufSemaphore);
+ if ( tty->rawOutBufHead == tty->rawOutBufTail )
+ return 0;
+ newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
+ if (newTail == tty->rawOutBufHead) {
+ /*
+ * Buffer empty
+ */
+ tty->rawOutBufState = rob_idle;
+ nToSend = 0;
+ }
+ /* check, whether output should stop due to received XOFF */
+ else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
+ == (FL_MDXON | FL_ORCVXOF)) {
+ /* Buffer not empty, but output stops due to XOFF */
+ /* set flag, that output has been stopped */
+ tty->flow_ctrl |= FL_OSTOP;
+ nToSend = 0;
+ }
+ else {
+ /*
+ * Buffer not empty, start tranmitter
+ */
+ if (newTail > tty->rawOutBufHead)
+ nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
+ else
+ nToSend = tty->rawOutBufHead - newTail;
+ /* when flow control XON or XOF, don't send blocks of data */
+ /* to allow fast reaction on incoming flow ctrl and low latency*/
+ /* for outgoing flow control */
+ if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
+ nToSend = 1;
+ }
+ (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
+ tty->rawOutBufState = rob_busy;
+ }
+ tty->rawOutBufTail = newTail;
}
- tty->rawOutBufTail = newTail;
-
return nToSend;
}
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index c2a43c7707..e783e54753 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -125,8 +125,22 @@ struct rtems_termios_tty {
* Callbacks to device-specific routines
*/
rtems_termios_callbacks device;
+ volatile unsigned int flow_ctrl;
+ unsigned int lowwater,highwater;
};
+/* fields for "flow_ctrl" status */
+#define FL_IREQXOF 1 /* input queue requests stop of incoming data */
+#define FL_ISNTXOF 2 /* XOFF has been sent to other side of line */
+#define FL_IRTSOFF 4 /* RTS has been turned off for other side.. */
+
+#define FL_ORCVXOF 0x10 /* XOFF has been received */
+#define FL_OSTOP 0x20 /* output has been stopped due to XOFF */
+
+#define FL_MDRTS 0x100 /* input controlled with RTS/CTS handshake */
+#define FL_MDXON 0x200 /* input controlled with XON/XOFF protocol */
+#define FL_MDXOF 0x400 /* output controlled with XON/XOFF protocol */
+
static struct rtems_termios_tty *ttyHead, *ttyTail;
static rtems_id ttyMutex;
@@ -270,6 +284,7 @@ rtems_termios_open (
tty->termios.c_oflag = OPOST | ONLCR | XTABS;
tty->termios.c_cflag = B9600 | CS8 | CREAD;
tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
+
tty->termios.c_cc[VINTR] = '\003';
tty->termios.c_cc[VQUIT] = '\034';
tty->termios.c_cc[VERASE] = '\177';
@@ -285,11 +300,19 @@ rtems_termios_open (
tty->termios.c_cc[VWERASE] = '\027';
tty->termios.c_cc[VLNEXT] = '\026';
+ /* setup flow control mode, clear flow control flags */
+ tty->flow_ctrl = FL_MDXON;
+ /*
+ * set low/highwater mark for XON/XOFF support
+ */
+ tty->lowwater = RAW_INPUT_BUFFER_SIZE * 1/2;
+ tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4;
/*
* Bump name characer
*/
if (c++ == 'z')
c = 'a';
+
}
args->iop->data1 = tty;
if (!tty->refcount++ && tty->device.firstOpen)
@@ -356,6 +379,75 @@ rtems_termios_close (void *arg)
return RTEMS_SUCCESSFUL;
}
+static void
+termios_set_flowctrl(struct rtems_termios_tty *tty)
+{
+ rtems_interrupt_level level;
+ /*
+ * check for flow control options to be switched off
+ */
+
+ /* check for outgoing XON/XOFF flow control switched off */
+ if (( tty->flow_ctrl & FL_MDXON) &&
+ !(tty->termios.c_iflag & IXON)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);
+
+ /* has output been stopped due to received XOFF? */
+ if (tty->flow_ctrl & FL_OSTOP) {
+ /* disable interrupts */
+ rtems_interrupt_disable(level);
+ tty->flow_ctrl &= ~FL_OSTOP;
+ /* check for chars in output buffer (or rob_state?) */
+ if (tty->rawOutBufState != rob_idle) {
+ /* if chars available, call write function... */
+ (*tty->device.write)(tty->minor,
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+ }
+ }
+ /* check for incoming XON/XOFF flow control switched off */
+ if (( tty->flow_ctrl & FL_MDXOF) &&
+ !(tty->termios.c_iflag & IXOFF)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDXOF);
+ /* FIXME: what happens, if we had sent XOFF but not yet XON? */
+ tty->flow_ctrl &= ~(FL_ISNTXOF);
+ }
+
+ /* check for incoming RTS/CTS flow control switched off */
+ if (( tty->flow_ctrl & FL_MDRTS) &&
+ !(tty->termios.c_cflag & CRTSCTS)) {
+ /* clear related flags in flow_ctrl */
+ tty->flow_ctrl &= ~(FL_MDRTS);
+
+ /* restart remote Tx, if it was stopped */
+ if ((tty->flow_ctrl & FL_IRTSOFF) &&
+ (tty->device.startRemoteTx != NULL)) {
+ tty->device.startRemoteTx(tty->minor);
+ }
+ tty->flow_ctrl &= ~(FL_IRTSOFF);
+ }
+
+ /*
+ * check for flow control options to be switched on
+ */
+ /* check for incoming RTS/CTS flow control switched on */
+ if (tty->termios.c_cflag & CRTSCTS) {
+ tty->flow_ctrl |= FL_MDRTS;
+ }
+ /* check for incoming XON/XOF flow control switched on */
+ if (tty->termios.c_iflag & IXOFF) {
+ tty->flow_ctrl |= FL_MDXOF;
+ }
+ /* check for outgoing XON/XOF flow control switched on */
+ if (tty->termios.c_iflag & IXON) {
+ tty->flow_ctrl |= FL_MDXON;
+ }
+}
+
rtems_status_code
rtems_termios_ioctl (void *arg)
{
@@ -380,6 +472,10 @@ rtems_termios_ioctl (void *arg)
case RTEMS_IO_SET_ATTRIBUTES:
tty->termios = *(struct termios *)args->buffer;
+
+ /* check for and process change in flow control options */
+ termios_set_flowctrl(tty);
+
if (tty->termios.c_lflag & ICANON) {
tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
@@ -464,9 +560,16 @@ osend (const char *buf, int len, struct rtems_termios_tty *tty)
tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
tty->rawOutBufHead = newHead;
if (tty->rawOutBufState == rob_idle) {
+ /* check, whether XOFF has been received */
+ if (!(tty->flow_ctrl & FL_ORCVXOF)) {
(*tty->device.write)(tty->minor,
- (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
- tty->rawOutBufState = rob_busy;
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);
+ }
+ else {
+ /* remember that output has been stopped due to flow ctrl*/
+ tty->flow_ctrl |= FL_OSTOP;
+ }
+ tty->rawOutBufState = rob_busy;
}
rtems_interrupt_enable (level);
len--;
@@ -807,6 +910,30 @@ fillBufferQueue (struct rtems_termios_tty *tty)
newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
c = tty->rawInBuf[newHead];
tty->rawInBufHead = newHead;
+ if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE)
+ % RAW_INPUT_BUFFER_SIZE)
+ < tty->lowwater) {
+ tty->flow_ctrl &= ~FL_IREQXOF;
+ /* if tx stopped and XON should be sent... */
+ if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
+ == (FL_MDXON | FL_ISNTXOF))
+ && ((tty->rawOutBufState == rob_idle)
+ || (tty->flow_ctrl & FL_OSTOP))) {
+ /* XON should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTART]),
+ 1);
+ }
+ else if (tty->flow_ctrl & FL_MDRTS) {
+ tty->flow_ctrl &= ~FL_IRTSOFF;
+ /* activate RTS line */
+ if (tty->device.startRemoteTx != NULL) {
+ tty->device.startRemoteTx(tty->minor);
+ }
+ }
+ }
+
+ /* continue processing new character */
if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty))
return RTEMS_SUCCESSFUL;
@@ -866,26 +993,106 @@ rtems_termios_read (void *arg)
* Place characters on raw queue.
* NOTE: This routine runs in the context of the
* device receive interrupt handler.
- * Returns the number of characters dropped because of overlow.
+ * Returns the number of characters dropped because of overflow.
*/
int
rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
{
struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
+ char c;
+ int dropped = 0;
+ boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
+ rtems_interrupt_level level;
- while (len) {
+ while (len--) {
+ c = *buf++;
+ /* FIXME: implement IXANY: any character restarts output */
+ /* if incoming XON/XOFF controls outgoing stream: */
+ if (tty->flow_ctrl & FL_MDXON) {
+ /* if received char is V_STOP and V_START (both are equal value) */
+ if (c == tty->termios.c_cc[VSTOP]) {
+ if (c == tty->termios.c_cc[VSTART]) {
+ /* received VSTOP and VSTART==VSTOP? */
+ /* then toggle "stop output" status */
+ tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
+ }
+ else {
+ /* VSTOP received (other code than VSTART) */
+ /* stop output */
+ tty->flow_ctrl |= FL_ORCVXOF;
+ }
+ flow_rcv = TRUE;
+ }
+ else if (c == tty->termios.c_cc[VSTART]) {
+ /* VSTART received */
+ /* restart output */
+ tty->flow_ctrl &= ~FL_ORCVXOF;
+ flow_rcv = TRUE;
+ }
+ }
+ if (flow_rcv) {
+ /* restart output according to FL_ORCVXOF flag */
+ if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
+ /* disable interrupts */
+ rtems_interrupt_disable(level);
+ tty->flow_ctrl &= ~FL_OSTOP;
+ /* check for chars in output buffer (or rob_state?) */
+ if (tty->rawOutBufState != rob_idle) {
+ /* if chars available, call write function... */
+ (*tty->device.write)(tty->minor,
+ (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+ }
+ }
+ else {
newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
+ /* if chars_in_buffer > highwater */
+ rtems_interrupt_disable(level);
+ if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE)
+ % RAW_INPUT_BUFFER_SIZE)
+ > tty->highwater) &&
+ !(tty->flow_ctrl & FL_IREQXOF)) {
+ /* incoming data stream should be stopped */
+ tty->flow_ctrl |= FL_IREQXOF;
+ if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
+ == (FL_MDXOF ) ){
+ if ((tty->flow_ctrl & FL_OSTOP) ||
+ (tty->rawOutBufState == rob_idle)) {
+ /* if tx is stopped due to XOFF or out of data */
+ /* call write function here */
+ tty->flow_ctrl |= FL_ISNTXOF;
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTOP]),
+ 1);
+ }
+ }
+ else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF))
+ == (FL_MDRTS ) ) {
+ tty->flow_ctrl |= FL_IRTSOFF;
+ /* deactivate RTS line */
+ if (tty->device.stopRemoteTx != NULL) {
+ tty->device.stopRemoteTx(tty->minor);
+ }
+ }
+ }
+ /* reenable interrupts */
+ rtems_interrupt_enable(level);
+
if (newTail == tty->rawInBufHead) {
- tty->rawInBufDropped += len;
- break;
+ dropped++;
}
- tty->rawInBuf[newTail] = *buf++;
- len--;
- tty->rawInBufTail = newTail;
+ else {
+ tty->rawInBuf[newTail] = c;
+ tty->rawInBufTail = newTail;
+ }
+ }
}
+ tty->rawInBufDropped += dropped;
rtems_semaphore_release (tty->rawInBufSemaphore);
- return len;
+ return dropped;
}
/*
@@ -904,31 +1111,64 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
unsigned int newTail;
int nToSend;
- if (tty->rawOutBufState == rob_wait)
- rtems_semaphore_release (tty->rawOutBufSemaphore);
- if ( tty->rawOutBufHead == tty->rawOutBufTail )
- return 0;
- newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
- if (newTail == tty->rawOutBufHead) {
- /*
- * Buffer empty
- */
- tty->rawOutBufState = rob_idle;
- nToSend = 0;
+ /* check for XOF/XON to send */
+ if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
+ == (FL_MDXOF | FL_IREQXOF)) {
+ /* XOFF should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTOP]), 1);
+ tty->flow_ctrl |= FL_ISNTXOF;
+ nToSend = 1;
+ }
+ else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
+ == FL_ISNTXOF) {
+ /* NOTE: send XON even, if no longer in XON/XOFF mode... */
+ /* XON should be sent now... */
+ (*tty->device.write)(tty->minor,
+ &(tty->termios.c_cc[VSTART]), 1);
+ tty->flow_ctrl &= ~FL_ISNTXOF;
+ nToSend = 1;
}
else {
- /*
- * Buffer not empty, start tranmitter
- */
- if (newTail > tty->rawOutBufHead)
- nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
- else
- nToSend = tty->rawOutBufHead - newTail;
- (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
- tty->rawOutBufState = rob_busy;
+ if (tty->rawOutBufState == rob_wait)
+ rtems_semaphore_release (tty->rawOutBufSemaphore);
+ if ( tty->rawOutBufHead == tty->rawOutBufTail )
+ return 0;
+ newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
+ if (newTail == tty->rawOutBufHead) {
+ /*
+ * Buffer empty
+ */
+ tty->rawOutBufState = rob_idle;
+ nToSend = 0;
+ }
+ /* check, whether output should stop due to received XOFF */
+ else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
+ == (FL_MDXON | FL_ORCVXOF)) {
+ /* Buffer not empty, but output stops due to XOFF */
+ /* set flag, that output has been stopped */
+ tty->flow_ctrl |= FL_OSTOP;
+ nToSend = 0;
+ }
+ else {
+ /*
+ * Buffer not empty, start tranmitter
+ */
+ if (newTail > tty->rawOutBufHead)
+ nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
+ else
+ nToSend = tty->rawOutBufHead - newTail;
+ /* when flow control XON or XOF, don't send blocks of data */
+ /* to allow fast reaction on incoming flow ctrl and low latency*/
+ /* for outgoing flow control */
+ if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
+ nToSend = 1;
+ }
+ (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
+ tty->rawOutBufState = rob_busy;
+ }
+ tty->rawOutBufTail = newTail;
}
- tty->rawOutBufTail = newTail;
-
return nToSend;
}