source: rtems/cpukit/libcsupport/src/termios.c @ 2f1b930

4.104.114.84.95
Last change on this file since 2f1b930 was 4b3c197f, checked in by Joel Sherrill <joel.sherrill@…>, on 08/16/01 at 20:04:19

2001-08-16 Mike Siers <mikes@…>

  • libc/termios.c: Fix a bug in the termios implementation in the following scenario: The General Terminal Interface document that me states that if VMIN = 0 and VTIME = 0, then read() should return the minimum of two values:

a) number of bytes available
b) number of bytes requested (I assume from the read call)

The current implementation of the fillBufferQueue() in termios.c is
always return 1 character with these setting values. I know the
termios buffer has more than one character available and my read()
call is requesting 1024 bytes.

  • Property mode set to 100644
File size: 36.5 KB
Line 
1/*
2 * TERMIOS serial line support
3 *
4 *  Author:
5 *    W. Eric Norum
6 *    Saskatchewan Accelerator Laboratory
7 *    University of Saskatchewan
8 *    Saskatoon, Saskatchewan, CANADA
9 *    eric@skatter.usask.ca
10 *
11 *  The license and distribution terms for this file may be
12 *  found in the file LICENSE in this distribution or at
13 *  http://www.OARcorp.com/rtems/license.html.
14 *
15 *  $Id$
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <rtems.h>
23#include <rtems/libio.h>
24#include <ctype.h>
25#include <errno.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <termios.h>
29#include <unistd.h>
30#include <sys/ttycom.h>
31
32#include <rtems/termiostypes.h>
33
34/*
35 *  FreeBSD does not support a full POSIX termios so we have to help it out
36 */
37
38#if defined(__FreeBSD__)
39#define XTABS   0
40#define ONLRET  0
41#define ONOCR   0
42#define TABDLY  0
43#define OLCUC   0
44#define ILCUC   0
45#define OCRNL   0
46#define IUCLC   0
47#endif
48
49/*
50 *  Cygwin does not define these
51 */
52
53#if defined(__CYGWIN__)
54#define ECHOPRT 0
55#endif
56
57/*
58 * The size of the cooked buffer
59 */
60#define CBUFSIZE        256
61
62/*
63 * The sizes of the raw message buffers.
64 * On most architectures it is quite a bit more
65 * efficient if these are powers of two.
66 */
67#define RAW_INPUT_BUFFER_SIZE   128
68#define RAW_OUTPUT_BUFFER_SIZE  64
69
70/* fields for "flow_ctrl" status */
71#define FL_IREQXOF 1        /* input queue requests stop of incoming data */
72#define FL_ISNTXOF 2        /* XOFF has been sent to other side of line   */
73#define FL_IRTSOFF 4        /* RTS has been turned off for other side..   */
74
75#define FL_ORCVXOF 0x10     /* XOFF has been received                     */
76#define FL_OSTOP   0x20     /* output has been stopped due to XOFF        */
77
78#define FL_MDRTS   0x100    /* input controlled with RTS/CTS handshake    */
79#define FL_MDXON   0x200    /* input controlled with XON/XOFF protocol    */
80#define FL_MDXOF   0x400    /* output controlled with XON/XOFF protocol   */
81
82#define NODISC(n) \
83        { NULL, NULL,   NULL,   NULL, \
84          NULL, NULL,   NULL,   NULL }
85/*
86 * FIXME: change linesw entries consistant with linesw entry usage...
87 */
88struct  linesw linesw[MAXLDISC] =
89{
90        NODISC(0),              /* 0- termios-built-in */
91        NODISC(1),              /* 1- defunct */
92        NODISC(2),              /* 2- NTTYDISC */
93        NODISC(3),              /* TABLDISC */
94        NODISC(4),              /* SLIPDISC */
95        NODISC(5),              /* PPPDISC */
96        NODISC(6),              /* loadable */
97        NODISC(7),              /* loadable */
98};
99
100int     nlinesw = sizeof (linesw) / sizeof (linesw[0]);
101
102extern struct rtems_termios_tty *rtems_termios_ttyHead;
103extern struct rtems_termios_tty *rtems_termios_ttyTail;
104extern rtems_id rtems_termios_ttyMutex;
105
106static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
107static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
108/*
109 * some constants for I/O daemon task creation
110 */
111#define TERMIOS_TXTASK_PRIO 10
112#define TERMIOS_RXTASK_PRIO 9
113#define TERMIOS_TXTASK_STACKSIZE 1024
114#define TERMIOS_RXTASK_STACKSIZE 1024
115/*
116 * some events to be sent to the I/O tasks
117 */
118#define TERMIOS_TX_START_EVENT     RTEMS_EVENT_1
119#define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0
120
121#define TERMIOS_RX_PROC_EVENT      RTEMS_EVENT_1
122#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
123
124/*
125 * Open a termios device
126 */
127rtems_status_code
128rtems_termios_open (
129  rtems_device_major_number      major,
130  rtems_device_minor_number      minor,
131  void                          *arg,
132  const rtems_termios_callbacks *callbacks
133  )
134{
135        rtems_status_code sc;
136        rtems_libio_open_close_args_t *args = arg;
137        struct rtems_termios_tty *tty;
138
139        /*
140         * See if the device has already been opened
141         */
142        sc = rtems_semaphore_obtain (rtems_termios_ttyMutex,
143                                     RTEMS_WAIT, RTEMS_NO_TIMEOUT);
144        if (sc != RTEMS_SUCCESSFUL)
145                return sc;
146        for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {
147                if ((tty->major == major) && (tty->minor == minor))
148                        break;
149        }
150        if (tty == NULL) {
151                static char c = 'a';
152
153                /*
154                 * Create a new device
155                 */
156                tty = calloc (1, sizeof (struct rtems_termios_tty));
157                if (tty == NULL) {
158                        rtems_semaphore_release (rtems_termios_ttyMutex);
159                        return RTEMS_NO_MEMORY;
160                }
161                /*
162                 * allocate raw input buffer
163                 */
164                tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
165                tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
166                if (tty->rawInBuf.theBuf == NULL) {
167                        free(tty);
168                        rtems_semaphore_release (rtems_termios_ttyMutex);
169                        return RTEMS_NO_MEMORY;
170                }
171                /*
172                 * allocate raw output buffer
173                 */
174                tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
175                tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
176                if (tty->rawInBuf.theBuf == NULL) {
177                        free((void *)(tty->rawInBuf.theBuf));
178                        free(tty);
179                        rtems_semaphore_release (rtems_termios_ttyMutex);
180                        return RTEMS_NO_MEMORY;
181                }
182                /*
183                 * allocate cooked buffer
184                 */
185                tty->cbuf  = malloc (CBUFSIZE);
186                if (tty->cbuf == NULL) {
187                        free((void *)(tty->rawOutBuf.theBuf));
188                        free((void *)(tty->rawInBuf.theBuf));
189                        free(tty);
190                        rtems_semaphore_release (rtems_termios_ttyMutex);
191                        return RTEMS_NO_MEMORY;
192                }
193                /*
194                 * link tty
195                 */
196                if (rtems_termios_ttyHead)
197                        rtems_termios_ttyHead->back = tty;
198                tty->forw = rtems_termios_ttyHead;
199                rtems_termios_ttyHead = tty;
200                if (rtems_termios_ttyTail == NULL)
201                        rtems_termios_ttyTail = tty;
202                tty->minor = minor;
203                tty->major = major;
204
205                /*
206                 * Set up mutex semaphores
207                 */
208                sc = rtems_semaphore_create (
209                        rtems_build_name ('T', 'R', 'i', c),
210                        1,
211                        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
212                        RTEMS_NO_PRIORITY,
213                        &tty->isem);
214                if (sc != RTEMS_SUCCESSFUL)
215                        rtems_fatal_error_occurred (sc);
216                sc = rtems_semaphore_create (
217                        rtems_build_name ('T', 'R', 'o', c),
218                        1,
219                        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
220                        RTEMS_NO_PRIORITY,
221                        &tty->osem);
222                if (sc != RTEMS_SUCCESSFUL)
223                        rtems_fatal_error_occurred (sc);
224                sc = rtems_semaphore_create (
225                        rtems_build_name ('T', 'R', 'x', c),
226                        0,
227                        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
228                        RTEMS_NO_PRIORITY,
229                        &tty->rawOutBuf.Semaphore);
230                if (sc != RTEMS_SUCCESSFUL)
231                        rtems_fatal_error_occurred (sc);
232                tty->rawOutBufState = rob_idle;
233
234                /*
235                 * Set callbacks
236                 */
237                tty->device = *callbacks;
238
239                /*
240                 * Create I/O tasks
241                 */
242                if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
243                        sc = rtems_task_create (
244                                   rtems_build_name ('T', 'x', 'T', c),
245                                   TERMIOS_TXTASK_PRIO,
246                                   TERMIOS_TXTASK_STACKSIZE,
247                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
248                                   RTEMS_NO_ASR,
249                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
250                                   &tty->txTaskId);
251                        if (sc != RTEMS_SUCCESSFUL)
252                                rtems_fatal_error_occurred (sc);
253                        sc = rtems_task_create (
254                                   rtems_build_name ('R', 'x', 'T', c),
255                                   TERMIOS_RXTASK_PRIO,
256                                   TERMIOS_RXTASK_STACKSIZE,
257                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
258                                   RTEMS_NO_ASR,
259                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
260                                   &tty->rxTaskId);
261                        if (sc != RTEMS_SUCCESSFUL)
262                                rtems_fatal_error_occurred (sc);
263                               
264                }
265                if ((tty->device.pollRead == NULL) ||
266                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){
267                        sc = rtems_semaphore_create (
268                                rtems_build_name ('T', 'R', 'r', c),
269                                0,
270                                RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
271                                RTEMS_NO_PRIORITY,
272                                &tty->rawInBuf.Semaphore);
273                        if (sc != RTEMS_SUCCESSFUL)
274                                rtems_fatal_error_occurred (sc);
275                }
276
277                /*
278                 * Set default parameters
279                 */
280                tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;
281                tty->termios.c_oflag = OPOST | ONLCR | XTABS;
282                tty->termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
283                tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
284
285                tty->termios.c_cc[VINTR] = '\003';
286                tty->termios.c_cc[VQUIT] = '\034';
287                tty->termios.c_cc[VERASE] = '\177';
288                tty->termios.c_cc[VKILL] = '\025';
289                tty->termios.c_cc[VEOF] = '\004';
290                tty->termios.c_cc[VEOL] = '\000';
291                tty->termios.c_cc[VEOL2] = '\000';
292                tty->termios.c_cc[VSTART] = '\021';
293                tty->termios.c_cc[VSTOP] = '\023';
294                tty->termios.c_cc[VSUSP] = '\032';
295                tty->termios.c_cc[VREPRINT] = '\022';
296                tty->termios.c_cc[VDISCARD] = '\017';
297                tty->termios.c_cc[VWERASE] = '\027';
298                tty->termios.c_cc[VLNEXT] = '\026';
299
300                /* start with no flow control, clear flow control flags */
301                tty->flow_ctrl = 0;
302                /*
303                 * set low/highwater mark for XON/XOFF support
304                 */
305                tty->lowwater  = tty->rawInBuf.Size * 1/2;
306                tty->highwater = tty->rawInBuf.Size * 3/4;
307                /*
308                 * Bump name characer
309                 */
310                if (c++ == 'z')
311                        c = 'a';
312
313        }
314        args->iop->data1 = tty;
315        if (!tty->refcount++) {
316          if (tty->device.firstOpen)
317                (*tty->device.firstOpen)(major, minor, arg);
318          /*
319           * start I/O tasks, if needed
320           */
321          if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
322            sc = rtems_task_start(tty->rxTaskId,
323                                  rtems_termios_rxdaemon,
324                                  (rtems_task_argument)tty);
325            if (sc != RTEMS_SUCCESSFUL)
326              rtems_fatal_error_occurred (sc);
327           
328            sc = rtems_task_start(tty->txTaskId,
329                                  rtems_termios_txdaemon,
330                                  (rtems_task_argument)tty);
331            if (sc != RTEMS_SUCCESSFUL)
332              rtems_fatal_error_occurred (sc);
333          }
334        }
335        rtems_semaphore_release (rtems_termios_ttyMutex);
336        return RTEMS_SUCCESSFUL;
337}
338
339/*
340 * Drain output queue
341 */
342static void
343drainOutput (struct rtems_termios_tty *tty)
344{
345        rtems_interrupt_level level;
346        rtems_status_code sc;
347
348        if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) {
349                rtems_interrupt_disable (level);
350                while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
351                        tty->rawOutBufState = rob_wait;
352                        rtems_interrupt_enable (level);
353                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
354                                                        RTEMS_WAIT,
355                                                        RTEMS_NO_TIMEOUT);
356                        if (sc != RTEMS_SUCCESSFUL)
357                                rtems_fatal_error_occurred (sc);
358                        rtems_interrupt_disable (level);
359                }
360                rtems_interrupt_enable (level);
361        }
362}
363
364rtems_status_code
365rtems_termios_close (void *arg)
366{
367        rtems_libio_open_close_args_t *args = arg;
368        struct rtems_termios_tty *tty = args->iop->data1;
369        rtems_status_code sc;
370
371        sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
372        if (sc != RTEMS_SUCCESSFUL)
373                rtems_fatal_error_occurred (sc);
374        if (--tty->refcount == 0) {
375                if (linesw[tty->t_line].l_close != NULL) {
376                        /*
377                         * call discipline-specific close
378                         */
379                        sc = linesw[tty->t_line].l_close(tty);
380                }
381                else {
382                        /*
383                         * default: just flush output buffer
384                         */
385                        drainOutput (tty);
386                }
387         
388                if (tty->device.outputUsesInterrupts
389                    == TERMIOS_TASK_DRIVEN) {
390                        /*
391                         * send "terminate" to I/O tasks
392                         */
393                        sc = rtems_event_send(
394                                  tty->rxTaskId,
395                                  TERMIOS_RX_TERMINATE_EVENT);
396                        if (sc != RTEMS_SUCCESSFUL)
397                                rtems_fatal_error_occurred (sc);
398                        sc = rtems_event_send(
399                                  tty->txTaskId,
400                                  TERMIOS_TX_TERMINATE_EVENT);
401                        if (sc != RTEMS_SUCCESSFUL)
402                                rtems_fatal_error_occurred (sc);
403                }
404                if (tty->device.lastClose)
405                         (*tty->device.lastClose)(tty->major, tty->minor, arg);
406                if (tty->forw == NULL)
407                        rtems_termios_ttyTail = tty->back;
408                else
409                        tty->forw->back = tty->back;
410                if (tty->back == NULL)
411                        rtems_termios_ttyHead = tty->forw;
412                else
413                        tty->back->forw = tty->forw;
414                rtems_semaphore_delete (tty->isem);
415                rtems_semaphore_delete (tty->osem);
416                rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
417                if ((tty->device.pollRead == NULL) ||
418                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN))
419                        rtems_semaphore_delete (tty->rawInBuf.Semaphore);
420                free (tty);
421        }
422        rtems_semaphore_release (rtems_termios_ttyMutex);
423        return RTEMS_SUCCESSFUL;
424}
425
426static void
427termios_set_flowctrl(struct rtems_termios_tty *tty)
428{
429  rtems_interrupt_level level;
430  /*
431   * check for flow control options to be switched off
432   */
433
434  /* check for outgoing XON/XOFF flow control switched off */
435  if (( tty->flow_ctrl & FL_MDXON) &&
436      !(tty->termios.c_iflag & IXON)) {
437    /* clear related flags in flow_ctrl */
438    tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);
439
440    /* has output been stopped due to received XOFF? */
441    if (tty->flow_ctrl & FL_OSTOP) {
442      /* disable interrupts    */
443      rtems_interrupt_disable(level);
444      tty->flow_ctrl &= ~FL_OSTOP;
445      /* check for chars in output buffer (or rob_state?) */
446      if (tty->rawOutBufState != rob_idle) {
447        /* if chars available, call write function... */
448        (*tty->device.write)(tty->minor,
449                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
450      }
451      /* reenable interrupts */
452      rtems_interrupt_enable(level);
453    }
454  }
455  /* check for incoming XON/XOFF flow control switched off */
456  if (( tty->flow_ctrl & FL_MDXOF) &&
457      !(tty->termios.c_iflag & IXOFF)) {
458    /* clear related flags in flow_ctrl */
459    tty->flow_ctrl &= ~(FL_MDXOF);
460    /* FIXME: what happens, if we had sent XOFF but not yet XON? */
461    tty->flow_ctrl &= ~(FL_ISNTXOF);
462  }
463
464  /* check for incoming RTS/CTS flow control switched off */
465  if (( tty->flow_ctrl & FL_MDRTS) &&
466      !(tty->termios.c_cflag & CRTSCTS)) {
467    /* clear related flags in flow_ctrl */
468    tty->flow_ctrl &= ~(FL_MDRTS);
469   
470    /* restart remote Tx, if it was stopped */
471    if ((tty->flow_ctrl & FL_IRTSOFF) &&
472        (tty->device.startRemoteTx != NULL)) {
473      tty->device.startRemoteTx(tty->minor);
474    }
475    tty->flow_ctrl &= ~(FL_IRTSOFF);
476  }   
477 
478  /*
479   * check for flow control options to be switched on 
480   */
481  /* check for incoming RTS/CTS flow control switched on */
482  if (tty->termios.c_cflag & CRTSCTS) {
483    tty->flow_ctrl |= FL_MDRTS;
484  }
485  /* check for incoming XON/XOF flow control switched on */
486  if (tty->termios.c_iflag & IXOFF) {
487    tty->flow_ctrl |= FL_MDXOF;
488  }
489  /* check for outgoing XON/XOF flow control switched on */
490  if (tty->termios.c_iflag & IXON) {
491    tty->flow_ctrl |= FL_MDXON;
492  }
493}
494
495rtems_status_code
496rtems_termios_ioctl (void *arg)
497{
498        rtems_libio_ioctl_args_t *args = arg;
499        struct rtems_termios_tty *tty = args->iop->data1;
500        rtems_status_code sc;
501
502        args->ioctl_return = 0;
503        sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
504        if (sc != RTEMS_SUCCESSFUL) {
505                args->ioctl_return = sc;
506                return sc;
507        }
508        switch (args->command) {
509        default:
510                if (linesw[tty->t_line].l_ioctl != NULL) {
511                        sc = linesw[tty->t_line].l_ioctl(tty,args);
512                }
513                else {
514                        sc = RTEMS_INVALID_NUMBER;
515                }
516                break;
517
518        case RTEMS_IO_GET_ATTRIBUTES:
519                *(struct termios *)args->buffer = tty->termios;
520                break;
521
522        case RTEMS_IO_SET_ATTRIBUTES:
523                tty->termios = *(struct termios *)args->buffer;
524
525                /* check for and process change in flow control options */
526                termios_set_flowctrl(tty);
527
528                if (tty->termios.c_lflag & ICANON) {
529                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
530                        tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
531                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
532                }
533                else {
534                        rtems_interval ticksPerSecond;
535                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
536                        tty->vtimeTicks = tty->termios.c_cc[VTIME] * ticksPerSecond / 10;
537                        if (tty->termios.c_cc[VTIME]) {
538                                tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
539                                tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
540                                if (tty->termios.c_cc[VMIN])
541                                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
542                                else
543                                        tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
544                        }
545                        else {
546                                if (tty->termios.c_cc[VMIN]) {
547                                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
548                                        tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
549                                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
550                                }
551                                else {
552                                        tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
553                                }
554                        }
555                }
556                if (tty->device.setAttributes)
557                        (*tty->device.setAttributes)(tty->minor, &tty->termios);
558                break;
559
560        case RTEMS_IO_TCDRAIN:
561                drainOutput (tty);
562                break;
563
564                /*
565                 * FIXME: add various ioctl code handlers
566                 */
567
568#if 1 /* FIXME */
569        case TIOCSETD:
570                /*
571                 * close old line discipline
572                 */
573                if (linesw[tty->t_line].l_close != NULL) {
574                        sc = linesw[tty->t_line].l_close(tty);
575                }
576                tty->t_line=*(int*)(args->buffer);
577                tty->t_sc = NULL; /* ensure that no more valid data */
578                /*
579                 * open new line discipline
580                 */
581                if (linesw[tty->t_line].l_open != NULL) {
582                        sc = linesw[tty->t_line].l_open(tty);
583                }
584                break;
585        case TIOCGETD: 
586                *(int*)(args->buffer)=tty->t_line;
587                break;         
588#endif
589        case FIONREAD:
590                /* Half guess that this is the right operation */
591                *(int *)args->buffer = tty->ccount - tty->cindex;
592                break;
593        }
594        rtems_semaphore_release (tty->osem);
595        args->ioctl_return = sc;
596        return sc;
597}
598
599/*
600 * Send characters to device-specific code
601 */
602void
603rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty)
604{
605        unsigned int newHead;
606        rtems_interrupt_level level;
607        rtems_status_code sc;
608
609        if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) {
610                (*tty->device.write)(tty->minor, buf, len);
611                return;
612        }
613        newHead = tty->rawOutBuf.Head;
614        while (len) {
615                /*
616                 * Performance improvement could be made here.
617                 * Copy multiple bytes to raw buffer:
618                 * if (len > 1) && (space to buffer end, or tail > 1)
619                 *      ncopy = MIN (len, space to buffer end or tail)
620                 *      memcpy (raw buffer, buf, ncopy)
621                 *      buf += ncopy
622                 *      len -= ncopy
623                 *
624                 * To minimize latency, the memcpy should be done
625                 * with interrupts enabled.
626                 */
627                newHead = (newHead + 1) % tty->rawOutBuf.Size;
628                rtems_interrupt_disable (level);
629                while (newHead == tty->rawOutBuf.Tail) {
630                        tty->rawOutBufState = rob_wait;
631                        rtems_interrupt_enable (level);
632                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
633                                                        RTEMS_WAIT,
634                                                        RTEMS_NO_TIMEOUT);
635                        if (sc != RTEMS_SUCCESSFUL)
636                                rtems_fatal_error_occurred (sc);
637                        rtems_interrupt_disable (level);
638                }
639                tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++;
640                tty->rawOutBuf.Head = newHead;
641                if (tty->rawOutBufState == rob_idle) {
642                  /* check, whether XOFF has been received */
643                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
644                    (*tty->device.write)(tty->minor,
645                        (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
646                  }
647                  else {
648                    /* remember that output has been stopped due to flow ctrl*/
649                    tty->flow_ctrl |= FL_OSTOP;
650                  }
651                  tty->rawOutBufState = rob_busy;
652                }
653                rtems_interrupt_enable (level);
654                len--;
655        }
656}
657
658/*
659 * Handle output processing
660 */
661static void
662oproc (unsigned char c, struct rtems_termios_tty *tty)
663{
664        int     i;
665
666        if (tty->termios.c_oflag & OPOST) {
667                switch (c) {
668                case '\n':
669                        if (tty->termios.c_oflag & ONLRET)
670                                tty->column = 0;
671                        if (tty->termios.c_oflag & ONLCR) {
672                                rtems_termios_puts ("\r", 1, tty);
673                                tty->column = 0;
674                        }
675                        break;
676
677                case '\r':
678                        if ((tty->termios.c_oflag & ONOCR) && (tty->column == 0))
679                                return;
680                        if (tty->termios.c_oflag & OCRNL) {
681                                c = '\n';
682                                if (tty->termios.c_oflag & ONLRET)
683                                        tty->column = 0;
684                                break;
685                        }
686                        tty->column = 0;
687                        break;
688
689                case '\t':
690                        i = 8 - (tty->column & 7);
691                        if ((tty->termios.c_oflag & TABDLY) == XTABS) {
692                                tty->column += i;
693                                rtems_termios_puts ( "        ",  i, tty);
694                                return;
695                        }
696                        tty->column += i;
697                        break;
698
699                case '\b':
700                        if (tty->column > 0)
701                                tty->column--;
702                        break;
703
704                default:
705                        if (tty->termios.c_oflag & OLCUC)
706                                c = toupper(c);
707                        if (!iscntrl(c))
708                                tty->column++;
709                        break;
710                }
711        }
712        rtems_termios_puts (&c, 1, tty);
713}
714
715rtems_status_code
716rtems_termios_write (void *arg)
717{
718        rtems_libio_rw_args_t *args = arg;
719        struct rtems_termios_tty *tty = args->iop->data1;
720        rtems_status_code sc;
721
722        sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
723        if (sc != RTEMS_SUCCESSFUL)
724                return sc;
725        if (linesw[tty->t_line].l_write != NULL) {
726                sc = linesw[tty->t_line].l_write(tty,args);
727                rtems_semaphore_release (tty->osem);
728                return sc;
729        }
730        if (tty->termios.c_oflag & OPOST) {
731                unsigned32 count = args->count;
732                unsigned8 *buffer = args->buffer;
733                while (count--)
734                        oproc (*buffer++, tty);
735                args->bytes_moved = args->count;
736        }
737        else {
738                rtems_termios_puts (args->buffer, args->count, tty);
739                args->bytes_moved = args->count;
740        }
741        rtems_semaphore_release (tty->osem);
742        return sc;
743}
744
745/*
746 * Echo a typed character
747 */
748static void
749echo (unsigned char c, struct rtems_termios_tty *tty)
750{
751        if ((tty->termios.c_lflag & ECHOCTL) && iscntrl(c) && (c != '\t') && (c != '\n')) {
752                char echobuf[2];
753
754                echobuf[0] = '^';
755                echobuf[1] = c ^ 0x40;
756                rtems_termios_puts (echobuf, 2, tty);
757                tty->column += 2;
758        }
759        else {
760                oproc (c, tty);
761        }
762}
763
764/*
765 * Erase a character or line
766 * FIXME: Needs support for WERASE and ECHOPRT.
767 * FIXME: Some of the tests should check for IEXTEN, too.
768 */
769static void
770erase (struct rtems_termios_tty *tty, int lineFlag)
771{
772        if (tty->ccount == 0)
773                return;
774        if (lineFlag) {
775                if (!(tty->termios.c_lflag & ECHO)) {
776                        tty->ccount = 0;
777                        return;
778                }
779                if (!(tty->termios.c_lflag & ECHOE)) {
780                        tty->ccount = 0;
781                        echo (tty->termios.c_cc[VKILL], tty);
782                        if (tty->termios.c_lflag & ECHOK)
783                                echo ('\n', tty);
784                        return;
785                }
786        }
787        while (tty->ccount) {
788                unsigned char c = tty->cbuf[--tty->ccount];
789
790                if (tty->termios.c_lflag & ECHO) {
791                        if (!lineFlag && !(tty->termios.c_lflag & ECHOE)) {
792                                echo (tty->termios.c_cc[VERASE], tty);
793                        }
794                        else if (c == '\t') {
795                                int col = tty->read_start_column;
796                                int i = 0;
797
798                                /*
799                                 * Find the character before the tab
800                                 */
801                                while (i != tty->ccount) {
802                                        c = tty->cbuf[i++];
803                                        if (c == '\t') {
804                                                col = (col | 7) + 1;
805                                        }
806                                        else if (iscntrl (c)) {
807                                                if (tty->termios.c_lflag & ECHOCTL)
808                                                        col += 2;
809                                        }
810                                        else {
811                                                col++;
812                                        }
813                                }
814
815                                /*
816                                 * Back up over the tab
817                                 */
818                                while (tty->column > col) {
819                                        rtems_termios_puts ("\b", 1, tty);
820                                        tty->column--;
821                                }
822                        }
823                        else {
824                                if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
825                                        rtems_termios_puts ("\b \b", 3, tty);
826                                        if (tty->column)
827                                                tty->column--;
828                                }
829                                if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
830                                        rtems_termios_puts ("\b \b", 3, tty);
831                                        if (tty->column)
832                                                tty->column--;
833                                }
834                        }
835                }
836                if (!lineFlag)
837                        break;
838        }
839}
840
841/*
842 * Process a single input character
843 */
844static int
845iproc (unsigned char c, struct rtems_termios_tty *tty)
846{
847        if (tty->termios.c_iflag & ISTRIP)
848                c &= 0x7f;
849        if (tty->termios.c_iflag & IUCLC)
850                c = tolower (c);
851        if (c == '\r') {
852                if (tty->termios.c_iflag & IGNCR)
853                        return 0;
854                if (tty->termios.c_iflag & ICRNL)
855                        c = '\n';
856        }
857        else if ((c == '\n') && (tty->termios.c_iflag & INLCR)) {
858                c = '\r';
859        }
860        if ((c != '\0') && (tty->termios.c_lflag & ICANON)) {
861                if (c == tty->termios.c_cc[VERASE]) {
862                        erase (tty, 0);
863                        return 0;
864                }
865                else if (c == tty->termios.c_cc[VKILL]) {
866                        erase (tty, 1);
867                        return 0;
868                }
869                else if (c == tty->termios.c_cc[VEOF]) {
870                        return 1;
871                }
872                else if (c == '\n') {
873                        if (tty->termios.c_lflag & (ECHO | ECHONL))
874                                echo (c, tty);
875                        tty->cbuf[tty->ccount++] = c;
876                        return 1;
877                }
878                else if ((c == tty->termios.c_cc[VEOL])
879                      || (c == tty->termios.c_cc[VEOL2])) {
880                        if (tty->termios.c_lflag & ECHO)
881                                echo (c, tty);
882                        tty->cbuf[tty->ccount++] = c;
883                        return 1;
884                }
885        }
886
887        /*
888         * FIXME: Should do IMAXBEL handling somehow
889         */
890        if (tty->ccount < (CBUFSIZE-1)) {
891                if (tty->termios.c_lflag & ECHO)
892                        echo (c, tty);
893                tty->cbuf[tty->ccount++] = c;
894        }
895        return 0;
896}
897
898/*
899 * Process input character, with semaphore.
900 */
901static int
902siproc (unsigned char c, struct rtems_termios_tty *tty)
903{
904        int i;
905
906        /*
907         * Obtain output semaphore if character will be echoed
908         */
909        if (tty->termios.c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ECHOPRT|ECHOCTL|ECHOKE)) {
910                rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
911                i = iproc (c, tty);
912                rtems_semaphore_release (tty->osem);
913        }
914        else {
915                i = iproc (c, tty);
916        }
917        return i;
918}
919
920/*
921 * Fill the input buffer by polling the device
922 */
923static rtems_status_code
924fillBufferPoll (struct rtems_termios_tty *tty)
925{
926        int n;
927
928        if (tty->termios.c_lflag & ICANON) {
929                for (;;) {
930                        n = (*tty->device.pollRead)(tty->minor);
931                        if (n < 0) {
932                                rtems_task_wake_after (1);
933                        }
934                        else {
935                                if  (siproc (n, tty))
936                                        break;
937                        }
938                }
939        }
940        else {
941                rtems_interval then, now;
942                if (!tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
943                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
944                for (;;) {
945                        n = (*tty->device.pollRead)(tty->minor);
946                        if (n < 0) {
947                                if (tty->termios.c_cc[VMIN]) {
948                                        if (tty->termios.c_cc[VTIME] && tty->ccount) {
949                                                rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
950                                                if ((now - then) > tty->vtimeTicks) {
951                                                        break;
952                                                }
953                                        }
954                                }
955                                else {
956                                        if (!tty->termios.c_cc[VTIME])
957                                                break;
958                                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
959                                        if ((now - then) > tty->vtimeTicks) {
960                                                break;
961                                        }
962                                }
963                                rtems_task_wake_after (1);
964                        }
965                        else {
966                                siproc (n, tty);
967                                if (tty->ccount >= tty->termios.c_cc[VMIN])
968                                        break;
969                                if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
970                                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
971                        }
972                }
973        }
974        return RTEMS_SUCCESSFUL;
975}
976
977/*
978 * Fill the input buffer from the raw input queue
979 */
980static rtems_status_code
981fillBufferQueue (struct rtems_termios_tty *tty)
982{
983        rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
984        rtems_status_code sc;
985        int               wait = (int)1;
986
987        while ( wait ) {
988                /*
989                 * Process characters read from raw queue
990                 */
991                while (tty->rawInBuf.Head != tty->rawInBuf.Tail) {
992                        unsigned char c;
993                        unsigned int newHead;
994
995                        newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
996                        c = tty->rawInBuf.theBuf[newHead];
997                        tty->rawInBuf.Head = newHead;
998                        if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
999                            % tty->rawInBuf.Size)
1000                           < tty->lowwater) {
1001                          tty->flow_ctrl &= ~FL_IREQXOF;
1002                          /* if tx stopped and XON should be sent... */
1003                          if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
1004                               ==                (FL_MDXON | FL_ISNTXOF))
1005                              && ((tty->rawOutBufState == rob_idle)
1006                                  || (tty->flow_ctrl & FL_OSTOP))) {
1007                            /* XON should be sent now... */
1008                            (*tty->device.write)(tty->minor,
1009                                                 &(tty->termios.c_cc[VSTART]),
1010                                                 1);
1011                          }
1012                          else if (tty->flow_ctrl & FL_MDRTS) {             
1013                            tty->flow_ctrl &= ~FL_IRTSOFF;             
1014                            /* activate RTS line */
1015                            if (tty->device.startRemoteTx != NULL) {
1016                              tty->device.startRemoteTx(tty->minor);
1017                            }
1018                          }
1019                        }
1020
1021                        /* continue processing new character */
1022                        if (tty->termios.c_lflag & ICANON) {
1023                                if  (siproc (c, tty))
1024                                        wait = 0;
1025                        }
1026                        else {
1027                                siproc (c, tty);
1028                                if (tty->ccount >= tty->termios.c_cc[VMIN])
1029                                        wait = 0;
1030                        }
1031                        timeout = tty->rawInBufSemaphoreTimeout;
1032                }
1033
1034                /*
1035                 * Wait for characters
1036                 */
1037                if ( wait ) {
1038                        sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore,
1039                                tty->rawInBufSemaphoreOptions,
1040                                timeout);
1041                        if (sc != RTEMS_SUCCESSFUL)
1042                                break;
1043                }
1044        }
1045        return RTEMS_SUCCESSFUL;
1046}
1047
1048rtems_status_code
1049rtems_termios_read (void *arg)
1050{
1051        rtems_libio_rw_args_t *args = arg;
1052        struct rtems_termios_tty *tty = args->iop->data1;
1053        unsigned32 count = args->count;
1054        unsigned8 *buffer = args->buffer;
1055        rtems_status_code sc;
1056
1057        sc = rtems_semaphore_obtain (tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1058        if (sc != RTEMS_SUCCESSFUL)
1059                return sc;
1060        if (linesw[tty->t_line].l_read != NULL) {
1061                sc = linesw[tty->t_line].l_read(tty,args);
1062                rtems_semaphore_release (tty->isem);
1063                return sc;
1064        }
1065        if (tty->cindex == tty->ccount) {
1066                tty->cindex = tty->ccount = 0;
1067                tty->read_start_column = tty->column;
1068                if (tty->device.pollRead != NULL
1069                    && tty->device.outputUsesInterrupts == TERMIOS_POLLED)
1070                        sc = fillBufferPoll (tty);
1071                else
1072                        sc = fillBufferQueue (tty);
1073                if (sc != RTEMS_SUCCESSFUL)
1074                        tty->cindex = tty->ccount = 0;
1075        }
1076        while (count && (tty->cindex < tty->ccount)) {
1077                *buffer++ = tty->cbuf[tty->cindex++];
1078                count--;
1079        }
1080        args->bytes_moved = args->count - count;
1081        rtems_semaphore_release (tty->isem);
1082        return sc;
1083}
1084
1085/*
1086 * signal receive interrupt to rx daemon
1087 * NOTE: This routine runs in the context of the
1088 *       device receive interrupt handler.
1089 */
1090void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
1091{
1092        /*
1093         * send event to rx daemon task
1094         */
1095        rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
1096}
1097
1098/*
1099 * Place characters on raw queue.
1100 * NOTE: This routine runs in the context of the
1101 *       device receive interrupt handler.
1102 * Returns the number of characters dropped because of overflow.
1103 */
1104int
1105rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
1106{
1107        struct rtems_termios_tty *tty = ttyp;
1108        unsigned int newTail;
1109        char c;
1110        int dropped = 0;
1111        boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
1112        rtems_interrupt_level level;
1113
1114        if (linesw[tty->t_line].l_rint != NULL) {
1115          while (len--) {
1116            c = *buf++;
1117            linesw[tty->t_line].l_rint(c,tty);
1118          }
1119          return 0;
1120        }
1121
1122        while (len--) {
1123          c = *buf++;
1124          /* FIXME: implement IXANY: any character restarts output */
1125          /* if incoming XON/XOFF controls outgoing stream: */
1126          if (tty->flow_ctrl & FL_MDXON) {         
1127            /* if received char is V_STOP and V_START (both are equal value) */
1128            if (c == tty->termios.c_cc[VSTOP]) {
1129              if (c == tty->termios.c_cc[VSTART]) {
1130                /* received VSTOP and VSTART==VSTOP? */
1131                /* then toggle "stop output" status  */
1132                tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
1133              }
1134              else {
1135                /* VSTOP received (other code than VSTART) */
1136                /* stop output                             */
1137                tty->flow_ctrl |= FL_ORCVXOF;
1138              }
1139              flow_rcv = TRUE;
1140            }
1141            else if (c == tty->termios.c_cc[VSTART]) {
1142              /* VSTART received */
1143              /* restart output  */
1144              tty->flow_ctrl &= ~FL_ORCVXOF;
1145              flow_rcv = TRUE;
1146            }
1147          }
1148          if (flow_rcv) {
1149            /* restart output according to FL_ORCVXOF flag */
1150            if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
1151              /* disable interrupts    */
1152              rtems_interrupt_disable(level);
1153              tty->flow_ctrl &= ~FL_OSTOP;
1154              /* check for chars in output buffer (or rob_state?) */
1155              if (tty->rawOutBufState != rob_idle) {
1156              /* if chars available, call write function... */
1157                (*tty->device.write)(tty->minor,
1158                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
1159              }
1160              /* reenable interrupts */
1161              rtems_interrupt_enable(level);
1162            }
1163          }     
1164          else {
1165                newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
1166                /* if chars_in_buffer > highwater                */
1167                rtems_interrupt_disable(level);
1168                if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
1169                      % tty->rawInBuf.Size)
1170                     > tty->highwater) &&
1171                    !(tty->flow_ctrl & FL_IREQXOF)) {
1172                  /* incoming data stream should be stopped */
1173                  tty->flow_ctrl |= FL_IREQXOF;
1174                  if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
1175                      ==                (FL_MDXOF             ) ){
1176                    if ((tty->flow_ctrl & FL_OSTOP) ||
1177                        (tty->rawOutBufState == rob_idle)) {
1178                      /* if tx is stopped due to XOFF or out of data */
1179                      /*    call write function here                 */
1180                      tty->flow_ctrl |= FL_ISNTXOF;
1181                      (*tty->device.write)(tty->minor,
1182                                           &(tty->termios.c_cc[VSTOP]),
1183                                           1);
1184                    }
1185                  }
1186                  else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF))
1187                           ==                (FL_MDRTS             ) ) {
1188                    tty->flow_ctrl |= FL_IRTSOFF;               
1189                    /* deactivate RTS line */
1190                    if (tty->device.stopRemoteTx != NULL) {
1191                      tty->device.stopRemoteTx(tty->minor);
1192                    }
1193                  }
1194                }
1195                /* reenable interrupts */
1196                rtems_interrupt_enable(level);
1197
1198                if (newTail == tty->rawInBuf.Head) {
1199                        dropped++;
1200                }
1201                else {
1202                        tty->rawInBuf.theBuf[newTail] = c;
1203                        tty->rawInBuf.Tail = newTail;
1204                }               
1205          }
1206        }
1207        tty->rawInBufDropped += dropped;
1208        rtems_semaphore_release (tty->rawInBuf.Semaphore);
1209        return dropped;
1210}
1211
1212/*
1213 * in task-driven mode, this function is called in Tx task context
1214 * in interrupt-driven mode, this function is called in TxIRQ context
1215 */
1216int
1217rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
1218{
1219        unsigned int newTail;
1220        int nToSend;
1221        rtems_interrupt_level level;
1222        int len;
1223
1224        /* check for XOF/XON to send */
1225        if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
1226            == (FL_MDXOF | FL_IREQXOF)) {
1227          /* XOFF should be sent now... */
1228          (*tty->device.write)(tty->minor,
1229                               &(tty->termios.c_cc[VSTOP]), 1);
1230
1231          rtems_interrupt_disable(level);
1232          tty->t_dqlen--;
1233          tty->flow_ctrl |= FL_ISNTXOF;
1234          rtems_interrupt_enable(level);
1235
1236          nToSend = 1;
1237        }
1238        else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
1239                 == FL_ISNTXOF) {
1240          /* NOTE: send XON even, if no longer in XON/XOFF mode... */
1241          /* XON should be sent now... */
1242                /*
1243                 * FIXME: this .write call will generate another
1244                 * dequeue callback. This will advance the "Tail" in the data
1245                 * buffer, although the corresponding data is not yet out!
1246                 * Therefore the dequeue "length" should be reduced by 1
1247                 */
1248          (*tty->device.write)(tty->minor,
1249                               &(tty->termios.c_cc[VSTART]), 1);
1250
1251          rtems_interrupt_disable(level);
1252          tty->t_dqlen--;
1253          tty->flow_ctrl &= ~FL_ISNTXOF;
1254          rtems_interrupt_enable(level);
1255
1256          nToSend = 1;
1257        }
1258        else {
1259          if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
1260            /*
1261             * buffer was empty
1262             */
1263            if (tty->rawOutBufState == rob_wait) {
1264              /*
1265               * this should never happen...
1266               */
1267              rtems_semaphore_release (tty->rawOutBuf.Semaphore);
1268            }
1269            return 0;   
1270          }
1271
1272          rtems_interrupt_disable(level);
1273          len = tty->t_dqlen;
1274          tty->t_dqlen = 0;
1275          rtems_interrupt_enable(level);
1276
1277          newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
1278          tty->rawOutBuf.Tail = newTail;
1279          if (tty->rawOutBufState == rob_wait) {
1280            /*
1281             * wake up any pending writer task
1282             */
1283            rtems_semaphore_release (tty->rawOutBuf.Semaphore);
1284          }
1285          if (newTail == tty->rawOutBuf.Head) {
1286            /*
1287             * Buffer has become empty
1288             */
1289            tty->rawOutBufState = rob_idle;
1290            nToSend = 0;
1291          }
1292          /* check, whether output should stop due to received XOFF */
1293          else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
1294                   ==                (FL_MDXON | FL_ORCVXOF)) {
1295                  /* Buffer not empty, but output stops due to XOFF */
1296                  /* set flag, that output has been stopped */
1297                  rtems_interrupt_disable(level);
1298                  tty->flow_ctrl |= FL_OSTOP;
1299                  tty->rawOutBufState = rob_busy; /*apm*/
1300                  rtems_interrupt_enable(level);
1301                  nToSend = 0;
1302          }
1303          else {
1304            /*
1305             * Buffer not empty, start tranmitter
1306             */
1307            if (newTail > tty->rawOutBuf.Head)
1308                    nToSend = tty->rawOutBuf.Size - newTail;
1309            else
1310                    nToSend = tty->rawOutBuf.Head - newTail;
1311            /* when flow control XON or XOF, don't send blocks of data     */
1312            /* to allow fast reaction on incoming flow ctrl and low latency*/
1313            /* for outgoing flow control                                   */
1314            if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
1315                    nToSend = 1;
1316            }
1317            tty->rawOutBufState = rob_busy; /*apm*/
1318            (*tty->device.write)(tty->minor,
1319                                 (char *)&tty->rawOutBuf.theBuf[newTail],
1320                                 nToSend);
1321          }
1322          tty->rawOutBuf.Tail = newTail; /*apm*/
1323        }
1324        return nToSend;
1325}
1326
1327/*
1328 * Characters have been transmitted
1329 * NOTE: This routine runs in the context of the
1330 *       device transmit interrupt handler.
1331 * The second argument is the number of characters transmitted so far.
1332 * This value will always be 1 for devices which generate an interrupt
1333 * for each transmitted character.
1334 * It returns number of characters left to transmit
1335 */
1336int
1337rtems_termios_dequeue_characters (void *ttyp, int len)
1338{
1339        struct rtems_termios_tty *tty = ttyp;
1340        rtems_status_code sc;
1341
1342        /*
1343         * sum up character count already sent
1344         */
1345        tty->t_dqlen += len;
1346
1347        if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
1348                /*
1349                 * send wake up to transmitter task
1350                 */
1351                sc = rtems_event_send(tty->txTaskId,
1352                                      TERMIOS_TX_START_EVENT);
1353                if (sc != RTEMS_SUCCESSFUL)
1354                        rtems_fatal_error_occurred (sc);
1355                return 0; /* nothing to output in IRQ... */
1356        }
1357        else {
1358                return rtems_termios_refill_transmitter(tty);
1359        }
1360}
1361
1362/*
1363 * this task actually processes any transmit events
1364 */
1365static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
1366{
1367        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1368        rtems_event_set the_event;
1369
1370        while (1) {
1371                /*
1372                 * wait for rtems event
1373                 */
1374                rtems_event_receive((TERMIOS_TX_START_EVENT |
1375                                     TERMIOS_TX_TERMINATE_EVENT),
1376                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
1377                                    RTEMS_NO_TIMEOUT,
1378                                    &the_event);
1379                if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
1380                        tty->txTaskId = 0;
1381                        rtems_task_delete(RTEMS_SELF);
1382                }
1383                else {
1384                        /*
1385                         * call any line discipline start function
1386                         */
1387                        if (linesw[tty->t_line].l_start != NULL) {
1388                                linesw[tty->t_line].l_start(tty);
1389                        }
1390                        /*
1391                         * try to push further characters to device
1392                         */
1393                        rtems_termios_refill_transmitter(tty);
1394                }
1395        }
1396}
1397
1398/*
1399 * this task actually processes any receive events
1400 */
1401static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
1402{
1403        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1404        rtems_event_set the_event;
1405        int c;
1406        char c_buf;
1407        while (1) {
1408                /*
1409                 * wait for rtems event
1410                 */
1411                rtems_event_receive((TERMIOS_RX_PROC_EVENT |
1412                                     TERMIOS_RX_TERMINATE_EVENT),
1413                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
1414                                    RTEMS_NO_TIMEOUT,
1415                                    &the_event);
1416                if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
1417                        tty->rxTaskId = 0;
1418                        rtems_task_delete(RTEMS_SELF);
1419                }
1420                else {
1421                        /*
1422                         * do something
1423                         */
1424                        c = tty->device.pollRead(tty->minor);
1425                        if (c != EOF) {
1426                                /*
1427                                 * pollRead did call enqueue on its own
1428                                 */
1429                                c_buf = c;
1430                                rtems_termios_enqueue_raw_characters (
1431                                      tty,&c_buf,1);
1432                        }
1433                }
1434        }
1435}
Note: See TracBrowser for help on using the repository browser.