source: rtems/c/src/exec/libcsupport/src/termios.c @ bbdab89

4.104.114.84.95
Last change on this file since bbdab89 was bbdab89, checked in by Joel Sherrill <joel.sherrill@…>, on 08/21/98 at 12:52:08

Added initialization of missing termios structure entries.

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