source: rtems/c/src/exec/libcsupport/src/termios.c @ 8a496e46

4.104.114.84.9
Last change on this file since 8a496e46 was 8a496e46, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 23, 1998 at 1:20:34 PM

Patch from Aleksey (Quality Quorum <qqi@…>):

  1. Finally fixes raw interrupts for pc386
  2. Makes some minor cleanup in console and startup
  3. Makes rtems_termios_dequeue_characters() to return count of outstanding chars - it allows to simplify console isrs a little bit.
  4. pc386 uart modified to be friendlier to termios parameter changes, to have minor performance improvement and to take advantage of of above termios modification.
  • Property mode set to 100644
File size: 21.2 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                if (ttyTail == NULL)
217                        ttyTail = tty;
218
219                tty->minor = minor;
220                tty->major = major;
221
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);
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);
249                tty->rawOutBufState = rob_idle;
250
251                /*
252                 * Set callbacks
253                 */
254                tty->device = *callbacks;
255                if (!tty->device.pollRead) {
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,
261                                &tty->rawInBufSemaphore);
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;
295        if (!tty->refcount++ && tty->device.firstOpen)
296                (*tty->device.firstOpen)(major, minor, arg);
297        rtems_semaphore_release (ttyMutex);
298        return RTEMS_SUCCESSFUL;
299}
300
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
326rtems_status_code
327rtems_termios_close (void *arg)
328{
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) {
337                drainOutput (tty);
338                if (tty->device.lastClose)
339                         (*tty->device.lastClose)(tty->major, tty->minor, arg);
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);
350                rtems_semaphore_delete (tty->rawOutBufSemaphore);
351                if (!tty->device.pollRead)
352                        rtems_semaphore_delete (tty->rawInBufSemaphore);
353                free (tty);
354        }
355        rtems_semaphore_release (ttyMutex);
356        return RTEMS_SUCCESSFUL;
357}
358
359rtems_status_code
360rtems_termios_ioctl (void *arg)
361{
362        rtems_libio_ioctl_args_t *args = arg;
363        struct rtems_termios_tty *tty = args->iop->data1;
364        rtems_status_code sc;
365
366        args->ioctl_return = 0;
367        sc = rtems_semaphore_obtain (tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
368        if (sc != RTEMS_SUCCESSFUL) {
369                args->ioctl_return = sc;
370                return sc;
371        }
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) {
384                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
385                        tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
386                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
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]) {
393                                tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
394                                tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
395                                if (tty->termios.c_cc[VMIN])
396                                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
397                                else
398                                        tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
399                        }
400                        else {
401                                if (tty->termios.c_cc[VMIN]) {
402                                        tty->rawInBufSemaphoreOptions = RTEMS_WAIT;
403                                        tty->rawInBufSemaphoreTimeout = RTEMS_NO_TIMEOUT;
404                                        tty->rawInBufSemaphoreFirstTimeout = RTEMS_NO_TIMEOUT;
405                                }
406                                else {
407                                        tty->rawInBufSemaphoreOptions = RTEMS_NO_WAIT;
408                                }
409                        }
410                }
411                if (tty->device.setAttributes)
412                        (*tty->device.setAttributes)(tty->minor, &tty->termios);
413                break;
414
415        case RTEMS_IO_TCDRAIN:
416                drainOutput (tty);
417                break;
418        }
419        rtems_semaphore_release (tty->osem);
420        args->ioctl_return = sc;
421        return sc;
422}
423
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
434        if (!tty->device.outputUsesInterrupts) {
435                (*tty->device.write)(tty->minor, buf, len);
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) {
467                        (*tty->device.write)(tty->minor,
468                                (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
469                        tty->rawOutBufState = rob_busy;
470                }
471                rtems_interrupt_enable (level);
472                len--;
473        }
474}
475
476/*
477 * Handle output processing
478 */
479static void
480oproc (unsigned char c, struct rtems_termios_tty *tty)
481{
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) {
490                                osend ("\r", 1, tty);
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;
511                                osend ( "        ",  i, tty);
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        }
530        osend (&c, 1, tty);
531}
532
533rtems_status_code
534rtems_termios_write (void *arg)
535{
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 {
551                osend (args->buffer, args->count, tty);
552                args->bytes_moved = args->count;
553        }
554        rtems_semaphore_release (tty->osem);
555        return sc;
556}
557
558/*
559 * Echo a typed character
560 */
561static void
562echo (unsigned char c, struct rtems_termios_tty *tty)
563{
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;
569                osend (echobuf, 2, tty);
570                tty->column += 2;
571        }
572        else {
573                oproc (c, tty);
574        }
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{
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) {
632                                        osend ("\b", 1, tty);
633                                        tty->column--;
634                                }
635                        }
636                        else {
637                                if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
638                                        osend ("\b \b", 3, tty);
639                                        if (tty->column)
640                                                tty->column--;
641                                }
642                                if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
643                                        osend ("\b \b", 3, tty);
644                                        if (tty->column)
645                                                tty->column--;
646                                }
647                        }
648                }
649                if (!lineFlag)
650                        break;
651        }
652}
653
654/*
655 * Process a single input character
656 */
657static int
658iproc (unsigned char c, struct rtems_termios_tty *tty)
659{
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;
709}
710
711/*
712 * Process input character, with semaphore.
713 */
714static int
715siproc (unsigned char c, struct rtems_termios_tty *tty)
716{
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;
731}
732
733/*
734 * Fill the input buffer by polling the device
735 */
736static rtems_status_code
737fillBufferPoll (struct rtems_termios_tty *tty)
738{
739        int n;
740
741        if (tty->termios.c_lflag & ICANON) {
742                for (;;) {
743                        n = (*tty->device.pollRead)(tty->minor);
744                        if (n < 0) {
745                                rtems_task_wake_after (1);
746                        }
747                        else {
748                                if  (siproc (n, tty))
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 (;;) {
758                        n = (*tty->device.pollRead)(tty->minor);
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 {
779                                siproc (n, tty);
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;
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{
796        rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
797        rtems_status_code sc;
798
799        for (;;) {
800                /*
801                 * Process characters read from raw queue
802                 */
803                while (tty->rawInBufHead != tty->rawInBufTail) {
804                        unsigned char c;
805                        unsigned int newHead;
806
807                        newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
808                        c = tty->rawInBuf[newHead];
809                        tty->rawInBufHead = newHead;
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                        }
819                        timeout = tty->rawInBufSemaphoreTimeout;
820                }
821
822                /*
823                 * Wait for characters
824                 */
825                sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
826                                                tty->rawInBufSemaphoreOptions,
827                                                timeout);
828                if (sc != RTEMS_SUCCESSFUL)
829                        break;
830        }
831        return RTEMS_SUCCESSFUL;
832}
833
834rtems_status_code
835rtems_termios_read (void *arg)
836{
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;
849                if (tty->device.pollRead)
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;
863}
864
865/*
866 * Place characters on raw queue.
867 * NOTE: This routine runs in the context of the
868 *       device receive interrupt handler.
869 * Returns the number of characters dropped because of overlow.
870 */
871int
872rtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len)
873{
874        struct rtems_termios_tty *tty = ttyp;
875        unsigned int newTail;
876
877        while (len) {
878                newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
879                if (newTail == tty->rawInBufHead) {
880                        tty->rawInBufDropped += len;
881                        break;
882                }
883                tty->rawInBuf[newTail] = *buf++;
884                len--;
885                tty->rawInBufTail = newTail;
886        }
887        rtems_semaphore_release (tty->rawInBufSemaphore);
888        return len;
889}
890
891/*
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.
898 * It returns number of characters left to transmit
899 */
900int
901rtems_termios_dequeue_characters (void *ttyp, int len)
902{
903        struct rtems_termios_tty *tty = ttyp;
904        unsigned int newTail;
905        int nToSend;
906
907        if (tty->rawOutBufState == rob_wait)
908                rtems_semaphore_release (tty->rawOutBufSemaphore);
909        if ( tty->rawOutBufHead == tty->rawOutBufTail )
910                return 0;
911        newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
912        if (newTail == tty->rawOutBufHead) {
913                /*
914                 * Buffer empty
915                 */
916                tty->rawOutBufState = rob_idle;
917                nToSend = 0;
918        }
919        else {
920                /*
921                 * Buffer not empty, start tranmitter
922                 */
923                if (newTail > tty->rawOutBufHead)
924                        nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
925                else
926                        nToSend = tty->rawOutBufHead - newTail;
927                (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
928                tty->rawOutBufState = rob_busy;
929        }
930        tty->rawOutBufTail = newTail;
931
932        return nToSend;
933}
934
935
Note: See TracBrowser for help on using the repository browser.