source: rtems/c/src/lib/libc/termios.c @ 27dccae

4.104.114.84.95
Last change on this file since 27dccae was 27dccae, checked in by Joel Sherrill <joel.sherrill@…>, on 05/20/98 at 17:09:12

Patch to add return status to rtems_termios_enqueue_raw_characters from
Eric Norum per request from Geoffroy Montel:

The rtems_termios_enqueue_raw_characters function type is void.
The problem is that I can't return an error message if the input
buffer is full.
Could we add a return value?

Sure, but what would you do with the overflow indication? POSIX says,
when the input limit is reached, the saved characters are thrown away
without notice.

Anyhow, the change is so small I've done it and enclosed the patch.

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