source: rtems/cpukit/libcsupport/src/termios.c @ e2af631

4.104.114.84.95
Last change on this file since e2af631 was e2af631, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 25, 2000 at 7:35:53 PM

2000-11-25 Antti P Miettinen <antti.p.miettinen@…>

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