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

5
Last change on this file since e34fe38 was e34fe38, checked in by Alexander Krutwig <alexander.krutwig@…>, on 10/17/16 at 12:15:34

termios: Add TERMIOS_IRQ_SERVER_DRIVEN

Add a new interrupt server driven Termios mode (TERMIOS_IRQ_DRIVEN).
This mode is identical to the interrupt driven mode except that a mutex
is used for device level locking. The intended use case for this mode
are device drivers that use the interrupt server, e.g. SPI or I2C
connected devices.

Update #2839.

  • Property mode set to 100644
File size: 55.8 KB
Line 
1/**
2 * @file
3 * TERMIOS serial line support
4 */
5
6/*
7 *  Author:
8 *    W. Eric Norum
9 *    Saskatchewan Accelerator Laboratory
10 *    University of Saskatchewan
11 *    Saskatoon, Saskatchewan, CANADA
12 *    eric@skatter.usask.ca
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <rtems.h>
24#include <rtems/libio.h>
25#include <rtems/imfs.h>
26#include <rtems/score/assert.h>
27#include <ctype.h>
28#include <errno.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <termios.h>
32#include <unistd.h>
33#include <sys/ttycom.h>
34
35#include <rtems/termiostypes.h>
36
37/*
38 * The size of the cooked buffer
39 */
40#define CBUFSIZE  (rtems_termios_cbufsize)
41
42/*
43 * The sizes of the raw message buffers.
44 * On most architectures it is quite a bit more
45 * efficient if these are powers of two.
46 */
47#define RAW_INPUT_BUFFER_SIZE  (rtems_termios_raw_input_size)
48#define RAW_OUTPUT_BUFFER_SIZE  (rtems_termios_raw_output_size)
49
50/* fields for "flow_ctrl" status */
51#define FL_IREQXOF 1U        /* input queue requests stop of incoming data */
52#define FL_ISNTXOF 2U        /* XOFF has been sent to other side of line   */
53#define FL_IRTSOFF 4U        /* RTS has been turned off for other side..   */
54
55#define FL_ORCVXOF 0x10U     /* XOFF has been received                     */
56#define FL_OSTOP   0x20U     /* output has been stopped due to XOFF        */
57
58#define FL_MDRTS   0x100U    /* input controlled with RTS/CTS handshake    */
59#define FL_MDXON   0x200U    /* input controlled with XON/XOFF protocol    */
60#define FL_MDXOF   0x400U    /* output controlled with XON/XOFF protocol   */
61
62#define NODISC(n) \
63  { NULL,  NULL,  NULL,  NULL, \
64    NULL,  NULL,  NULL,  NULL }
65/*
66 * FIXME: change rtems_termios_linesw entries consistent
67 *        with rtems_termios_linesw entry usage...
68 */
69struct  rtems_termios_linesw rtems_termios_linesw[MAXLDISC] =
70{
71  NODISC(0),    /* 0- termios-built-in */
72  NODISC(1),    /* 1- defunct */
73  NODISC(2),    /* 2- NTTYDISC */
74  NODISC(3),    /* TABLDISC */
75  NODISC(4),    /* SLIPDISC */
76  NODISC(5),    /* PPPDISC */
77  NODISC(6),    /* loadable */
78  NODISC(7),    /* loadable */
79};
80
81int  rtems_termios_nlinesw =
82       sizeof (rtems_termios_linesw) / sizeof (rtems_termios_linesw[0]);
83
84extern rtems_id rtems_termios_ttyMutex;
85
86static size_t rtems_termios_cbufsize = 256;
87static size_t rtems_termios_raw_input_size = 128;
88static size_t rtems_termios_raw_output_size = 64;
89
90static const IMFS_node_control rtems_termios_imfs_node_control;
91
92static struct rtems_termios_tty *rtems_termios_ttyHead;
93static struct rtems_termios_tty *rtems_termios_ttyTail;
94
95static RTEMS_CHAIN_DEFINE_EMPTY(rtems_termios_devices);
96
97static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
98static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
99/*
100 * some constants for I/O daemon task creation
101 */
102#define TERMIOS_TXTASK_PRIO 10
103#define TERMIOS_RXTASK_PRIO 9
104#define TERMIOS_TXTASK_STACKSIZE 1024
105#define TERMIOS_RXTASK_STACKSIZE 1024
106/*
107 * some events to be sent to the I/O tasks
108 */
109#define TERMIOS_TX_START_EVENT     RTEMS_EVENT_1
110#define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0
111
112#define TERMIOS_RX_PROC_EVENT      RTEMS_EVENT_1
113#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
114
115static rtems_status_code
116rtems_termios_obtain (void)
117{
118  return rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT,
119    RTEMS_NO_TIMEOUT);
120}
121
122static void
123rtems_termios_release (void)
124{
125  rtems_status_code sc;
126
127  sc = rtems_semaphore_release (rtems_termios_ttyMutex);
128  _Assert (sc == RTEMS_SUCCESSFUL);
129  (void) sc;
130}
131
132rtems_status_code rtems_termios_device_install(
133  const char                         *device_file,
134  const rtems_termios_device_handler *handler,
135  const rtems_termios_device_flow    *flow,
136  rtems_termios_device_context       *context
137)
138{
139  rtems_termios_device_node *new_device_node;
140  int rv;
141
142  new_device_node = calloc (1, sizeof(*new_device_node));
143  if (new_device_node == NULL) {
144    return RTEMS_NO_MEMORY;
145  }
146
147  rtems_chain_initialize_node (&new_device_node->node);
148  new_device_node->handler = handler;
149  new_device_node->flow = flow;
150  new_device_node->context = context;
151  new_device_node->tty = NULL;
152
153  rv = IMFS_make_generic_node(
154    device_file,
155    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
156    &rtems_termios_imfs_node_control,
157    new_device_node
158  );
159  if (rv != 0) {
160    free (new_device_node);
161    return RTEMS_UNSATISFIED;
162  }
163
164  return RTEMS_SUCCESSFUL;
165}
166
167static rtems_termios_tty *
168legacyContextToTTY (rtems_termios_device_context *ctx)
169{
170  return RTEMS_CONTAINER_OF (ctx, rtems_termios_tty, legacy_device_context);
171}
172
173static bool
174rtems_termios_callback_firstOpen(
175  rtems_termios_tty             *tty,
176  rtems_termios_device_context  *ctx,
177  struct termios                *term,
178  rtems_libio_open_close_args_t *args
179)
180{
181  (void) ctx;
182  (void) term;
183
184  (*tty->device.firstOpen) (tty->major, tty->minor, args);
185
186  return true;
187}
188
189static void
190rtems_termios_callback_lastClose(
191  rtems_termios_tty             *tty,
192  rtems_termios_device_context  *ctx,
193  rtems_libio_open_close_args_t *args
194)
195{
196  (void) ctx;
197
198  (*tty->device.lastClose) (tty->major, tty->minor, args);
199}
200
201static int
202rtems_termios_callback_pollRead (rtems_termios_device_context *ctx)
203{
204  rtems_termios_tty *tty = legacyContextToTTY (ctx);
205
206  return (*tty->device.pollRead) (tty->minor);
207}
208
209static void
210rtems_termios_callback_write(
211  rtems_termios_device_context *ctx,
212  const char                   *buf,
213  size_t                        len
214)
215{
216  rtems_termios_tty *tty = legacyContextToTTY (ctx);
217
218  (*tty->device.write) (tty->minor, buf, len);
219}
220
221static bool
222rtems_termios_callback_setAttributes(
223  rtems_termios_device_context *ctx,
224  const struct termios         *term
225)
226{
227  rtems_termios_tty *tty = legacyContextToTTY (ctx);
228
229  (*tty->device.setAttributes) (tty->minor, term);
230
231  return true;
232}
233
234static void
235rtems_termios_callback_stopRemoteTx (rtems_termios_device_context *ctx)
236{
237  rtems_termios_tty *tty = legacyContextToTTY (ctx);
238
239  (*tty->device.stopRemoteTx) (tty->minor);
240}
241
242static void
243rtems_termios_callback_startRemoteTx (rtems_termios_device_context *ctx)
244{
245  rtems_termios_tty *tty = legacyContextToTTY (ctx);
246
247  (*tty->device.startRemoteTx) (tty->minor);
248}
249
250/*
251 * Drain output queue
252 */
253static void
254drainOutput (struct rtems_termios_tty *tty)
255{
256  rtems_termios_device_context *ctx = tty->device_context;
257  rtems_interrupt_lock_context lock_context;
258  rtems_status_code sc;
259
260  if (tty->handler.mode != TERMIOS_POLLED) {
261    rtems_termios_device_lock_acquire (ctx, &lock_context);
262    while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
263      tty->rawOutBufState = rob_wait;
264      rtems_termios_device_lock_release (ctx, &lock_context);
265      sc = rtems_semaphore_obtain(
266        tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
267      if (sc != RTEMS_SUCCESSFUL)
268        rtems_fatal_error_occurred (sc);
269      rtems_termios_device_lock_acquire (ctx, &lock_context);
270    }
271    rtems_termios_device_lock_release (ctx, &lock_context);
272  }
273}
274
275static bool
276needDeviceMutex (rtems_termios_tty *tty)
277{
278  return tty->handler.mode == TERMIOS_IRQ_SERVER_DRIVEN
279    || tty->handler.mode == TERMIOS_TASK_DRIVEN;
280}
281
282static void
283rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
284{
285  rtems_status_code sc;
286
287  if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
288    /*
289     * call discipline-specific close
290     */
291    (void) rtems_termios_linesw[tty->t_line].l_close(tty);
292  } else if (last_close) {
293    /*
294     * default: just flush output buffer
295     */
296    sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
297    if (sc != RTEMS_SUCCESSFUL) {
298      rtems_fatal_error_occurred (sc);
299    }
300    drainOutput (tty);
301    rtems_semaphore_release (tty->osem);
302  }
303
304  if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
305    /*
306     * send "terminate" to I/O tasks
307     */
308    sc = rtems_event_send( tty->rxTaskId, TERMIOS_RX_TERMINATE_EVENT );
309    if (sc != RTEMS_SUCCESSFUL)
310      rtems_fatal_error_occurred (sc);
311    sc = rtems_event_send( tty->txTaskId, TERMIOS_TX_TERMINATE_EVENT );
312    if (sc != RTEMS_SUCCESSFUL)
313      rtems_fatal_error_occurred (sc);
314  }
315  if (last_close && tty->handler.last_close)
316     (*tty->handler.last_close)(tty, tty->device_context, arg);
317
318  if (tty->device_node != NULL)
319    tty->device_node->tty = NULL;
320
321  rtems_semaphore_delete (tty->isem);
322  rtems_semaphore_delete (tty->osem);
323  rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
324  if ((tty->handler.poll_read == NULL) ||
325      (tty->handler.mode == TERMIOS_TASK_DRIVEN))
326    rtems_semaphore_delete (tty->rawInBuf.Semaphore);
327
328  if (needDeviceMutex (tty)) {
329    rtems_semaphore_delete (tty->device_context->lock.mutex);
330  } else if (tty->device_context == &tty->legacy_device_context) {
331    rtems_interrupt_lock_destroy (&tty->legacy_device_context.lock.interrupt);
332  }
333
334  free (tty->rawInBuf.theBuf);
335  free (tty->rawOutBuf.theBuf);
336  free (tty->cbuf);
337  free (tty);
338}
339
340static void
341deviceAcquireMutex(
342  rtems_termios_device_context *ctx,
343  rtems_interrupt_lock_context *lock_context
344)
345{
346  rtems_status_code sc;
347
348  sc = rtems_semaphore_obtain (ctx->lock.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
349  _Assert (sc == RTEMS_SUCCESSFUL);
350  (void) sc;
351}
352
353static void
354deviceReleaseMutex(
355  rtems_termios_device_context *ctx,
356  rtems_interrupt_lock_context *lock_context
357)
358{
359  rtems_status_code sc;
360
361  sc = rtems_semaphore_release (ctx->lock.mutex);
362  _Assert (sc == RTEMS_SUCCESSFUL);
363  (void) sc;
364}
365
366static void
367deviceAcquireInterrupt(
368  rtems_termios_device_context *ctx,
369  rtems_interrupt_lock_context *lock_context
370)
371{
372  rtems_interrupt_lock_acquire (&ctx->lock.interrupt, lock_context);
373}
374
375static void
376deviceReleaseInterrupt(
377  rtems_termios_device_context *ctx,
378  rtems_interrupt_lock_context *lock_context
379)
380{
381  rtems_interrupt_lock_release (&ctx->lock.interrupt, lock_context);
382}
383
384static rtems_termios_tty *
385rtems_termios_open_tty(
386  rtems_device_major_number      major,
387  rtems_device_minor_number      minor,
388  rtems_libio_open_close_args_t *args,
389  rtems_termios_tty             *tty,
390  rtems_termios_device_node     *device_node,
391  const rtems_termios_callbacks *callbacks
392)
393{
394  rtems_status_code sc;
395
396  if (tty == NULL) {
397    static char c = 'a';
398    rtems_termios_device_context *ctx;
399
400    /*
401     * Create a new device
402     */
403    tty = calloc (1, sizeof (struct rtems_termios_tty));
404    if (tty == NULL) {
405      return NULL;
406    }
407    /*
408     * allocate raw input buffer
409     */
410    tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
411    tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
412    if (tty->rawInBuf.theBuf == NULL) {
413            free(tty);
414      return NULL;
415    }
416    /*
417     * allocate raw output buffer
418     */
419    tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
420    tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
421    if (tty->rawOutBuf.theBuf == NULL) {
422            free((void *)(tty->rawInBuf.theBuf));
423            free(tty);
424      return NULL;
425    }
426    /*
427     * allocate cooked buffer
428     */
429    tty->cbuf  = malloc (CBUFSIZE);
430    if (tty->cbuf == NULL) {
431            free((void *)(tty->rawOutBuf.theBuf));
432            free((void *)(tty->rawInBuf.theBuf));
433            free(tty);
434      return NULL;
435    }
436    /*
437     * Initialize wakeup callbacks
438     */
439    tty->tty_snd.sw_pfn = NULL;
440    tty->tty_snd.sw_arg = NULL;
441    tty->tty_rcv.sw_pfn = NULL;
442    tty->tty_rcv.sw_arg = NULL;
443    tty->tty_rcvwakeup  = 0;
444
445    tty->minor = minor;
446    tty->major = major;
447
448    /*
449     * Set up mutex semaphores
450     */
451    sc = rtems_semaphore_create (
452      rtems_build_name ('T', 'R', 'i', c),
453      1,
454      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
455      RTEMS_NO_PRIORITY,
456      &tty->isem);
457    if (sc != RTEMS_SUCCESSFUL)
458      rtems_fatal_error_occurred (sc);
459    sc = rtems_semaphore_create (
460      rtems_build_name ('T', 'R', 'o', c),
461      1,
462      RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
463      RTEMS_NO_PRIORITY,
464      &tty->osem);
465    if (sc != RTEMS_SUCCESSFUL)
466      rtems_fatal_error_occurred (sc);
467    sc = rtems_semaphore_create (
468      rtems_build_name ('T', 'R', 'x', c),
469      0,
470      RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
471      RTEMS_NO_PRIORITY,
472      &tty->rawOutBuf.Semaphore);
473    if (sc != RTEMS_SUCCESSFUL)
474      rtems_fatal_error_occurred (sc);
475    tty->rawOutBufState = rob_idle;
476
477    /*
478     * Set callbacks
479     */
480    if (device_node != NULL) {
481      device_node->tty = tty;
482      tty->handler = *device_node->handler;
483
484      if (device_node->flow != NULL) {
485        tty->flow = *device_node->flow;
486      }
487
488      tty->device_node = device_node;
489      tty->device_context = device_node->context;
490      memset(&tty->device, 0, sizeof(tty->device));
491    } else {
492      tty->handler.first_open = callbacks->firstOpen != NULL ?
493        rtems_termios_callback_firstOpen : NULL;
494      tty->handler.last_close = callbacks->lastClose != NULL ?
495        rtems_termios_callback_lastClose : NULL;
496      tty->handler.poll_read = callbacks->pollRead != NULL ?
497        rtems_termios_callback_pollRead : NULL;
498      tty->handler.write = callbacks->write != NULL ?
499        rtems_termios_callback_write : NULL;
500      tty->handler.set_attributes = callbacks->setAttributes != NULL ?
501        rtems_termios_callback_setAttributes : NULL;
502      tty->flow.stop_remote_tx = callbacks->stopRemoteTx != NULL ?
503        rtems_termios_callback_stopRemoteTx : NULL;
504      tty->flow.start_remote_tx = callbacks->startRemoteTx != NULL ?
505        rtems_termios_callback_startRemoteTx : NULL;
506      tty->handler.mode = callbacks->outputUsesInterrupts;
507      tty->device_context = NULL;
508      tty->device_node = NULL;
509      tty->device = *callbacks;
510    }
511
512    if (tty->device_context == NULL) {
513      tty->device_context = &tty->legacy_device_context;
514      rtems_termios_device_context_initialize (tty->device_context, "Termios");
515    }
516
517    ctx = tty->device_context;
518
519    if (needDeviceMutex (tty)) {
520      sc = rtems_semaphore_create (
521        rtems_build_name ('T', 'l', 'k', c),
522        1,
523        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
524        0,
525        &ctx->lock.mutex);
526      if (sc != RTEMS_SUCCESSFUL) {
527        rtems_fatal_error_occurred (sc);
528      }
529
530      ctx->lock_acquire = deviceAcquireMutex;
531      ctx->lock_release = deviceReleaseMutex;
532    } else {
533      ctx->lock_acquire = deviceAcquireInterrupt;
534      ctx->lock_release = deviceReleaseInterrupt;
535    }
536
537    /*
538     * Create I/O tasks
539     */
540    if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
541      sc = rtems_task_create (
542                                   rtems_build_name ('T', 'x', 'T', c),
543           TERMIOS_TXTASK_PRIO,
544           TERMIOS_TXTASK_STACKSIZE,
545           RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
546           RTEMS_NO_ASR,
547           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
548           &tty->txTaskId);
549      if (sc != RTEMS_SUCCESSFUL)
550        rtems_fatal_error_occurred (sc);
551      sc = rtems_task_create (
552                                   rtems_build_name ('R', 'x', 'T', c),
553           TERMIOS_RXTASK_PRIO,
554           TERMIOS_RXTASK_STACKSIZE,
555           RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
556           RTEMS_NO_ASR,
557           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
558           &tty->rxTaskId);
559      if (sc != RTEMS_SUCCESSFUL)
560        rtems_fatal_error_occurred (sc);
561
562    }
563    if ((tty->handler.poll_read == NULL) ||
564        (tty->handler.mode == TERMIOS_TASK_DRIVEN)){
565      sc = rtems_semaphore_create (
566        rtems_build_name ('T', 'R', 'r', c),
567        0,
568        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY,
569        RTEMS_NO_PRIORITY,
570        &tty->rawInBuf.Semaphore);
571      if (sc != RTEMS_SUCCESSFUL)
572        rtems_fatal_error_occurred (sc);
573    }
574
575    /*
576     * Set default parameters
577     */
578    tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;
579    tty->termios.c_oflag = OPOST | ONLCR | XTABS;
580    tty->termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
581    tty->termios.c_lflag =
582       ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
583
584    tty->termios.c_cc[VINTR] = '\003';
585    tty->termios.c_cc[VQUIT] = '\034';
586    tty->termios.c_cc[VERASE] = '\177';
587    tty->termios.c_cc[VKILL] = '\025';
588    tty->termios.c_cc[VEOF] = '\004';
589    tty->termios.c_cc[VEOL] = '\000';
590    tty->termios.c_cc[VEOL2] = '\000';
591    tty->termios.c_cc[VSTART] = '\021';
592    tty->termios.c_cc[VSTOP] = '\023';
593    tty->termios.c_cc[VSUSP] = '\032';
594    tty->termios.c_cc[VREPRINT] = '\022';
595    tty->termios.c_cc[VDISCARD] = '\017';
596    tty->termios.c_cc[VWERASE] = '\027';
597    tty->termios.c_cc[VLNEXT] = '\026';
598
599    /* start with no flow control, clear flow control flags */
600    tty->flow_ctrl = 0;
601    /*
602     * set low/highwater mark for XON/XOFF support
603     */
604    tty->lowwater  = tty->rawInBuf.Size * 1/2;
605    tty->highwater = tty->rawInBuf.Size * 3/4;
606    /*
607     * Bump name characer
608     */
609    if (c++ == 'z')
610      c = 'a';
611
612  }
613  args->iop->data1 = tty;
614  if (!tty->refcount++) {
615    if (tty->handler.first_open && !(*tty->handler.first_open)(
616        tty, tty->device_context, &tty->termios, args)) {
617      rtems_termios_destroy_tty(tty, args, false);
618      return NULL;
619    }
620
621    /*
622     * start I/O tasks, if needed
623     */
624    if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
625      sc = rtems_task_start(
626        tty->rxTaskId, rtems_termios_rxdaemon, (rtems_task_argument)tty);
627      if (sc != RTEMS_SUCCESSFUL)
628        rtems_fatal_error_occurred (sc);
629
630      sc = rtems_task_start(
631        tty->txTaskId, rtems_termios_txdaemon, (rtems_task_argument)tty);
632      if (sc != RTEMS_SUCCESSFUL)
633        rtems_fatal_error_occurred (sc);
634    }
635  }
636
637  return tty;
638}
639
640/*
641 * Open a termios device
642 */
643rtems_status_code
644rtems_termios_open (
645  rtems_device_major_number      major,
646  rtems_device_minor_number      minor,
647  void                          *arg,
648  const rtems_termios_callbacks *callbacks
649)
650{
651  rtems_status_code sc;
652  struct rtems_termios_tty *tty;
653
654  /*
655   * See if the device has already been opened
656   */
657  sc = rtems_termios_obtain ();
658  if (sc != RTEMS_SUCCESSFUL)
659    return sc;
660
661  for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {
662    if ((tty->major == major) && (tty->minor == minor))
663      break;
664  }
665
666  tty = rtems_termios_open_tty(
667    major, minor, arg, tty, NULL, callbacks);
668  if (tty == NULL) {
669    rtems_termios_release ();
670    return RTEMS_NO_MEMORY;
671  }
672
673  if (tty->refcount == 1) {
674    /*
675     * link tty
676     */
677    tty->forw = rtems_termios_ttyHead;
678    tty->back = NULL;
679    if (rtems_termios_ttyHead != NULL)
680      rtems_termios_ttyHead->back = tty;
681    rtems_termios_ttyHead = tty;
682    if (rtems_termios_ttyTail == NULL)
683      rtems_termios_ttyTail = tty;
684  }
685
686  rtems_termios_release ();
687
688  return RTEMS_SUCCESSFUL;
689}
690
691static void
692flushOutput (struct rtems_termios_tty *tty)
693{
694  rtems_termios_device_context *ctx = tty->device_context;
695  rtems_interrupt_lock_context lock_context;
696
697  rtems_termios_device_lock_acquire (ctx, &lock_context);
698  tty->rawOutBuf.Tail = 0;
699  tty->rawOutBuf.Head = 0;
700  tty->rawOutBufState = rob_idle;
701  rtems_termios_device_lock_release (ctx, &lock_context);
702}
703
704static void
705flushInput (struct rtems_termios_tty *tty)
706{
707  rtems_termios_device_context *ctx = tty->device_context;
708  rtems_interrupt_lock_context lock_context;
709
710  rtems_termios_device_lock_acquire (ctx, &lock_context);
711  tty->rawInBuf.Tail = 0;
712  tty->rawInBuf.Head = 0;
713  rtems_termios_device_lock_release (ctx, &lock_context);
714}
715
716static void
717rtems_termios_close_tty (rtems_termios_tty *tty, void *arg)
718{
719  if (--tty->refcount == 0) {
720    rtems_termios_destroy_tty (tty, arg, true);
721  }
722}
723
724rtems_status_code
725rtems_termios_close (void *arg)
726{
727  rtems_status_code sc;
728  rtems_libio_open_close_args_t *args = arg;
729  struct rtems_termios_tty *tty = args->iop->data1;
730
731  sc = rtems_termios_obtain ();
732  if (sc != RTEMS_SUCCESSFUL)
733    rtems_fatal_error_occurred (sc);
734
735  if (tty->refcount == 1) {
736    if (tty->forw == NULL) {
737      rtems_termios_ttyTail = tty->back;
738      if ( rtems_termios_ttyTail != NULL ) {
739        rtems_termios_ttyTail->forw = NULL;
740      }
741    } else {
742      tty->forw->back = tty->back;
743    }
744
745    if (tty->back == NULL) {
746      rtems_termios_ttyHead = tty->forw;
747      if ( rtems_termios_ttyHead != NULL ) {
748        rtems_termios_ttyHead->back = NULL;
749      }
750    } else {
751      tty->back->forw = tty->forw;
752    }
753  }
754
755  rtems_termios_close_tty (tty, arg);
756
757  rtems_termios_release ();
758
759  return RTEMS_SUCCESSFUL;
760}
761
762rtems_status_code rtems_termios_bufsize (
763  size_t cbufsize,
764  size_t raw_input,
765  size_t raw_output
766)
767{
768  rtems_termios_cbufsize        = cbufsize;
769  rtems_termios_raw_input_size  = raw_input;
770  rtems_termios_raw_output_size = raw_output;
771  return RTEMS_SUCCESSFUL;
772}
773
774static void
775termios_set_flowctrl(struct rtems_termios_tty *tty)
776{
777  rtems_termios_device_context *ctx = tty->device_context;
778  rtems_interrupt_lock_context lock_context;
779  /*
780   * check for flow control options to be switched off
781   */
782
783  /* check for outgoing XON/XOFF flow control switched off */
784  if (( tty->flow_ctrl & FL_MDXON) &&
785      !(tty->termios.c_iflag & IXON)) {
786    /* clear related flags in flow_ctrl */
787    tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);
788
789    /* has output been stopped due to received XOFF? */
790    if (tty->flow_ctrl & FL_OSTOP) {
791      /* disable interrupts    */
792      rtems_termios_device_lock_acquire (ctx, &lock_context);
793      tty->flow_ctrl &= ~FL_OSTOP;
794      /* check for chars in output buffer (or rob_state?) */
795      if (tty->rawOutBufState != rob_idle) {
796        /* if chars available, call write function... */
797        (*tty->handler.write)(
798          ctx, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
799      }
800      /* reenable interrupts */
801      rtems_termios_device_lock_release (ctx, &lock_context);
802    }
803  }
804  /* check for incoming XON/XOFF flow control switched off */
805  if (( tty->flow_ctrl & FL_MDXOF) && !(tty->termios.c_iflag & IXOFF)) {
806    /* clear related flags in flow_ctrl */
807    tty->flow_ctrl &= ~(FL_MDXOF);
808    /* FIXME: what happens, if we had sent XOFF but not yet XON? */
809    tty->flow_ctrl &= ~(FL_ISNTXOF);
810  }
811
812  /* check for incoming RTS/CTS flow control switched off */
813  if (( tty->flow_ctrl & FL_MDRTS) && !(tty->termios.c_cflag & CRTSCTS)) {
814    /* clear related flags in flow_ctrl */
815    tty->flow_ctrl &= ~(FL_MDRTS);
816
817    /* restart remote Tx, if it was stopped */
818    if ((tty->flow_ctrl & FL_IRTSOFF) &&
819        (tty->flow.start_remote_tx != NULL)) {
820      tty->flow.start_remote_tx(ctx);
821    }
822    tty->flow_ctrl &= ~(FL_IRTSOFF);
823  }
824
825  /*
826   * check for flow control options to be switched on
827   */
828  /* check for incoming RTS/CTS flow control switched on */
829  if (tty->termios.c_cflag & CRTSCTS) {
830    tty->flow_ctrl |= FL_MDRTS;
831  }
832  /* check for incoming XON/XOF flow control switched on */
833  if (tty->termios.c_iflag & IXOFF) {
834    tty->flow_ctrl |= FL_MDXOF;
835  }
836  /* check for outgoing XON/XOF flow control switched on */
837  if (tty->termios.c_iflag & IXON) {
838    tty->flow_ctrl |= FL_MDXON;
839  }
840}
841
842rtems_status_code
843rtems_termios_ioctl (void *arg)
844{
845  rtems_libio_ioctl_args_t *args = arg;
846  struct rtems_termios_tty *tty = args->iop->data1;
847  struct ttywakeup         *wakeup = (struct ttywakeup *)args->buffer;
848  rtems_status_code sc;
849
850  args->ioctl_return = 0;
851  sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
852  if (sc != RTEMS_SUCCESSFUL) {
853    return sc;
854  }
855  switch (args->command) {
856  default:
857    if (rtems_termios_linesw[tty->t_line].l_ioctl != NULL) {
858      sc = rtems_termios_linesw[tty->t_line].l_ioctl(tty,args);
859    } else if (tty->handler.ioctl) {
860      args->ioctl_return = (*tty->handler.ioctl) (tty->device_context,
861        args->command, args->buffer);
862      sc = RTEMS_SUCCESSFUL;
863    } else {
864      sc = RTEMS_INVALID_NUMBER;
865    }
866    break;
867
868  case RTEMS_IO_GET_ATTRIBUTES:
869    *(struct termios *)args->buffer = tty->termios;
870    break;
871
872  case RTEMS_IO_SET_ATTRIBUTES:
873    tty->termios = *(struct termios *)args->buffer;
874
875    /* check for and process change in flow control options */
876    termios_set_flowctrl(tty);
877
878    if (tty->termios.c_lflag & ICANON) {
879      tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
880      tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
881      tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
882    } else {
883      tty->vtimeTicks = tty->termios.c_cc[VTIME] *
884                    rtems_clock_get_ticks_per_second() / 10;
885      if (tty->termios.c_cc[VTIME]) {
886        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
887        tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
888        if (tty->termios.c_cc[VMIN])
889          tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
890        else
891          tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
892      } else {
893        if (tty->termios.c_cc[VMIN]) {
894          tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
895          tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
896          tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
897        } else {
898          tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
899        }
900      }
901    }
902    if (tty->handler.set_attributes) {
903      sc = (*tty->handler.set_attributes)(tty->device_context, &tty->termios) ?
904        RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
905    }
906    break;
907
908  case RTEMS_IO_TCDRAIN:
909    drainOutput (tty);
910    break;
911
912  case RTEMS_IO_TCFLUSH:
913    switch ((intptr_t) args->buffer) {
914      case TCIFLUSH:
915        flushInput (tty);
916        break;
917      case TCOFLUSH:
918        flushOutput (tty);
919        break;
920      case TCIOFLUSH:
921        flushOutput (tty);
922        flushInput (tty);
923        break;
924      default:
925        sc = RTEMS_INVALID_NAME;
926        break;
927    }
928    break;
929
930  case RTEMS_IO_SNDWAKEUP:
931    tty->tty_snd = *wakeup;
932    break;
933
934  case RTEMS_IO_RCVWAKEUP:
935    tty->tty_rcv = *wakeup;
936    break;
937
938    /*
939     * FIXME: add various ioctl code handlers
940     */
941
942#if 1 /* FIXME */
943  case TIOCSETD:
944    /*
945     * close old line discipline
946     */
947    if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
948      sc = rtems_termios_linesw[tty->t_line].l_close(tty);
949    }
950    tty->t_line=*(int*)(args->buffer);
951    tty->t_sc = NULL; /* ensure that no more valid data */
952    /*
953     * open new line discipline
954     */
955    if (rtems_termios_linesw[tty->t_line].l_open != NULL) {
956      sc = rtems_termios_linesw[tty->t_line].l_open(tty);
957    }
958    break;
959  case TIOCGETD:
960    *(int*)(args->buffer)=tty->t_line;
961    break;
962#endif
963   case FIONREAD: {
964      int rawnc = tty->rawInBuf.Tail - tty->rawInBuf.Head;
965      if ( rawnc < 0 )
966        rawnc += tty->rawInBuf.Size;
967      /* Half guess that this is the right operation */
968      *(int *)args->buffer = tty->ccount - tty->cindex + rawnc;
969    }
970    break;
971  }
972
973  rtems_semaphore_release (tty->osem);
974  return sc;
975}
976
977/*
978 * Send as many chars at once as possible to device-specific code.
979 * If transmitting==true then assume transmission is already running and
980 * an explicit write(0) is needed if output has to stop for flow control.
981 */
982static unsigned int
983startXmit (
984  struct rtems_termios_tty *tty,
985  unsigned int newTail,
986  bool transmitting
987)
988{
989  unsigned int nToSend;
990
991  tty->rawOutBufState = rob_busy;
992
993  /* if XOFF was received, do not (re)start output */
994  if (tty->flow_ctrl & FL_ORCVXOF) {
995    /* set flag, that output has been stopped */
996    tty->flow_ctrl |= FL_OSTOP;
997    nToSend = 0;
998    /* stop transmitter */
999    if (transmitting) {
1000      (*tty->handler.write) (tty->device_context, NULL, 0);
1001    }
1002  } else {
1003    /* when flow control XON or XOF, don't send blocks of data     */
1004    /* to allow fast reaction on incoming flow ctrl and low latency*/
1005    /* for outgoing flow control                                   */
1006    if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF))
1007      nToSend = 1;
1008    else if (newTail > tty->rawOutBuf.Head)
1009      nToSend = tty->rawOutBuf.Size - newTail;
1010    else
1011      nToSend = tty->rawOutBuf.Head - newTail;
1012
1013    (*tty->handler.write)(
1014        tty->device_context, &tty->rawOutBuf.theBuf[newTail], nToSend);
1015  }
1016
1017  return nToSend;
1018}
1019
1020/*
1021 * Send characters to device-specific code
1022 */
1023void
1024rtems_termios_puts (
1025  const void *_buf, size_t len, struct rtems_termios_tty *tty)
1026{
1027  const char *buf = _buf;
1028  unsigned int newHead;
1029  rtems_termios_device_context *ctx = tty->device_context;
1030  rtems_interrupt_lock_context lock_context;
1031  rtems_status_code sc;
1032
1033  if (tty->handler.mode == TERMIOS_POLLED) {
1034    (*tty->handler.write)(ctx, buf, len);
1035    return;
1036  }
1037
1038  while (len) {
1039    size_t nToCopy;
1040    size_t nAvail;
1041
1042    /* Check space for at least one char */
1043    newHead = tty->rawOutBuf.Head + 1;
1044    if (newHead >= tty->rawOutBuf.Size)
1045      newHead -= tty->rawOutBuf.Size;
1046
1047    rtems_termios_device_lock_acquire (ctx, &lock_context);
1048    while (newHead == tty->rawOutBuf.Tail) {
1049      tty->rawOutBufState = rob_wait;
1050      rtems_termios_device_lock_release (ctx, &lock_context);
1051      sc = rtems_semaphore_obtain(
1052        tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1053      if (sc != RTEMS_SUCCESSFUL)
1054        rtems_fatal_error_occurred (sc);
1055      rtems_termios_device_lock_acquire (ctx, &lock_context);
1056    }
1057
1058    /* Determine free space up to current tail or end of ring buffer */
1059    nToCopy = len;
1060    if (tty->rawOutBuf.Tail > tty->rawOutBuf.Head) {
1061      /* Available space is contiguous from Head to Tail */
1062      nAvail = tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1;
1063    } else {
1064      /* Available space wraps at buffer end. To keep it simple, utilize
1065         only the free space from Head to end during this iteration */
1066      nAvail = tty->rawOutBuf.Size - tty->rawOutBuf.Head;
1067      /* Head may not touch Tail after wraparound */
1068      if (tty->rawOutBuf.Tail == 0)
1069        nAvail--;
1070    }
1071    if (nToCopy > nAvail)
1072      nToCopy = nAvail;
1073
1074    /* To minimize latency, the memcpy could be done
1075     * with interrupts enabled or with limit on nToCopy (TBD)
1076     */
1077    memcpy(&tty->rawOutBuf.theBuf[tty->rawOutBuf.Head], buf, nToCopy);
1078
1079    newHead = tty->rawOutBuf.Head + nToCopy;
1080    if (newHead >= tty->rawOutBuf.Size)
1081      newHead -= tty->rawOutBuf.Size;
1082    tty->rawOutBuf.Head = newHead;
1083
1084    if (tty->rawOutBufState == rob_idle) {
1085      startXmit (tty, tty->rawOutBuf.Tail, false);
1086    }
1087
1088    rtems_termios_device_lock_release (ctx, &lock_context);
1089
1090    buf += nToCopy;
1091    len -= nToCopy;
1092  }
1093}
1094
1095/*
1096 * Handle output processing
1097 */
1098static void
1099oproc (unsigned char c, struct rtems_termios_tty *tty)
1100{
1101  int  i;
1102
1103  if (tty->termios.c_oflag & OPOST) {
1104    switch (c) {
1105    case '\n':
1106      if (tty->termios.c_oflag & ONLRET)
1107        tty->column = 0;
1108      if (tty->termios.c_oflag & ONLCR) {
1109        rtems_termios_puts ("\r", 1, tty);
1110        tty->column = 0;
1111      }
1112      break;
1113
1114    case '\r':
1115      if ((tty->termios.c_oflag & ONOCR) && (tty->column == 0))
1116        return;
1117      if (tty->termios.c_oflag & OCRNL) {
1118        c = '\n';
1119        if (tty->termios.c_oflag & ONLRET)
1120          tty->column = 0;
1121        break;
1122      }
1123      tty->column = 0;
1124      break;
1125
1126    case '\t':
1127      i = 8 - (tty->column & 7);
1128      if ((tty->termios.c_oflag & TABDLY) == XTABS) {
1129        tty->column += i;
1130        rtems_termios_puts ( "        ",  i, tty);
1131        return;
1132      }
1133      tty->column += i;
1134      break;
1135
1136    case '\b':
1137      if (tty->column > 0)
1138        tty->column--;
1139      break;
1140
1141    default:
1142      if (tty->termios.c_oflag & OLCUC)
1143        c = toupper(c);
1144      if (!iscntrl(c))
1145        tty->column++;
1146      break;
1147    }
1148  }
1149  rtems_termios_puts (&c, 1, tty);
1150}
1151
1152static uint32_t
1153rtems_termios_write_tty (struct rtems_termios_tty *tty, const char *buffer,
1154  uint32_t initial_count)
1155{
1156
1157  if (tty->termios.c_oflag & OPOST) {
1158    uint32_t count;
1159
1160    count = initial_count;
1161
1162    while (count--)
1163      oproc (*buffer++, tty);
1164  } else {
1165    rtems_termios_puts (buffer, initial_count, tty);
1166  }
1167
1168  return initial_count;
1169}
1170
1171rtems_status_code
1172rtems_termios_write (void *arg)
1173{
1174  rtems_libio_rw_args_t *args = arg;
1175  struct rtems_termios_tty *tty = args->iop->data1;
1176  rtems_status_code sc;
1177
1178  sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1179  if (sc != RTEMS_SUCCESSFUL)
1180    return sc;
1181  if (rtems_termios_linesw[tty->t_line].l_write != NULL) {
1182    sc = rtems_termios_linesw[tty->t_line].l_write(tty,args);
1183    rtems_semaphore_release (tty->osem);
1184    return sc;
1185  }
1186  args->bytes_moved = rtems_termios_write_tty (tty, args->buffer, args->count);
1187  rtems_semaphore_release (tty->osem);
1188  return sc;
1189}
1190
1191/*
1192 * Echo a typed character
1193 */
1194static void
1195echo (unsigned char c, struct rtems_termios_tty *tty)
1196{
1197  if ((tty->termios.c_lflag & ECHOCTL) &&
1198       iscntrl(c) && (c != '\t') && (c != '\n')) {
1199    char echobuf[2];
1200
1201    echobuf[0] = '^';
1202    echobuf[1] = c ^ 0x40;
1203    rtems_termios_puts (echobuf, 2, tty);
1204    tty->column += 2;
1205  } else {
1206    oproc (c, tty);
1207  }
1208}
1209
1210/*
1211 * Erase a character or line
1212 * FIXME: Needs support for WERASE and ECHOPRT.
1213 * FIXME: Some of the tests should check for IEXTEN, too.
1214 */
1215static void
1216erase (struct rtems_termios_tty *tty, int lineFlag)
1217{
1218  if (tty->ccount == 0)
1219    return;
1220  if (lineFlag) {
1221    if (!(tty->termios.c_lflag & ECHO)) {
1222      tty->ccount = 0;
1223      return;
1224    }
1225    if (!(tty->termios.c_lflag & ECHOE)) {
1226      tty->ccount = 0;
1227      echo (tty->termios.c_cc[VKILL], tty);
1228      if (tty->termios.c_lflag & ECHOK)
1229        echo ('\n', tty);
1230      return;
1231    }
1232  }
1233
1234  while (tty->ccount) {
1235    unsigned char c = tty->cbuf[--tty->ccount];
1236
1237    if (tty->termios.c_lflag & ECHO) {
1238      if (!lineFlag && !(tty->termios.c_lflag & ECHOE)) {
1239        echo (tty->termios.c_cc[VERASE], tty);
1240      } else if (c == '\t') {
1241        int col = tty->read_start_column;
1242        int i = 0;
1243
1244        /*
1245         * Find the character before the tab
1246         */
1247        while (i != tty->ccount) {
1248          c = tty->cbuf[i++];
1249          if (c == '\t') {
1250            col = (col | 7) + 1;
1251          } else if (iscntrl (c)) {
1252            if (tty->termios.c_lflag & ECHOCTL)
1253              col += 2;
1254          } else {
1255            col++;
1256          }
1257        }
1258
1259        /*
1260         * Back up over the tab
1261         */
1262        while (tty->column > col) {
1263          rtems_termios_puts ("\b", 1, tty);
1264          tty->column--;
1265        }
1266      }
1267      else {
1268        if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
1269          rtems_termios_puts ("\b \b", 3, tty);
1270          if (tty->column)
1271            tty->column--;
1272        }
1273        if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
1274          rtems_termios_puts ("\b \b", 3, tty);
1275          if (tty->column)
1276            tty->column--;
1277        }
1278      }
1279    }
1280    if (!lineFlag)
1281      break;
1282  }
1283}
1284
1285/*
1286 * Process a single input character
1287 */
1288static int
1289iproc (unsigned char c, struct rtems_termios_tty *tty)
1290{
1291  if (tty->termios.c_iflag & ISTRIP)
1292    c &= 0x7f;
1293
1294  if (tty->termios.c_iflag & IUCLC)
1295    c = tolower (c);
1296
1297  if (c == '\r') {
1298    if (tty->termios.c_iflag & IGNCR)
1299      return 0;
1300    if (tty->termios.c_iflag & ICRNL)
1301      c = '\n';
1302  } else if ((c == '\n') && (tty->termios.c_iflag & INLCR)) {
1303    c = '\r';
1304  }
1305
1306  if ((c != '\0') && (tty->termios.c_lflag & ICANON)) {
1307    if (c == tty->termios.c_cc[VERASE]) {
1308      erase (tty, 0);
1309      return 0;
1310    }
1311    else if (c == tty->termios.c_cc[VKILL]) {
1312      erase (tty, 1);
1313      return 0;
1314    }
1315    else if (c == tty->termios.c_cc[VEOF]) {
1316      return 1;
1317    } else if (c == '\n') {
1318      if (tty->termios.c_lflag & (ECHO | ECHONL))
1319        echo (c, tty);
1320      tty->cbuf[tty->ccount++] = c;
1321      return 1;
1322    } else if ((c == tty->termios.c_cc[VEOL]) ||
1323               (c == tty->termios.c_cc[VEOL2])) {
1324      if (tty->termios.c_lflag & ECHO)
1325        echo (c, tty);
1326      tty->cbuf[tty->ccount++] = c;
1327      return 1;
1328    }
1329  }
1330
1331  /*
1332   * FIXME: Should do IMAXBEL handling somehow
1333   */
1334  if (tty->ccount < (CBUFSIZE-1)) {
1335    if (tty->termios.c_lflag & ECHO)
1336      echo (c, tty);
1337    tty->cbuf[tty->ccount++] = c;
1338  }
1339  return 0;
1340}
1341
1342/*
1343 * Process input character, with semaphore.
1344 */
1345static int
1346siproc (unsigned char c, struct rtems_termios_tty *tty)
1347{
1348  int i;
1349
1350  /*
1351   * Obtain output semaphore if character will be echoed
1352   */
1353  if (tty->termios.c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ECHOPRT|ECHOCTL|ECHOKE)) {
1354    rtems_status_code sc;
1355    sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1356    if (sc != RTEMS_SUCCESSFUL)
1357      rtems_fatal_error_occurred (sc);
1358    i = iproc (c, tty);
1359    sc = rtems_semaphore_release (tty->osem);
1360    if (sc != RTEMS_SUCCESSFUL)
1361      rtems_fatal_error_occurred (sc);
1362  }
1363  else {
1364    i = iproc (c, tty);
1365  }
1366  return i;
1367}
1368
1369/*
1370 * Fill the input buffer by polling the device
1371 */
1372static rtems_status_code
1373fillBufferPoll (struct rtems_termios_tty *tty)
1374{
1375  int n;
1376
1377  if (tty->termios.c_lflag & ICANON) {
1378    for (;;) {
1379      n = (*tty->handler.poll_read)(tty->device_context);
1380      if (n < 0) {
1381        rtems_task_wake_after (1);
1382      } else {
1383        if  (siproc (n, tty))
1384          break;
1385      }
1386    }
1387  } else {
1388    rtems_interval then, now;
1389
1390    then = rtems_clock_get_ticks_since_boot();
1391    for (;;) {
1392      n = (*tty->handler.poll_read)(tty->device_context);
1393      if (n < 0) {
1394        if (tty->termios.c_cc[VMIN]) {
1395          if (tty->termios.c_cc[VTIME] && tty->ccount) {
1396            now = rtems_clock_get_ticks_since_boot();
1397            if ((now - then) > tty->vtimeTicks) {
1398              break;
1399            }
1400          }
1401        } else {
1402          if (!tty->termios.c_cc[VTIME])
1403            break;
1404          now = rtems_clock_get_ticks_since_boot();
1405          if ((now - then) > tty->vtimeTicks) {
1406            break;
1407          }
1408        }
1409        rtems_task_wake_after (1);
1410      } else {
1411        siproc (n, tty);
1412        if (tty->ccount >= tty->termios.c_cc[VMIN])
1413          break;
1414        if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
1415          then = rtems_clock_get_ticks_since_boot();
1416      }
1417    }
1418  }
1419  return RTEMS_SUCCESSFUL;
1420}
1421
1422/*
1423 * Fill the input buffer from the raw input queue
1424 */
1425static rtems_status_code
1426fillBufferQueue (struct rtems_termios_tty *tty)
1427{
1428  rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
1429  rtems_status_code sc;
1430  int               wait = 1;
1431
1432  while ( wait ) {
1433    /*
1434     * Process characters read from raw queue
1435     */
1436    while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
1437                       (tty->ccount < (CBUFSIZE-1))) {
1438      unsigned char c;
1439      unsigned int newHead;
1440
1441      newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
1442      c = tty->rawInBuf.theBuf[newHead];
1443      tty->rawInBuf.Head = newHead;
1444      if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
1445          % tty->rawInBuf.Size)
1446         < tty->lowwater) {
1447        tty->flow_ctrl &= ~FL_IREQXOF;
1448        /* if tx stopped and XON should be sent... */
1449        if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
1450             ==                (FL_MDXON | FL_ISNTXOF))
1451            && ((tty->rawOutBufState == rob_idle)
1452          || (tty->flow_ctrl & FL_OSTOP))) {
1453          /* XON should be sent now... */
1454          (*tty->handler.write)(
1455            tty->device_context, (void *)&(tty->termios.c_cc[VSTART]), 1);
1456        } else if (tty->flow_ctrl & FL_MDRTS) {
1457          tty->flow_ctrl &= ~FL_IRTSOFF;
1458          /* activate RTS line */
1459          if (tty->flow.start_remote_tx != NULL) {
1460            tty->flow.start_remote_tx(tty->device_context);
1461          }
1462        }
1463      }
1464
1465      /* continue processing new character */
1466      if (tty->termios.c_lflag & ICANON) {
1467        if (siproc (c, tty))
1468          wait = 0;
1469      } else {
1470        siproc (c, tty);
1471        if (tty->ccount >= tty->termios.c_cc[VMIN])
1472          wait = 0;
1473      }
1474      timeout = tty->rawInBufSemaphoreTimeout;
1475    }
1476
1477    /*
1478     * Wait for characters
1479     */
1480    if ( wait ) {
1481      sc = rtems_semaphore_obtain(
1482        tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout);
1483      if (sc != RTEMS_SUCCESSFUL)
1484        break;
1485    }
1486  }
1487  return RTEMS_SUCCESSFUL;
1488}
1489
1490static uint32_t
1491rtems_termios_read_tty (struct rtems_termios_tty *tty, char *buffer,
1492  uint32_t initial_count)
1493{
1494  uint32_t count;
1495
1496  count = initial_count;
1497
1498  if (tty->cindex == tty->ccount) {
1499    rtems_status_code sc;
1500
1501    tty->cindex = tty->ccount = 0;
1502    tty->read_start_column = tty->column;
1503    if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
1504      sc = fillBufferPoll (tty);
1505    else
1506      sc = fillBufferQueue (tty);
1507
1508    if (sc != RTEMS_SUCCESSFUL)
1509      tty->cindex = tty->ccount = 0;
1510  }
1511  while (count && (tty->cindex < tty->ccount)) {
1512    *buffer++ = tty->cbuf[tty->cindex++];
1513    count--;
1514  }
1515  tty->tty_rcvwakeup = 0;
1516  return initial_count - count;
1517}
1518
1519rtems_status_code
1520rtems_termios_read (void *arg)
1521{
1522  rtems_libio_rw_args_t *args = arg;
1523  struct rtems_termios_tty *tty = args->iop->data1;
1524  rtems_status_code sc;
1525
1526  sc = rtems_semaphore_obtain (tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1527  if (sc != RTEMS_SUCCESSFUL)
1528    return sc;
1529
1530  if (rtems_termios_linesw[tty->t_line].l_read != NULL) {
1531    sc = rtems_termios_linesw[tty->t_line].l_read(tty,args);
1532    tty->tty_rcvwakeup = 0;
1533    rtems_semaphore_release (tty->isem);
1534    return sc;
1535  }
1536
1537  args->bytes_moved = rtems_termios_read_tty (tty, args->buffer, args->count);
1538  rtems_semaphore_release (tty->isem);
1539  return sc;
1540}
1541
1542/*
1543 * signal receive interrupt to rx daemon
1544 * NOTE: This routine runs in the context of the
1545 *       device receive interrupt handler.
1546 */
1547void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
1548{
1549  /*
1550   * send event to rx daemon task
1551   */
1552  rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
1553}
1554
1555/*
1556 * Place characters on raw queue.
1557 * NOTE: This routine runs in the context of the
1558 *       device receive interrupt handler.
1559 * Returns the number of characters dropped because of overflow.
1560 */
1561int
1562rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
1563{
1564  struct rtems_termios_tty *tty = ttyp;
1565  unsigned int newTail;
1566  char c;
1567  int dropped = 0;
1568  bool flow_rcv = false; /* true, if flow control char received */
1569  rtems_termios_device_context *ctx = tty->device_context;
1570  rtems_interrupt_lock_context lock_context;
1571
1572  if (rtems_termios_linesw[tty->t_line].l_rint != NULL) {
1573    while (len--) {
1574      c = *buf++;
1575      rtems_termios_linesw[tty->t_line].l_rint(c,tty);
1576    }
1577
1578    /*
1579     * check to see if rcv wakeup callback was set
1580     */
1581    if (( !tty->tty_rcvwakeup ) && ( tty->tty_rcv.sw_pfn != NULL )) {
1582      (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
1583      tty->tty_rcvwakeup = 1;
1584        }
1585    return 0;
1586  }
1587
1588  while (len--) {
1589    c = *buf++;
1590    /* FIXME: implement IXANY: any character restarts output */
1591    /* if incoming XON/XOFF controls outgoing stream: */
1592    if (tty->flow_ctrl & FL_MDXON) {
1593      /* if received char is V_STOP and V_START (both are equal value) */
1594      if (c == tty->termios.c_cc[VSTOP]) {
1595        if (c == tty->termios.c_cc[VSTART]) {
1596          /* received VSTOP and VSTART==VSTOP? */
1597          /* then toggle "stop output" status  */
1598          tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
1599        }
1600        else {
1601          /* VSTOP received (other code than VSTART) */
1602          /* stop output                             */
1603          tty->flow_ctrl |= FL_ORCVXOF;
1604        }
1605        flow_rcv = true;
1606      }
1607      else if (c == tty->termios.c_cc[VSTART]) {
1608        /* VSTART received */
1609        /* restart output  */
1610        tty->flow_ctrl &= ~FL_ORCVXOF;
1611        flow_rcv = true;
1612      }
1613    }
1614    if (flow_rcv) {
1615      /* restart output according to FL_ORCVXOF flag */
1616      if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
1617        /* disable interrupts    */
1618        rtems_termios_device_lock_acquire (ctx, &lock_context);
1619        tty->flow_ctrl &= ~FL_OSTOP;
1620        /* check for chars in output buffer (or rob_state?) */
1621        if (tty->rawOutBufState != rob_idle) {
1622          /* if chars available, call write function... */
1623          (*tty->handler.write)(
1624            ctx, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
1625        }
1626        /* reenable interrupts */
1627        rtems_termios_device_lock_release (ctx, &lock_context);
1628      }
1629    } else {
1630      newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
1631      /* if chars_in_buffer > highwater                */
1632      rtems_termios_device_lock_acquire (ctx, &lock_context);
1633      if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
1634            % tty->rawInBuf.Size) > tty->highwater) &&
1635          !(tty->flow_ctrl & FL_IREQXOF)) {
1636        /* incoming data stream should be stopped */
1637        tty->flow_ctrl |= FL_IREQXOF;
1638        if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
1639            ==                (FL_MDXOF             ) ) {
1640          if ((tty->flow_ctrl & FL_OSTOP) ||
1641              (tty->rawOutBufState == rob_idle)) {
1642            /* if tx is stopped due to XOFF or out of data */
1643            /*    call write function here                 */
1644            tty->flow_ctrl |= FL_ISNTXOF;
1645            (*tty->handler.write)(ctx,
1646                (void *)&(tty->termios.c_cc[VSTOP]), 1);
1647          }
1648        } else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) == (FL_MDRTS) ) {
1649          tty->flow_ctrl |= FL_IRTSOFF;
1650          /* deactivate RTS line */
1651          if (tty->flow.stop_remote_tx != NULL) {
1652            tty->flow.stop_remote_tx(ctx);
1653          }
1654        }
1655      }
1656
1657      /* reenable interrupts */
1658      rtems_termios_device_lock_release (ctx, &lock_context);
1659
1660      if (newTail == tty->rawInBuf.Head) {
1661        dropped++;
1662      } else {
1663        tty->rawInBuf.theBuf[newTail] = c;
1664        tty->rawInBuf.Tail = newTail;
1665
1666        /*
1667         * check to see if rcv wakeup callback was set
1668         */
1669        if (( !tty->tty_rcvwakeup ) && ( tty->tty_rcv.sw_pfn != NULL )) {
1670          (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
1671          tty->tty_rcvwakeup = 1;
1672        }
1673      }
1674    }
1675  }
1676
1677  tty->rawInBufDropped += dropped;
1678  rtems_semaphore_release (tty->rawInBuf.Semaphore);
1679  return dropped;
1680}
1681
1682/*
1683 * in task-driven mode, this function is called in Tx task context
1684 * in interrupt-driven mode, this function is called in TxIRQ context
1685 */
1686static int
1687rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
1688{
1689  bool wakeUpWriterTask = false;
1690  unsigned int newTail;
1691  int nToSend;
1692  rtems_termios_device_context *ctx = tty->device_context;
1693  rtems_interrupt_lock_context lock_context;
1694  int len;
1695
1696  rtems_termios_device_lock_acquire (ctx, &lock_context);
1697
1698  /* check for XOF/XON to send */
1699  if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
1700      == (FL_MDXOF | FL_IREQXOF)) {
1701    /* XOFF should be sent now... */
1702    (*tty->handler.write)(ctx, (void *)&(tty->termios.c_cc[VSTOP]), 1);
1703
1704    tty->t_dqlen--;
1705    tty->flow_ctrl |= FL_ISNTXOF;
1706
1707    nToSend = 1;
1708
1709  } else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) == FL_ISNTXOF) {
1710    /* NOTE: send XON even, if no longer in XON/XOFF mode... */
1711    /* XON should be sent now... */
1712    /*
1713     * FIXME: this .write call will generate another
1714     * dequeue callback. This will advance the "Tail" in the data
1715     * buffer, although the corresponding data is not yet out!
1716     * Therefore the dequeue "length" should be reduced by 1
1717     */
1718    (*tty->handler.write)(ctx, (void *)&(tty->termios.c_cc[VSTART]), 1);
1719
1720    tty->t_dqlen--;
1721    tty->flow_ctrl &= ~FL_ISNTXOF;
1722
1723    nToSend = 1;
1724  } else if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
1725    /*
1726     * buffer was empty
1727     */
1728    if (tty->rawOutBufState == rob_wait) {
1729      /*
1730       * this should never happen...
1731       */
1732      wakeUpWriterTask = true;
1733    }
1734
1735    (*tty->handler.write) (ctx, NULL, 0);
1736    nToSend = 0;
1737  } else {
1738    len = tty->t_dqlen;
1739    tty->t_dqlen = 0;
1740
1741    newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
1742    tty->rawOutBuf.Tail = newTail;
1743    if (tty->rawOutBufState == rob_wait) {
1744      /*
1745       * wake up any pending writer task
1746       */
1747      wakeUpWriterTask = true;
1748    }
1749
1750    if (newTail == tty->rawOutBuf.Head) {
1751      /*
1752       * Buffer has become empty
1753       */
1754      tty->rawOutBufState = rob_idle;
1755      (*tty->handler.write) (ctx, NULL, 0);
1756      nToSend = 0;
1757
1758      /*
1759       * check to see if snd wakeup callback was set
1760       */
1761      if ( tty->tty_snd.sw_pfn != NULL) {
1762        (*tty->tty_snd.sw_pfn)(&tty->termios, tty->tty_snd.sw_arg);
1763      }
1764    } else {
1765      /*
1766       * Buffer not empty, check flow control, start transmitter
1767       */
1768      nToSend = startXmit (tty, newTail, true);
1769    }
1770  }
1771
1772  rtems_termios_device_lock_release (ctx, &lock_context);
1773
1774  if (wakeUpWriterTask) {
1775    rtems_semaphore_release (tty->rawOutBuf.Semaphore);
1776  }
1777
1778  return nToSend;
1779}
1780
1781/*
1782 * Characters have been transmitted
1783 * NOTE: This routine runs in the context of the
1784 *       device transmit interrupt handler.
1785 * The second argument is the number of characters transmitted so far.
1786 * This value will always be 1 for devices which generate an interrupt
1787 * for each transmitted character.
1788 * It returns number of characters left to transmit
1789 */
1790int
1791rtems_termios_dequeue_characters (void *ttyp, int len)
1792{
1793  struct rtems_termios_tty *tty = ttyp;
1794  rtems_status_code sc;
1795
1796  /*
1797   * sum up character count already sent
1798   */
1799  tty->t_dqlen += len;
1800
1801  if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
1802    /*
1803     * send wake up to transmitter task
1804     */
1805    sc = rtems_event_send(tty->txTaskId, TERMIOS_TX_START_EVENT);
1806    if (sc != RTEMS_SUCCESSFUL)
1807      rtems_fatal_error_occurred (sc);
1808    return 0; /* nothing to output in IRQ... */
1809  }
1810
1811  if (tty->t_line == PPPDISC ) {
1812    /*
1813     * call PPP line discipline start function
1814     */
1815    if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
1816      rtems_termios_linesw[tty->t_line].l_start(tty);
1817    }
1818    return 0; /* nothing to output in IRQ... */
1819  }
1820
1821  return rtems_termios_refill_transmitter(tty);
1822}
1823
1824/*
1825 * this task actually processes any transmit events
1826 */
1827static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
1828{
1829  struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1830  rtems_event_set the_event;
1831
1832  while (1) {
1833    /*
1834     * wait for rtems event
1835     */
1836    rtems_event_receive(
1837       (TERMIOS_TX_START_EVENT | TERMIOS_TX_TERMINATE_EVENT),
1838       RTEMS_EVENT_ANY | RTEMS_WAIT,
1839       RTEMS_NO_TIMEOUT,
1840       &the_event
1841    );
1842    if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
1843      tty->txTaskId = 0;
1844      rtems_task_delete(RTEMS_SELF);
1845    }
1846
1847    /*
1848     * call any line discipline start function
1849     */
1850    if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
1851      rtems_termios_linesw[tty->t_line].l_start(tty);
1852
1853      if (tty->t_line == PPPDISC) {
1854        /*
1855         * Do not call rtems_termios_refill_transmitter() in this case similar
1856         * to rtems_termios_dequeue_characters().
1857         */
1858        continue;
1859      }
1860    }
1861
1862    /*
1863     * try to push further characters to device
1864     */
1865    rtems_termios_refill_transmitter(tty);
1866  }
1867}
1868
1869/*
1870 * this task actually processes any receive events
1871 */
1872static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
1873{
1874  struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1875  rtems_termios_device_context *ctx = tty->device_context;
1876  rtems_event_set the_event;
1877  int c;
1878  char c_buf;
1879
1880  while (1) {
1881    /*
1882     * wait for rtems event
1883     */
1884    rtems_event_receive(
1885      (TERMIOS_RX_PROC_EVENT | TERMIOS_RX_TERMINATE_EVENT),
1886      RTEMS_EVENT_ANY | RTEMS_WAIT,
1887      RTEMS_NO_TIMEOUT,
1888      &the_event
1889    );
1890    if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
1891      tty->rxTaskId = 0;
1892      rtems_task_delete(RTEMS_SELF);
1893    }
1894
1895    /*
1896     * do something
1897     */
1898    c = tty->handler.poll_read(ctx);
1899    if (c != EOF) {
1900      /*
1901       * poll_read did call enqueue on its own
1902       */
1903      c_buf = c;
1904      rtems_termios_enqueue_raw_characters ( tty,&c_buf,1);
1905    }
1906  }
1907}
1908
1909static int
1910rtems_termios_imfs_open (rtems_libio_t *iop,
1911  const char *path, int oflag, mode_t mode)
1912{
1913  rtems_termios_device_node *device_node;
1914  rtems_status_code sc;
1915  rtems_libio_open_close_args_t args;
1916  struct rtems_termios_tty *tty;
1917
1918  device_node = IMFS_generic_get_context_by_iop (iop);
1919
1920  memset (&args, 0, sizeof (args));
1921  args.iop = iop;
1922  args.flags = iop->flags;
1923  args.mode = mode;
1924
1925  sc = rtems_termios_obtain ();
1926  if (sc != RTEMS_SUCCESSFUL) {
1927    rtems_set_errno_and_return_minus_one (ENXIO);
1928  }
1929
1930  tty = rtems_termios_open_tty (device_node->major, device_node->minor, &args,
1931      device_node->tty, device_node, NULL);
1932  if (tty == NULL) {
1933    rtems_termios_release ();
1934    rtems_set_errno_and_return_minus_one (ENOMEM);
1935  }
1936
1937  rtems_termios_release ();
1938  return 0;
1939}
1940
1941static int
1942rtems_termios_imfs_close (rtems_libio_t *iop)
1943{
1944  rtems_status_code sc;
1945  rtems_libio_open_close_args_t args;
1946  struct rtems_termios_tty *tty;
1947
1948  memset (&args, 0, sizeof (args));
1949  args.iop = iop;
1950
1951  tty = iop->data1;
1952
1953  sc = rtems_termios_obtain ();
1954  _Assert (sc == RTEMS_SUCCESSFUL);
1955  (void) sc;
1956
1957  rtems_termios_close_tty (tty, &args);
1958  rtems_termios_release ();
1959  return 0;
1960}
1961
1962static ssize_t
1963rtems_termios_imfs_read (rtems_libio_t *iop, void *buffer, size_t count)
1964{
1965  struct rtems_termios_tty *tty;
1966  rtems_status_code sc;
1967  uint32_t bytes_moved;
1968
1969  tty = iop->data1;
1970
1971  sc = rtems_semaphore_obtain (tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1972  _Assert (sc == RTEMS_SUCCESSFUL);
1973
1974  if (rtems_termios_linesw[tty->t_line].l_read != NULL) {
1975    rtems_libio_rw_args_t args;
1976
1977    memset (&args, 0, sizeof (args));
1978    args.iop = iop;
1979    args.buffer = buffer;
1980    args.count = count;
1981    args.flags = iop->flags;
1982
1983    sc = rtems_termios_linesw[tty->t_line].l_read (tty, &args);
1984    tty->tty_rcvwakeup = 0;
1985    rtems_semaphore_release (tty->isem);
1986
1987    if (sc != RTEMS_SUCCESSFUL) {
1988      return rtems_status_code_to_errno (sc);
1989    }
1990
1991    return (ssize_t) args.bytes_moved;
1992  }
1993
1994  bytes_moved = rtems_termios_read_tty (tty, buffer, count);
1995  rtems_semaphore_release (tty->isem);
1996  return (ssize_t) bytes_moved;
1997}
1998
1999static ssize_t
2000rtems_termios_imfs_write (rtems_libio_t *iop, const void *buffer, size_t count)
2001{
2002  struct rtems_termios_tty *tty;
2003  rtems_status_code sc;
2004  uint32_t bytes_moved;
2005
2006  tty = iop->data1;
2007
2008  sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
2009  _Assert (sc == RTEMS_SUCCESSFUL);
2010
2011  if (rtems_termios_linesw[tty->t_line].l_write != NULL) {
2012    rtems_libio_rw_args_t args;
2013
2014    memset (&args, 0, sizeof (args));
2015    args.iop = iop;
2016    args.buffer = RTEMS_DECONST (void *, buffer);
2017    args.count = count;
2018    args.flags = iop->flags;
2019
2020    sc = rtems_termios_linesw[tty->t_line].l_write (tty, &args);
2021    rtems_semaphore_release (tty->osem);
2022
2023    if (sc != RTEMS_SUCCESSFUL) {
2024      return rtems_status_code_to_errno (sc);
2025    }
2026
2027    return (ssize_t) args.bytes_moved;
2028  }
2029
2030  bytes_moved = rtems_termios_write_tty (tty, buffer, count);
2031  rtems_semaphore_release (tty->osem);
2032  return (ssize_t) bytes_moved;
2033}
2034
2035static int
2036rtems_termios_imfs_ioctl (rtems_libio_t *iop, uint32_t request, void *buffer)
2037{
2038  rtems_status_code sc;
2039  rtems_libio_ioctl_args_t args;
2040
2041  memset (&args, 0, sizeof (args));
2042  args.iop = iop;
2043  args.command = request;
2044  args.buffer = buffer;
2045
2046  sc = rtems_termios_ioctl (&args);
2047  if ( sc == RTEMS_SUCCESSFUL ) {
2048    return args.ioctl_return;
2049  } else {
2050    return rtems_status_code_to_errno (sc);
2051  }
2052}
2053
2054static const rtems_filesystem_file_handlers_r rtems_termios_imfs_handler = {
2055  .open_h = rtems_termios_imfs_open,
2056  .close_h = rtems_termios_imfs_close,
2057  .read_h = rtems_termios_imfs_read,
2058  .write_h = rtems_termios_imfs_write,
2059  .ioctl_h = rtems_termios_imfs_ioctl,
2060  .lseek_h = rtems_filesystem_default_lseek,
2061  .fstat_h = IMFS_stat,
2062  .ftruncate_h = rtems_filesystem_default_ftruncate,
2063  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
2064  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
2065  .fcntl_h = rtems_filesystem_default_fcntl,
2066  .kqfilter_h = rtems_filesystem_default_kqfilter,
2067  .poll_h = rtems_filesystem_default_poll,
2068  .readv_h = rtems_filesystem_default_readv,
2069  .writev_h = rtems_filesystem_default_writev
2070};
2071
2072static IMFS_jnode_t *
2073rtems_termios_imfs_node_initialize (IMFS_jnode_t *node, void *arg)
2074{
2075  rtems_termios_device_node *device_node;
2076  dev_t dev;
2077
2078  node = IMFS_node_initialize_generic (node, arg);
2079  device_node = IMFS_generic_get_context_by_node (node);
2080  dev = IMFS_generic_get_device_identifier_by_node (node);
2081  device_node->major = rtems_filesystem_dev_major_t (dev);
2082  device_node->minor = rtems_filesystem_dev_minor_t (dev);
2083
2084  return node;
2085}
2086
2087static void
2088rtems_termios_imfs_node_destroy (IMFS_jnode_t *node)
2089{
2090  rtems_termios_device_node *device_node;
2091
2092  device_node = IMFS_generic_get_context_by_node (node);
2093  free (device_node);
2094  IMFS_node_destroy_default (node);
2095}
2096
2097static const IMFS_node_control rtems_termios_imfs_node_control =
2098  IMFS_GENERIC_INITIALIZER(
2099    &rtems_termios_imfs_handler,
2100    rtems_termios_imfs_node_initialize,
2101    rtems_termios_imfs_node_destroy
2102  );
Note: See TracBrowser for help on using the repository browser.