source: rtems/c/src/exec/libcsupport/src/termios.c @ b8575ab

4.104.114.84.95
Last change on this file since b8575ab was c0af4e47, checked in by Joel Sherrill <joel.sherrill@…>, on 08/16/01 at 20:58:14

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