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

4.115
Last change on this file since da154e14 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

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