source: rtems/c/src/exec/libcsupport/src/termios.c @ 5ec6f09

4.104.114.84.95
Last change on this file since 5ec6f09 was 5ec6f09, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:36

2001-01-31 Mike Siers <mikes@…>

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