source: rtems/cpukit/libcsupport/src/termios.c @ 9c49db4

4.104.114.84.95
Last change on this file since 9c49db4 was 9c49db4, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 8, 2001 at 6:26:44 PM

2001-01-08 Ralf Corsepius <corsepiu@…>

  • configure.in: Add libc/config.h
  • libc/Makefile.am: Add INCLUDES += -I. to pickup config.h
  • libc/.cvsignore: Add config.h and stamp-h
  • libc/*.c: Add config.h support.
  • 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
986        for (;;) {
987                /*
988                 * Process characters read from raw queue
989                 */
990                while (tty->rawInBuf.Head != tty->rawInBuf.Tail) {
991                        unsigned char c;
992                        unsigned int newHead;
993
994                        newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
995                        c = tty->rawInBuf.theBuf[newHead];
996                        tty->rawInBuf.Head = newHead;
997                        if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
998                            % tty->rawInBuf.Size)
999                           < tty->lowwater) {
1000                          tty->flow_ctrl &= ~FL_IREQXOF;
1001                          /* if tx stopped and XON should be sent... */
1002                          if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
1003                               ==                (FL_MDXON | FL_ISNTXOF))
1004                              && ((tty->rawOutBufState == rob_idle)
1005                                  || (tty->flow_ctrl & FL_OSTOP))) {
1006                            /* XON should be sent now... */
1007                            (*tty->device.write)(tty->minor, 
1008                                                 &(tty->termios.c_cc[VSTART]),
1009                                                 1);
1010                          }
1011                          else if (tty->flow_ctrl & FL_MDRTS) {             
1012                            tty->flow_ctrl &= ~FL_IRTSOFF;             
1013                            /* activate RTS line */
1014                            if (tty->device.startRemoteTx != NULL) {
1015                              tty->device.startRemoteTx(tty->minor);
1016                            }
1017                          }
1018                        }
1019
1020                        /* continue processing new character */
1021                        if (tty->termios.c_lflag & ICANON) {
1022                                if  (siproc (c, tty))
1023                                        return RTEMS_SUCCESSFUL;
1024                        }
1025                        else {
1026                                siproc (c, tty);
1027                                if (tty->ccount >= tty->termios.c_cc[VMIN])
1028                                        return RTEMS_SUCCESSFUL;
1029                        }
1030                        timeout = tty->rawInBufSemaphoreTimeout;
1031                }
1032
1033                /*
1034                 * Wait for characters
1035                 */
1036                sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore,
1037                                                tty->rawInBufSemaphoreOptions,
1038                                                timeout);
1039                if (sc != RTEMS_SUCCESSFUL)
1040                        break;
1041        }
1042        return RTEMS_SUCCESSFUL;
1043}
1044
1045rtems_status_code
1046rtems_termios_read (void *arg)
1047{
1048        rtems_libio_rw_args_t *args = arg;
1049        struct rtems_termios_tty *tty = args->iop->data1;
1050        unsigned32 count = args->count;
1051        unsigned8 *buffer = args->buffer;
1052        rtems_status_code sc;
1053
1054        sc = rtems_semaphore_obtain (tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1055        if (sc != RTEMS_SUCCESSFUL)
1056                return sc;
1057        if (linesw[tty->t_line].l_read != NULL) {
1058                sc = linesw[tty->t_line].l_read(tty,args);
1059                rtems_semaphore_release (tty->isem);
1060                return sc;
1061        }
1062        if (tty->cindex == tty->ccount) {
1063                tty->cindex = tty->ccount = 0;
1064                tty->read_start_column = tty->column;
1065                if (tty->device.pollRead != NULL
1066                    && tty->device.outputUsesInterrupts == TERMIOS_POLLED)
1067                        sc = fillBufferPoll (tty);
1068                else
1069                        sc = fillBufferQueue (tty);
1070                if (sc != RTEMS_SUCCESSFUL)
1071                        tty->cindex = tty->ccount = 0;
1072        }
1073        while (count && (tty->cindex < tty->ccount)) {
1074                *buffer++ = tty->cbuf[tty->cindex++];
1075                count--;
1076        }
1077        args->bytes_moved = args->count - count;
1078        rtems_semaphore_release (tty->isem);
1079        return sc;
1080}
1081
1082/*
1083 * signal receive interrupt to rx daemon
1084 * NOTE: This routine runs in the context of the
1085 *       device receive interrupt handler.
1086 */
1087void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
1088{
1089        /*
1090         * send event to rx daemon task
1091         */
1092        rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
1093}
1094
1095/*
1096 * Place characters on raw queue.
1097 * NOTE: This routine runs in the context of the
1098 *       device receive interrupt handler.
1099 * Returns the number of characters dropped because of overflow.
1100 */
1101int
1102rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
1103{
1104        struct rtems_termios_tty *tty = ttyp;
1105        unsigned int newTail;
1106        char c;
1107        int dropped = 0;
1108        boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
1109        rtems_interrupt_level level;
1110
1111        if (linesw[tty->t_line].l_rint != NULL) {
1112          while (len--) {
1113            c = *buf++;
1114            linesw[tty->t_line].l_rint(c,tty);
1115          }
1116          return 0;
1117        }
1118
1119        while (len--) {
1120          c = *buf++;
1121          /* FIXME: implement IXANY: any character restarts output */
1122          /* if incoming XON/XOFF controls outgoing stream: */
1123          if (tty->flow_ctrl & FL_MDXON) {         
1124            /* if received char is V_STOP and V_START (both are equal value) */
1125            if (c == tty->termios.c_cc[VSTOP]) {
1126              if (c == tty->termios.c_cc[VSTART]) {
1127                /* received VSTOP and VSTART==VSTOP? */
1128                /* then toggle "stop output" status  */
1129                tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
1130              }
1131              else {
1132                /* VSTOP received (other code than VSTART) */
1133                /* stop output                             */
1134                tty->flow_ctrl |= FL_ORCVXOF;
1135              }
1136              flow_rcv = TRUE;
1137            }
1138            else if (c == tty->termios.c_cc[VSTART]) {
1139              /* VSTART received */
1140              /* restart output  */
1141              tty->flow_ctrl &= ~FL_ORCVXOF;
1142              flow_rcv = TRUE;
1143            }
1144          }
1145          if (flow_rcv) {
1146            /* restart output according to FL_ORCVXOF flag */
1147            if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
1148              /* disable interrupts    */
1149              rtems_interrupt_disable(level);
1150              tty->flow_ctrl &= ~FL_OSTOP;
1151              /* check for chars in output buffer (or rob_state?) */
1152              if (tty->rawOutBufState != rob_idle) {
1153              /* if chars available, call write function... */
1154                (*tty->device.write)(tty->minor,
1155                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
1156              }
1157              /* reenable interrupts */
1158              rtems_interrupt_enable(level);
1159            }
1160          }     
1161          else {
1162                newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
1163                /* if chars_in_buffer > highwater                */
1164                rtems_interrupt_disable(level);
1165                if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
1166                      % tty->rawInBuf.Size)
1167                     > tty->highwater) && 
1168                    !(tty->flow_ctrl & FL_IREQXOF)) {
1169                  /* incoming data stream should be stopped */
1170                  tty->flow_ctrl |= FL_IREQXOF; 
1171                  if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF)) 
1172                      ==                (FL_MDXOF             ) ){
1173                    if ((tty->flow_ctrl & FL_OSTOP) || 
1174                        (tty->rawOutBufState == rob_idle)) {
1175                      /* if tx is stopped due to XOFF or out of data */
1176                      /*    call write function here                 */
1177                      tty->flow_ctrl |= FL_ISNTXOF;
1178                      (*tty->device.write)(tty->minor,
1179                                           &(tty->termios.c_cc[VSTOP]),
1180                                           1);
1181                    }
1182                  }
1183                  else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) 
1184                           ==                (FL_MDRTS             ) ) {
1185                    tty->flow_ctrl |= FL_IRTSOFF;               
1186                    /* deactivate RTS line */
1187                    if (tty->device.stopRemoteTx != NULL) {
1188                      tty->device.stopRemoteTx(tty->minor);
1189                    }
1190                  }
1191                }
1192                /* reenable interrupts */
1193                rtems_interrupt_enable(level);
1194
1195                if (newTail == tty->rawInBuf.Head) {
1196                        dropped++;
1197                }
1198                else {
1199                        tty->rawInBuf.theBuf[newTail] = c;
1200                        tty->rawInBuf.Tail = newTail;
1201                }               
1202          }
1203        }
1204        tty->rawInBufDropped += dropped;
1205        rtems_semaphore_release (tty->rawInBuf.Semaphore);
1206        return dropped;
1207}
1208
1209/*
1210 * in task-driven mode, this function is called in Tx task context
1211 * in interrupt-driven mode, this function is called in TxIRQ context
1212 */
1213int
1214rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
1215{
1216        unsigned int newTail;
1217        int nToSend;
1218        rtems_interrupt_level level;
1219        int len;
1220
1221        /* check for XOF/XON to send */
1222        if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
1223            == (FL_MDXOF | FL_IREQXOF)) {
1224          /* XOFF should be sent now... */
1225          (*tty->device.write)(tty->minor, 
1226                               &(tty->termios.c_cc[VSTOP]), 1);
1227
1228          rtems_interrupt_disable(level);
1229          tty->t_dqlen--;
1230          tty->flow_ctrl |= FL_ISNTXOF;
1231          rtems_interrupt_enable(level);
1232
1233          nToSend = 1;
1234        }
1235        else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
1236                 == FL_ISNTXOF) {
1237          /* NOTE: send XON even, if no longer in XON/XOFF mode... */
1238          /* XON should be sent now... */
1239                /*
1240                 * FIXME: this .write call will generate another
1241                 * dequeue callback. This will advance the "Tail" in the data
1242                 * buffer, although the corresponding data is not yet out!
1243                 * Therefore the dequeue "length" should be reduced by 1
1244                 */
1245          (*tty->device.write)(tty->minor, 
1246                               &(tty->termios.c_cc[VSTART]), 1);
1247
1248          rtems_interrupt_disable(level);
1249          tty->t_dqlen--;
1250          tty->flow_ctrl &= ~FL_ISNTXOF;
1251          rtems_interrupt_enable(level);
1252
1253          nToSend = 1;
1254        }
1255        else {
1256          if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
1257            /*
1258             * buffer was empty
1259             */
1260            if (tty->rawOutBufState == rob_wait) {
1261              /*
1262               * this should never happen...
1263               */
1264              rtems_semaphore_release (tty->rawOutBuf.Semaphore);
1265            }
1266            return 0;   
1267          }
1268
1269          rtems_interrupt_disable(level);
1270          len = tty->t_dqlen;
1271          tty->t_dqlen = 0;
1272          rtems_interrupt_enable(level);
1273
1274          newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
1275          tty->rawOutBuf.Tail = newTail;
1276          if (tty->rawOutBufState == rob_wait) {
1277            /*
1278             * wake up any pending writer task
1279             */
1280            rtems_semaphore_release (tty->rawOutBuf.Semaphore);
1281          }
1282          if (newTail == tty->rawOutBuf.Head) {
1283            /*
1284             * Buffer has become empty
1285             */
1286            tty->rawOutBufState = rob_idle;
1287            nToSend = 0;
1288          }
1289          /* check, whether output should stop due to received XOFF */
1290          else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 
1291                   ==                (FL_MDXON | FL_ORCVXOF)) {
1292                  /* Buffer not empty, but output stops due to XOFF */
1293                  /* set flag, that output has been stopped */
1294                  rtems_interrupt_disable(level);
1295                  tty->flow_ctrl |= FL_OSTOP;
1296                  tty->rawOutBufState = rob_busy; /*apm*/
1297                  rtems_interrupt_enable(level);
1298                  nToSend = 0;
1299          }
1300          else {
1301            /*
1302             * Buffer not empty, start tranmitter
1303             */
1304            if (newTail > tty->rawOutBuf.Head)
1305                    nToSend = tty->rawOutBuf.Size - newTail;
1306            else
1307                    nToSend = tty->rawOutBuf.Head - newTail;
1308            /* when flow control XON or XOF, don't send blocks of data     */
1309            /* to allow fast reaction on incoming flow ctrl and low latency*/
1310            /* for outgoing flow control                                   */
1311            if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
1312                    nToSend = 1;
1313            }
1314            tty->rawOutBufState = rob_busy; /*apm*/
1315            (*tty->device.write)(tty->minor, 
1316                                 (char *)&tty->rawOutBuf.theBuf[newTail], 
1317                                 nToSend);
1318          }
1319          tty->rawOutBuf.Tail = newTail; /*apm*/
1320        }
1321        return nToSend;
1322}
1323
1324/*
1325 * Characters have been transmitted
1326 * NOTE: This routine runs in the context of the
1327 *       device transmit interrupt handler.
1328 * The second argument is the number of characters transmitted so far.
1329 * This value will always be 1 for devices which generate an interrupt
1330 * for each transmitted character.
1331 * It returns number of characters left to transmit
1332 */
1333int
1334rtems_termios_dequeue_characters (void *ttyp, int len)
1335{
1336        struct rtems_termios_tty *tty = ttyp;
1337        rtems_status_code sc;
1338
1339        /*
1340         * sum up character count already sent
1341         */
1342        tty->t_dqlen += len;
1343
1344        if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
1345                /*
1346                 * send wake up to transmitter task
1347                 */
1348                sc = rtems_event_send(tty->txTaskId,
1349                                      TERMIOS_TX_START_EVENT);
1350                if (sc != RTEMS_SUCCESSFUL)
1351                        rtems_fatal_error_occurred (sc);
1352                return 0; /* nothing to output in IRQ... */
1353        }
1354        else {
1355                return rtems_termios_refill_transmitter(tty);
1356        }
1357}
1358
1359/*
1360 * this task actually processes any transmit events
1361 */
1362static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
1363{
1364        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1365        rtems_event_set the_event;
1366
1367        while (1) {
1368                /*
1369                 * wait for rtems event
1370                 */
1371                rtems_event_receive((TERMIOS_TX_START_EVENT | 
1372                                     TERMIOS_TX_TERMINATE_EVENT),
1373                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
1374                                    RTEMS_NO_TIMEOUT,
1375                                    &the_event);
1376                if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
1377                        tty->txTaskId = 0;
1378                        rtems_task_delete(RTEMS_SELF);
1379                }
1380                else {
1381                        /*
1382                         * call any line discipline start function
1383                         */
1384                        if (linesw[tty->t_line].l_start != NULL) {
1385                                linesw[tty->t_line].l_start(tty);
1386                        }
1387                        /*
1388                         * try to push further characters to device
1389                         */
1390                        rtems_termios_refill_transmitter(tty);
1391                }
1392        }
1393}
1394
1395/*
1396 * this task actually processes any receive events
1397 */
1398static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
1399{
1400        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1401        rtems_event_set the_event;
1402        int c;
1403        char c_buf;
1404        while (1) {
1405                /*
1406                 * wait for rtems event
1407                 */
1408                rtems_event_receive((TERMIOS_RX_PROC_EVENT | 
1409                                     TERMIOS_RX_TERMINATE_EVENT),
1410                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
1411                                    RTEMS_NO_TIMEOUT,
1412                                    &the_event);
1413                if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
1414                        tty->rxTaskId = 0;
1415                        rtems_task_delete(RTEMS_SELF);
1416                }
1417                else {
1418                        /*
1419                         * do something
1420                         */
1421                        c = tty->device.pollRead(tty->minor);
1422                        if (c != EOF) {
1423                                /*
1424                                 * pollRead did call enqueue on its own
1425                                 */
1426                                c_buf = c;
1427                                rtems_termios_enqueue_raw_characters (
1428                                      tty,&c_buf,1);
1429                        }
1430                }
1431        }
1432}
Note: See TracBrowser for help on using the repository browser.