source: rtems/c/src/lib/libc/termios.c @ db4aaf8

4.104.114.84.95
Last change on this file since db4aaf8 was 4dc0fd6, checked in by Joel Sherrill <joel.sherrill@…>, on 01/19/98 at 22:22:25

Patch from Eric Norum:

With this in place, it is possible to fdopen a TCP stream socket and
getc/fprintf/etc. on the STDIO stream!

  • Property mode set to 100644
File size: 20.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.OARcorp.com/rtems/license.html.
14 *
15 *  $Id$
16 */
17
18#include <rtems.h>
19#include <rtems/libio.h>
20#include <ctype.h>
21#include <errno.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <termios.h>
25#include <unistd.h>
26
27/*
28 * The size of the cooked buffer
29 */
30#define CBUFSIZE        256
31
32/*
33 * The sizes of the raw message buffers.
34 * On most architectures it is quite a bit more
35 * efficient if these are powers of two.
36 */
37#define RAW_INPUT_BUFFER_SIZE   128
38#define RAW_OUTPUT_BUFFER_SIZE  64
39
40/*
41 * Variables associated with each termios instance.
42 * One structure for each hardware I/O device.
43 */
44struct rtems_termios_tty {
45        /*
46         * Linked-list of active TERMIOS devices
47         */
48        struct rtems_termios_tty        *forw;
49        struct rtems_termios_tty        *back;
50
51        /*
52         * How many times has this device been opened
53         */
54        int             refcount;
55
56        /*
57         * This device
58         */
59        rtems_device_major_number       major;
60        rtems_device_major_number       minor;
61
62        /*
63         * Mutual-exclusion semaphores
64         */
65        rtems_id        isem;
66        rtems_id        osem;
67
68        /*
69         * The canonical (cooked) character buffer
70         */
71        char            cbuf[CBUFSIZE];
72        int             ccount;
73        int             cindex;
74
75        /*
76         * Keep track of cursor (printhead) position
77         */
78        int             column;
79        int             read_start_column;
80
81        /*
82         * The ioctl settings
83         */
84        struct termios  termios;
85        rtems_interval  vtimeTicks;
86
87        /*
88         * Raw input character buffer
89         */
90        volatile char           rawInBuf[RAW_INPUT_BUFFER_SIZE];
91        volatile unsigned int   rawInBufHead;
92        volatile unsigned int   rawInBufTail;
93        rtems_id                rawInBufSemaphore;
94        rtems_unsigned32        rawInBufSemaphoreOptions;
95        rtems_interval          rawInBufSemaphoreTimeout;
96        rtems_interval          rawInBufSemaphoreFirstTimeout;
97        unsigned int            rawInBufDropped;        /* Statistics */
98
99        /*
100         * Raw output character buffer
101         */
102        char                    outputUsesInterrupts;
103        volatile char           rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
104        volatile unsigned int   rawOutBufHead;
105        volatile unsigned int   rawOutBufTail;
106        rtems_id                rawOutBufSemaphore;
107        enum {rob_idle, rob_busy, rob_wait }    rawOutBufState;
108
109        /*
110         * Callbacks to device-specific routines
111         */
112        int             (*lastClose)(int major, int minor, void *arg);
113        int             (*read)(int minor);
114        int             (*write)(int minor, const char *buf, int len);
115};
116
117static struct rtems_termios_tty *ttyHead, *ttyTail;
118static rtems_id ttyMutex;
119
120/*
121 *  Reserve enough resources to open every physical device once.
122 */
123
124static int first_time;   /* assumed to be zeroed by BSS initialization */
125
126void
127rtems_termios_reserve_resources (
128  rtems_configuration_table *configuration,
129  rtems_unsigned32           number_of_devices
130  )
131{
132        rtems_api_configuration_table *rtems_config;
133
134        if (!configuration)
135                rtems_fatal_error_occurred (0xFFF0F001);
136        rtems_config = configuration->RTEMS_api_configuration;
137        if (!rtems_config)
138                rtems_fatal_error_occurred (0xFFF0F002);
139        if (!first_time)
140                rtems_config->maximum_semaphores += 1;
141        first_time = 1;
142        rtems_config->maximum_semaphores += (4 * number_of_devices);
143}
144
145void
146rtems_termios_initialize (void)
147{
148        rtems_status_code sc;
149
150        /*
151         * Create the mutex semaphore for the tty list
152         */
153        if (!ttyMutex) {
154                sc = rtems_semaphore_create (
155                        rtems_build_name ('T', 'R', 'm', 'i'),
156                        1,
157                        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
158                        RTEMS_NO_PRIORITY,
159                        &ttyMutex);
160                if (sc != RTEMS_SUCCESSFUL)
161                        rtems_fatal_error_occurred (sc);
162        }
163}
164       
165/*
166 * Open a termios device
167 */
168rtems_status_code
169rtems_termios_open (
170  rtems_device_major_number  major,
171  rtems_device_minor_number  minor,
172  void                      *arg,
173  int                      (*deviceFirstOpen)(int major, int minor, void *arg),
174  int                      (*deviceLastClose)(int major, int minor, void *arg),
175  int                      (*deviceRead)(int minor),
176  int                      (*deviceWrite)(int minor, const char *buf, int len),
177  int                        deviceOutputUsesInterrupts
178  )
179{
180        rtems_status_code sc;
181        rtems_libio_open_close_args_t *args = arg;
182        struct rtems_termios_tty *tty;
183
184        /*
185         * See if the device has already been opened
186         */
187        sc = rtems_semaphore_obtain (ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
188        if (sc != RTEMS_SUCCESSFUL)
189                return sc;
190        for (tty = ttyHead ; tty != NULL ; tty = tty->forw) {
191                if ((tty->major == major) && (tty->minor == minor))
192                        break;
193        }
194        if (tty == NULL) {
195                static char c = 'a';
196
197                /*
198                 * Create a new device
199                 */
200                tty = malloc (sizeof (struct rtems_termios_tty));
201                if (tty == NULL) {
202                        rtems_semaphore_release (ttyMutex);
203                        return RTEMS_NO_MEMORY;
204                }
205                tty->forw = ttyHead;
206                ttyHead = tty;
207                tty->back = NULL;
208                if (ttyTail == NULL)
209                        ttyTail = tty;
210
211                tty->minor = minor;
212                tty->major = major;
213
214                /*
215                 * Set up mutex semaphores
216                 */
217                sc = rtems_semaphore_create (
218                        rtems_build_name ('T', 'R', 'i', c),
219                        1,
220                        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
221                        RTEMS_NO_PRIORITY,
222                        &tty->isem);
223                if (sc != RTEMS_SUCCESSFUL)
224                        rtems_fatal_error_occurred (sc);
225                sc = rtems_semaphore_create (
226                        rtems_build_name ('T', 'R', 'o', c),
227                        1,
228                        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
229                        RTEMS_NO_PRIORITY,
230                        &tty->osem);
231                if (sc != RTEMS_SUCCESSFUL)
232                        rtems_fatal_error_occurred (sc);
233                sc = rtems_semaphore_create (
234                        rtems_build_name ('T', 'R', 'x', c),
235                        0,
236                        RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
237                        RTEMS_NO_PRIORITY,
238                        &tty->rawOutBufSemaphore);
239                if (sc != RTEMS_SUCCESSFUL)
240                        rtems_fatal_error_occurred (sc);
241                tty->rawOutBufHead = 0;
242                tty->rawOutBufTail = 0;
243
244                /*
245                 * Set callbacks
246                 */
247                tty->write = deviceWrite;
248                tty->lastClose = deviceLastClose;
249                if ((tty->read = deviceRead) == NULL) {
250                        sc = rtems_semaphore_create (
251                                rtems_build_name ('T', 'R', 'r', c),
252                                0,
253                                RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
254                                RTEMS_NO_PRIORITY,
255                                &tty->rawInBufSemaphore);
256                        if (sc != RTEMS_SUCCESSFUL)
257                                rtems_fatal_error_occurred (sc);
258                        tty->rawInBufHead = 0;
259                        tty->rawInBufTail = 0;
260                }
261
262                /*
263                 * Initialize variables
264                 */
265                tty->column = 0;
266                tty->cindex = tty->ccount = 0;
267                tty->outputUsesInterrupts = deviceOutputUsesInterrupts;
268
269                /*
270                 * Set default parameters
271                 */
272                tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;
273                tty->termios.c_oflag = OPOST | ONLCR | XTABS;
274                tty->termios.c_cflag = B9600 | CS8 | CREAD;
275                tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
276                tty->termios.c_cc[VINTR] = '\003';
277                tty->termios.c_cc[VQUIT] = '\034';
278                tty->termios.c_cc[VERASE] = '\177';
279                tty->termios.c_cc[VKILL] = '\025';
280                tty->termios.c_cc[VEOF] = '\004';
281                tty->termios.c_cc[VEOL] = '\000';
282                tty->termios.c_cc[VEOL2] = '\000';
283                tty->termios.c_cc[VSTART] = '\021';
284                tty->termios.c_cc[VSTOP] = '\023';
285                tty->termios.c_cc[VSUSP] = '\032';
286                tty->termios.c_cc[VREPRINT] = '\022';
287                tty->termios.c_cc[VDISCARD] = '\017';
288                tty->termios.c_cc[VWERASE] = '\027';
289                tty->termios.c_cc[VLNEXT] = '\026';
290
291                /*
292                 * Device-specific open
293                 */
294                if (deviceFirstOpen)
295                        (*deviceFirstOpen) (major, minor, arg);
296
297                /*
298                 * Bump name characer
299                 */
300                if (c++ == 'z')
301                        c = 'a';
302        }
303        tty->refcount++;
304        args->iop->data1 = tty;
305        rtems_semaphore_release (ttyMutex);
306        return RTEMS_SUCCESSFUL;
307}
308
309rtems_status_code
310rtems_termios_close (void *arg)
311{
312        rtems_libio_open_close_args_t *args = arg;
313        struct rtems_termios_tty *tty = args->iop->data1;
314        rtems_status_code sc;
315
316        sc = rtems_semaphore_obtain (ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
317        if (sc != RTEMS_SUCCESSFUL)
318                rtems_fatal_error_occurred (sc);
319        if (--tty->refcount == 0) {
320                if (tty->lastClose)
321                         (*tty->lastClose) (tty->major, tty->minor, arg);
322                if (tty->forw == NULL)
323                        ttyTail = tty->back;
324                else
325                        tty->forw->back = tty->back;
326                if (tty->back == NULL)
327                        ttyHead = tty->forw;
328                else
329                        tty->back->forw = tty->forw;
330                rtems_semaphore_delete (tty->isem);
331                rtems_semaphore_delete (tty->osem);
332                rtems_semaphore_delete (tty->rawOutBufSemaphore);
333                if (tty->read == NULL)
334                        rtems_semaphore_delete (tty->rawInBufSemaphore);
335                free (tty);
336        }
337        rtems_semaphore_release (ttyMutex);
338        return RTEMS_SUCCESSFUL;
339}
340
341rtems_status_code
342rtems_termios_ioctl (void *arg)
343{
344        rtems_libio_ioctl_args_t *args = arg;
345        struct rtems_termios_tty *tty = args->iop->data1;
346        rtems_status_code sc;
347
348        args->ioctl_return = 0;
349        sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
350        if (sc != RTEMS_SUCCESSFUL) {
351                args->ioctl_return = sc;
352                return sc;
353        }
354        switch (args->command) {
355        default:
356                sc = RTEMS_INVALID_NUMBER;
357                break;
358
359        case RTEMS_IO_GET_ATTRIBUTES:
360                *(struct termios *)args->buffer = tty->termios;
361                break;
362
363        case RTEMS_IO_SET_ATTRIBUTES:
364                tty->termios = *(struct termios *)args->buffer;
365                if (tty->termios.c_lflag & ICANON) {
366                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
367                        tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
368                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
369                }
370                else {
371                        rtems_interval ticksPerSecond;
372                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond);
373                        tty->vtimeTicks = tty->termios.c_cc[VTIME] * ticksPerSecond / 10;
374                        if (tty->termios.c_cc[VTIME]) {
375                                tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
376                                tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
377                                if (tty->termios.c_cc[VMIN])
378                                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
379                                else
380                                        tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
381                        }
382                        else {
383                                if (tty->termios.c_cc[VMIN]) {
384                                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
385                                        tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
386                                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
387                                }
388                                else {
389                                        tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
390                                }
391                        }
392                }
393                break;
394        }
395        rtems_semaphore_release (tty->osem);
396        args->ioctl_return = sc;
397        return sc;
398}
399
400/*
401 * Send characters to device-specific code
402 */
403static void
404osend (const char *buf, int len, struct rtems_termios_tty *tty)
405{
406        unsigned int newHead;
407        rtems_interrupt_level level;
408        rtems_status_code sc;
409
410        if (!tty->outputUsesInterrupts) {
411                (*tty->write)(tty->minor, buf, len);
412                return;
413        }
414        newHead = tty->rawOutBufHead;
415        while (len) {
416                /*
417                 * Performance improvement could be made here.
418                 * Copy multiple bytes to raw buffer:
419                 * if (len > 1) && (space to buffer end, or tail > 1)
420                 *      ncopy = MIN (len, space to buffer end or tail)
421                 *      memcpy (raw buffer, buf, ncopy)
422                 *      buf += ncopy
423                 *      len -= ncopy
424                 *
425                 * To minimize latency, the memcpy should be done
426                 * with interrupts enabled.
427                 */
428                newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
429                rtems_interrupt_disable (level);
430                while (newHead == tty->rawOutBufTail) {
431                        tty->rawOutBufState = rob_wait;
432                        rtems_interrupt_enable (level);
433                        sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
434                                                        RTEMS_WAIT,
435                                                        RTEMS_NO_TIMEOUT);
436                        if (sc != RTEMS_SUCCESSFUL)
437                                rtems_fatal_error_occurred (sc);
438                        rtems_interrupt_disable (level);
439                }
440                tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
441                tty->rawOutBufHead = newHead;
442                if (tty->rawOutBufState == rob_idle) {
443                        rtems_interrupt_enable (level);
444                        tty->rawOutBufState = rob_busy;
445                        (*tty->write)(tty->minor, (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
446                }
447                else {
448                        rtems_interrupt_enable (level);
449                }
450                len--;
451        }
452}
453
454/*
455 * Handle output processing
456 */
457static void
458oproc (unsigned char c, struct rtems_termios_tty *tty)
459{
460        int     i;
461
462        if (tty->termios.c_oflag & OPOST) {
463                switch (c) {
464                case '\n':
465                        if (tty->termios.c_oflag & ONLRET)
466                                tty->column = 0;
467                        if (tty->termios.c_oflag & ONLCR) {
468                                osend ("\r", 1, tty);
469                                tty->column = 0;
470                        }
471                        break;
472
473                case '\r':
474                        if ((tty->termios.c_oflag & ONOCR) && (tty->column == 0))
475                                return;
476                        if (tty->termios.c_oflag & OCRNL) {
477                                c = '\n';
478                                if (tty->termios.c_oflag & ONLRET)
479                                        tty->column = 0;
480                                break;
481                        }
482                        tty->column = 0;
483                        break;
484
485                case '\t':
486                        i = 8 - (tty->column & 7);
487                        if ((tty->termios.c_oflag & TABDLY) == XTABS) {
488                                tty->column += i;
489                                osend ( "        ",  i, tty);
490                                return;
491                        }
492                        tty->column += i;
493                        break;
494
495                case '\b':
496                        if (tty->column > 0)
497                                tty->column--;
498                        break;
499
500                default:
501                        if (tty->termios.c_oflag & OLCUC)
502                                c = toupper(c);
503                        if (!iscntrl(c))
504                                tty->column++;
505                        break;
506                }
507        }
508        osend (&c, 1, tty);
509}
510
511rtems_status_code
512rtems_termios_write (void *arg)
513{
514        rtems_libio_rw_args_t *args = arg;
515        struct rtems_termios_tty *tty = args->iop->data1;
516        rtems_status_code sc;
517
518        sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
519        if (sc != RTEMS_SUCCESSFUL)
520                return sc;
521        if (tty->termios.c_oflag & OPOST) {
522                unsigned32 count = args->count;
523                unsigned8 *buffer = args->buffer;
524                while (count--)
525                        oproc (*buffer++, tty);
526                args->bytes_moved = args->count;
527        }
528        else {
529                osend (args->buffer, args->count, tty);
530                args->bytes_moved = args->count;
531        }
532        rtems_semaphore_release (tty->osem);
533        return sc;
534}
535
536/*
537 * Echo a typed character
538 */
539static void
540echo (unsigned char c, struct rtems_termios_tty *tty)
541{
542        if ((tty->termios.c_lflag & ECHOCTL) && iscntrl(c) && (c != '\t') && (c != '\n')) {
543                char echobuf[2];
544
545                echobuf[0] = '^';
546                echobuf[1] = c ^ 0x40;
547                osend (echobuf, 2, tty);
548                tty->column += 2;
549        }
550        else {
551                oproc (c, tty);
552        }
553}
554
555/*
556 * Erase a character or line
557 * FIXME: Needs support for WERASE and ECHOPRT.
558 * FIXME: Some of the tests should check for IEXTEN, too.
559 */
560static void
561erase (struct rtems_termios_tty *tty, int lineFlag)
562{
563        if (tty->ccount == 0)
564                return;
565        if (lineFlag) {
566                if (!(tty->termios.c_lflag & ECHO)) {
567                        tty->ccount = 0;
568                        return;
569                }
570                if (!(tty->termios.c_lflag & ECHOE)) {
571                        tty->ccount = 0;
572                        echo (tty->termios.c_cc[VKILL], tty);
573                        if (tty->termios.c_lflag & ECHOK)
574                                echo ('\n', tty);
575                        return;
576                }
577        }
578        while (tty->ccount) {
579                unsigned char c = tty->cbuf[--tty->ccount];
580
581                if (tty->termios.c_lflag & ECHO) {
582                        if (!lineFlag && !(tty->termios.c_lflag & ECHOE)) {
583                                echo (tty->termios.c_cc[VERASE], tty);
584                        }
585                        else if (c == '\t') {
586                                int col = tty->read_start_column;
587                                int i = 0;
588
589                                /*
590                                 * Find the character before the tab
591                                 */
592                                while (i != tty->ccount) {
593                                        c = tty->cbuf[i++];
594                                        if (c == '\t') {
595                                                col = (col | 7) + 1;
596                                        }
597                                        else if (iscntrl (c)) {
598                                                if (tty->termios.c_lflag & ECHOCTL)
599                                                        col += 2;
600                                        }
601                                        else {
602                                                col++;
603                                        }
604                                }
605
606                                /*
607                                 * Back up over the tab
608                                 */
609                                while (tty->column > col) {
610                                        osend ("\b", 1, tty);
611                                        tty->column--;
612                                }
613                        }
614                        else {
615                                if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
616                                        osend ("\b \b", 3, tty);
617                                        if (tty->column)
618                                                tty->column--;
619                                }
620                                if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
621                                        osend ("\b \b", 3, tty);
622                                        if (tty->column)
623                                                tty->column--;
624                                }
625                        }
626                }
627                if (!lineFlag)
628                        break;
629        }
630}
631
632/*
633 * Process a single input character
634 */
635static int
636iproc (unsigned char c, struct rtems_termios_tty *tty)
637{
638        if (tty->termios.c_iflag & ISTRIP)
639                c &= 0x7f;
640        if (tty->termios.c_iflag & IUCLC)
641                c = tolower (c);
642        if (c == '\r') {
643                if (tty->termios.c_iflag & IGNCR)
644                        return 0;
645                if (tty->termios.c_iflag & ICRNL)
646                        c = '\n';
647        }
648        else if ((c == '\n') && (tty->termios.c_iflag & INLCR)) {
649                c = '\r';
650        }
651        if ((c != '\0') && (tty->termios.c_lflag & ICANON)) {
652                if (c == tty->termios.c_cc[VERASE]) {
653                        erase (tty, 0);
654                        return 0;
655                }
656                else if (c == tty->termios.c_cc[VKILL]) {
657                        erase (tty, 1);
658                        return 0;
659                }
660                else if (c == tty->termios.c_cc[VEOF]) {
661                        return 1;
662                }
663                else if (c == '\n') {
664                        if (tty->termios.c_lflag & (ECHO | ECHONL))
665                                echo (c, tty);
666                        tty->cbuf[tty->ccount++] = c;
667                        return 1;
668                }
669                else if ((c == tty->termios.c_cc[VEOL])
670                      || (c == tty->termios.c_cc[VEOL2])) {
671                        if (tty->termios.c_lflag & ECHO)
672                                echo (c, tty);
673                        tty->cbuf[tty->ccount++] = c;
674                        return 1;
675                }
676        }
677
678        /*
679         * FIXME: Should do IMAXBEL handling somehow
680         */
681        if (tty->ccount < (CBUFSIZE-1)) {
682                if (tty->termios.c_lflag & ECHO)
683                        echo (c, tty);
684                tty->cbuf[tty->ccount++] = c;
685        }
686        return 0;
687}
688
689/*
690 * Process input character, with semaphore.
691 */
692static int
693siproc (unsigned char c, struct rtems_termios_tty *tty)
694{
695        int i;
696
697        /*
698         * Obtain output semaphore if character will be echoed
699         */
700        if (tty->termios.c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ECHOPRT|ECHOCTL|ECHOKE)) {
701                rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
702                i = iproc (c, tty);
703                rtems_semaphore_release (tty->osem);
704        }
705        else {
706                i = iproc (c, tty);
707        }
708        return i;
709}
710
711/*
712 * Fill the input buffer by polling the device
713 */
714static rtems_status_code
715fillBufferPoll (struct rtems_termios_tty *tty)
716{
717        int n;
718
719        if (tty->termios.c_lflag & ICANON) {
720                for (;;) {
721                        n = (*tty->read)(tty->minor);
722                        if (n < 0) {
723                                rtems_task_wake_after (1);
724                        }
725                        else {
726                                if  (siproc (n, tty))
727                                        break;
728                        }
729                }
730        }
731        else {
732                rtems_interval then, now;
733                if (!tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
734                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
735                for (;;) {
736                        n = (*tty->read)(tty->minor);
737                        if (n < 0) {
738                                if (tty->termios.c_cc[VMIN]) {
739                                        if (tty->termios.c_cc[VTIME] && tty->ccount) {
740                                                rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
741                                                if ((now - then) > tty->vtimeTicks) {
742                                                        break;
743                                                }
744                                        }
745                                }
746                                else {
747                                        if (!tty->termios.c_cc[VTIME])
748                                                break;
749                                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
750                                        if ((now - then) > tty->vtimeTicks) {
751                                                break;
752                                        }
753                                }
754                                rtems_task_wake_after (1);
755                        }
756                        else {
757                                siproc (n, tty);
758                                if (tty->ccount >= tty->termios.c_cc[VMIN])
759                                        break;
760                                if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
761                                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
762                        }
763                }
764        }
765        return RTEMS_SUCCESSFUL;
766}
767
768/*
769 * Fill the input buffer from the raw input queue
770 */
771static rtems_status_code
772fillBufferQueue (struct rtems_termios_tty *tty)
773{
774        rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
775        rtems_status_code sc;
776
777        for (;;) {
778                /*
779                 * Process characters read from raw queue
780                 */
781                while (tty->rawInBufHead != tty->rawInBufTail) {
782                        unsigned char c;
783                        unsigned int newHead;
784
785                        newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
786                        c = tty->rawInBuf[newHead];
787                        tty->rawInBufHead = newHead;
788                        if (tty->termios.c_lflag & ICANON) {
789                                if  (siproc (c, tty))
790                                        return RTEMS_SUCCESSFUL;
791                        }
792                        else {
793                                siproc (c, tty);
794                                if (tty->ccount >= tty->termios.c_cc[VMIN])
795                                        return RTEMS_SUCCESSFUL;
796                        }
797                        timeout = tty->rawInBufSemaphoreTimeout;
798                }
799
800                /*
801                 * Wait for characters
802                 */
803                sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
804                                                tty->rawInBufSemaphoreOptions,
805                                                timeout);
806                if (sc != RTEMS_SUCCESSFUL)
807                        break;
808        }
809        return RTEMS_SUCCESSFUL;
810}
811
812rtems_status_code
813rtems_termios_read (void *arg)
814{
815        rtems_libio_rw_args_t *args = arg;
816        struct rtems_termios_tty *tty = args->iop->data1;
817        unsigned32 count = args->count;
818        unsigned8 *buffer = args->buffer;
819        rtems_status_code sc;
820
821        sc = rtems_semaphore_obtain (tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
822        if (sc != RTEMS_SUCCESSFUL)
823                return sc;
824        if (tty->cindex == tty->ccount) {
825                tty->cindex = tty->ccount = 0;
826                tty->read_start_column = tty->column;
827                if (tty->read)
828                        sc = fillBufferPoll (tty);
829                else
830                        sc = fillBufferQueue (tty);
831                if (sc != RTEMS_SUCCESSFUL)
832                        tty->cindex = tty->ccount = 0;
833        }
834        while (count && (tty->cindex < tty->ccount)) {
835                *buffer++ = tty->cbuf[tty->cindex++];
836                count--;
837        }
838        args->bytes_moved = args->count - count;
839        rtems_semaphore_release (tty->isem);
840        return sc;
841}
842
843/*
844 * Place characters on raw queue.
845 * NOTE: This routine runs in the context of the
846 *       device receive interrupt handler.
847 */
848void
849rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
850{
851        struct rtems_termios_tty *tty = ttyp;
852        unsigned int newTail;
853
854        while (len) {
855                newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
856                if (newTail == tty->rawInBufHead) {
857                        tty->rawInBufDropped += len;
858                        break;
859                }
860                tty->rawInBuf[newTail] = *buf++;
861                len--;
862                tty->rawInBufTail = newTail;
863        }
864        rtems_semaphore_release (tty->rawInBufSemaphore);
865}
866
867/*
868 * Characters have been transmitted
869 * NOTE: This routine runs in the context of the
870 *       device transmit interrupt handler.
871 * The second argument is the number of characters transmitted so far.
872 * This value will always be 1 for devices which generate an interrupt
873 * for each transmitted character.
874 */
875void
876rtems_termios_dequeue_characters (void *ttyp, int len)
877{
878        struct rtems_termios_tty *tty = ttyp;
879        unsigned int newTail;
880        int nToSend;
881
882        if (tty->rawOutBufState == rob_wait)
883                rtems_semaphore_release (tty->rawOutBufSemaphore);
884        newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
885        if (newTail == tty->rawOutBufHead) {
886                /*
887                 * Buffer empty
888                 */
889                tty->rawOutBufState = rob_idle;
890        }
891        else {
892                /*
893                 * Buffer not empty, start tranmitter
894                 */
895                tty->rawOutBufState = rob_busy;
896                if (newTail > tty->rawOutBufHead)
897                        nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
898                else
899                        nToSend = tty->rawOutBufHead - newTail;
900                (*tty->write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
901        }
902        tty->rawOutBufTail = newTail;
903}
Note: See TracBrowser for help on using the repository browser.