source: rtems/c/src/lib/libc/termios.c @ 30ba752

4.104.114.84.95
Last change on this file since 30ba752 was 30ba752, checked in by Joel Sherrill <joel.sherrill@…>, on 09/21/98 at 00:01:26

Patch from Eric Norum:

I fixed the problems noted by Victor Vengerov.

1) Fix typo in cfsetispeed().
2) In rtems_termios_open, ensure that args->iop->data1 is set before calling
device-specific open routine.

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