Changeset e2af631 in rtems


Ignore:
Timestamp:
11/25/00 19:35:53 (23 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, 5, master
Children:
a6abd67
Parents:
c8471315
Message:

2000-11-25 Antti P Miettinen <antti.p.miettinen@…>

  • libc/termios.c, libc/termiostypes.h: Task driver driver model and line discipline support from Thomas Doerfler <Thomas.Doerfler@…>.
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • c/src/exec/libcsupport/src/Makefile.am

    rc8471315 re2af631  
    8282
    8383EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \
    84     $(UNIX_C_FILES)
     84    $(UNIX_C_FILES) termiostypes.h
    8585
    8686include $(top_srcdir)/../../../automake/local.am
  • c/src/exec/libcsupport/src/termios.c

    rc8471315 re2af631  
    2424#include <termios.h>
    2525#include <unistd.h>
     26#include <sys/ttycom.h>
     27
     28#include "termiostypes.h"
    2629
    2730/*
     
    6164#define RAW_OUTPUT_BUFFER_SIZE  64
    6265
    63 /*
    64  * Variables associated with each termios instance.
    65  * One structure for each hardware I/O device.
    66  */
    67 struct rtems_termios_tty {
    68         /*
    69          * Linked-list of active TERMIOS devices
    70          */
    71         struct rtems_termios_tty        *forw;
    72         struct rtems_termios_tty        *back;
    73 
    74         /*
    75          * How many times has this device been opened
    76          */
    77         int             refcount;
    78 
    79         /*
    80          * This device
    81          */
    82         rtems_device_major_number       major;
    83         rtems_device_major_number       minor;
    84 
    85         /*
    86          * Mutual-exclusion semaphores
    87          */
    88         rtems_id        isem;
    89         rtems_id        osem;
    90 
    91         /*
    92          * The canonical (cooked) character buffer
    93          */
    94         char            cbuf[CBUFSIZE];
    95         int             ccount;
    96         int             cindex;
    97 
    98         /*
    99          * Keep track of cursor (printhead) position
    100          */
    101         int             column;
    102         int             read_start_column;
    103 
    104         /*
    105          * The ioctl settings
    106          */
    107         struct termios  termios;
    108         rtems_interval  vtimeTicks;
    109 
    110         /*
    111          * Raw input character buffer
    112          */
    113         volatile char           rawInBuf[RAW_INPUT_BUFFER_SIZE];
    114         volatile unsigned int   rawInBufHead;
    115         volatile unsigned int   rawInBufTail;
    116         rtems_id                rawInBufSemaphore;
    117         rtems_unsigned32        rawInBufSemaphoreOptions;
    118         rtems_interval          rawInBufSemaphoreTimeout;
    119         rtems_interval          rawInBufSemaphoreFirstTimeout;
    120         unsigned int            rawInBufDropped;        /* Statistics */
    121 
    122         /*
    123          * Raw output character buffer
    124          */
    125         volatile char           rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
    126         volatile unsigned int   rawOutBufHead;
    127         volatile unsigned int   rawOutBufTail;
    128         rtems_id                rawOutBufSemaphore;
    129         volatile enum {rob_idle, rob_busy, rob_wait }   rawOutBufState;
    130 
    131         /*
    132          * Callbacks to device-specific routines
    133          */
    134         rtems_termios_callbacks device;
    135         volatile unsigned int   flow_ctrl;
    136         unsigned int            lowwater,highwater;
    137 };
    138 
    13966/* fields for "flow_ctrl" status */
    14067#define FL_IREQXOF 1        /* input queue requests stop of incoming data */
     
    14976#define FL_MDXOF   0x400    /* output controlled with XON/XOFF protocol   */
    15077
     78#define NODISC(n) \
     79        { NULL, NULL,   NULL,   NULL, \
     80          NULL, NULL,   NULL,   NULL }
     81/*
     82 * FIXME: change linesw entries consistant with linesw entry usage...
     83 */
     84struct  linesw linesw[MAXLDISC] =
     85{
     86        NODISC(0),              /* 0- termios-built-in */
     87        NODISC(1),              /* 1- defunct */
     88        NODISC(2),              /* 2- NTTYDISC */
     89        NODISC(3),              /* TABLDISC */
     90        NODISC(4),              /* SLIPDISC */
     91        NODISC(5),              /* PPPDISC */
     92        NODISC(6),              /* loadable */
     93        NODISC(7),              /* loadable */
     94};
     95
     96int     nlinesw = sizeof (linesw) / sizeof (linesw[0]);
     97
    15198extern struct rtems_termios_tty *rtems_termios_ttyHead;
    15299extern struct rtems_termios_tty *rtems_termios_ttyTail;
    153100extern rtems_id rtems_termios_ttyMutex;
     101
     102static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
     103static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
     104/*
     105 * some constants for I/O daemon task creation
     106 */
     107#define TERMIOS_TXTASK_PRIO 10
     108#define TERMIOS_RXTASK_PRIO 9
     109#define TERMIOS_TXTASK_STACKSIZE 1024
     110#define TERMIOS_RXTASK_STACKSIZE 1024
     111/*
     112 * some events to be sent to the I/O tasks
     113 */
     114#define TERMIOS_TX_START_EVENT     RTEMS_EVENT_1
     115#define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0
     116
     117#define TERMIOS_RX_PROC_EVENT      RTEMS_EVENT_1
     118#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
    154119
    155120/*
     
    171136         * See if the device has already been opened
    172137         */
    173         sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     138        sc = rtems_semaphore_obtain (rtems_termios_ttyMutex,
     139                                     RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    174140        if (sc != RTEMS_SUCCESSFUL)
    175141                return sc;
     
    189155                        return RTEMS_NO_MEMORY;
    190156                }
     157                /*
     158                 * allocate raw input buffer
     159                 */
     160                tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
     161                tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
     162                if (tty->rawInBuf.theBuf == NULL) {
     163                        free(tty);
     164                        rtems_semaphore_release (rtems_termios_ttyMutex);
     165                        return RTEMS_NO_MEMORY;
     166                }
     167                /*
     168                 * allocate raw output buffer
     169                 */
     170                tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
     171                tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
     172                if (tty->rawInBuf.theBuf == NULL) {
     173                        free((void *)(tty->rawInBuf.theBuf));
     174                        free(tty);
     175                        rtems_semaphore_release (rtems_termios_ttyMutex);
     176                        return RTEMS_NO_MEMORY;
     177                }
     178                /*
     179                 * allocate cooked buffer
     180                 */
     181                tty->cbuf  = malloc (CBUFSIZE);
     182                if (tty->cbuf == NULL) {
     183                        free((void *)(tty->rawOutBuf.theBuf));
     184                        free((void *)(tty->rawInBuf.theBuf));
     185                        free(tty);
     186                        rtems_semaphore_release (rtems_termios_ttyMutex);
     187                        return RTEMS_NO_MEMORY;
     188                }
     189                /*
     190                 * link tty
     191                 */
    191192                if (rtems_termios_ttyHead)
    192193                        rtems_termios_ttyHead->back = tty;
     
    222223                        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
    223224                        RTEMS_NO_PRIORITY,
    224                         &tty->rawOutBufSemaphore);
     225                        &tty->rawOutBuf.Semaphore);
    225226                if (sc != RTEMS_SUCCESSFUL)
    226227                        rtems_fatal_error_occurred (sc);
     
    231232                 */
    232233                tty->device = *callbacks;
    233                 if (!tty->device.pollRead) {
     234
     235                /*
     236                 * Create I/O tasks
     237                 */
     238                if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     239                        sc = rtems_task_create (
     240                                   rtems_build_name ('T', 'x', 'T', c),
     241                                   TERMIOS_TXTASK_PRIO,
     242                                   TERMIOS_TXTASK_STACKSIZE,
     243                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
     244                                   RTEMS_NO_ASR,
     245                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
     246                                   &tty->txTaskId);
     247                        if (sc != RTEMS_SUCCESSFUL)
     248                                rtems_fatal_error_occurred (sc);
     249                        sc = rtems_task_create (
     250                                   rtems_build_name ('R', 'x', 'T', c),
     251                                   TERMIOS_RXTASK_PRIO,
     252                                   TERMIOS_RXTASK_STACKSIZE,
     253                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
     254                                   RTEMS_NO_ASR,
     255                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
     256                                   &tty->rxTaskId);
     257                        if (sc != RTEMS_SUCCESSFUL)
     258                                rtems_fatal_error_occurred (sc);
     259                               
     260                }
     261                if ((tty->device.pollRead == NULL) ||
     262                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){
    234263                        sc = rtems_semaphore_create (
    235264                                rtems_build_name ('T', 'R', 'r', c),
     
    237266                                RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
    238267                                RTEMS_NO_PRIORITY,
    239                                 &tty->rawInBufSemaphore);
     268                                &tty->rawInBuf.Semaphore);
    240269                        if (sc != RTEMS_SUCCESSFUL)
    241270                                rtems_fatal_error_occurred (sc);
     
    270299                 * set low/highwater mark for XON/XOFF support
    271300                 */
    272                 tty->lowwater  = RAW_INPUT_BUFFER_SIZE * 1/2;
    273                 tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4;
     301                tty->lowwater  = tty->rawInBuf.Size * 1/2;
     302                tty->highwater = tty->rawInBuf.Size * 3/4;
    274303                /*
    275304                 * Bump name characer
     
    280309        }
    281310        args->iop->data1 = tty;
    282         if (!tty->refcount++ && tty->device.firstOpen)
     311        if (!tty->refcount++) {
     312          if (tty->device.firstOpen)
    283313                (*tty->device.firstOpen)(major, minor, arg);
     314          /*
     315           * start I/O tasks, if needed
     316           */
     317          if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     318            sc = rtems_task_start(tty->rxTaskId,
     319                                  rtems_termios_rxdaemon,
     320                                  (rtems_task_argument)tty);
     321            if (sc != RTEMS_SUCCESSFUL)
     322              rtems_fatal_error_occurred (sc);
     323           
     324            sc = rtems_task_start(tty->txTaskId,
     325                                  rtems_termios_txdaemon,
     326                                  (rtems_task_argument)tty);
     327            if (sc != RTEMS_SUCCESSFUL)
     328              rtems_fatal_error_occurred (sc);
     329          }
     330        }
    284331        rtems_semaphore_release (rtems_termios_ttyMutex);
    285332        return RTEMS_SUCCESSFUL;
     
    295342        rtems_status_code sc;
    296343
    297         if (tty->device.outputUsesInterrupts) {
     344        if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) {
    298345                rtems_interrupt_disable (level);
    299                 while (tty->rawOutBufTail != tty->rawOutBufHead) {
     346                while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
    300347                        tty->rawOutBufState = rob_wait;
    301348                        rtems_interrupt_enable (level);
    302                         sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
     349                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
    303350                                                        RTEMS_WAIT,
    304351                                                        RTEMS_NO_TIMEOUT);
     
    322369                rtems_fatal_error_occurred (sc);
    323370        if (--tty->refcount == 0) {
    324                 drainOutput (tty);
     371                if (linesw[tty->t_line].l_close != NULL) {
     372                        /*
     373                         * call discipline-specific close
     374                         */
     375                        sc = linesw[tty->t_line].l_close(tty);
     376                }
     377                else {
     378                        /*
     379                         * default: just flush output buffer
     380                         */
     381                        drainOutput (tty);
     382                }
     383         
     384                if (tty->device.outputUsesInterrupts
     385                    == TERMIOS_TASK_DRIVEN) {
     386                        /*
     387                         * send "terminate" to I/O tasks
     388                         */
     389                        sc = rtems_event_send(
     390                                  tty->rxTaskId,
     391                                  TERMIOS_RX_TERMINATE_EVENT);
     392                        if (sc != RTEMS_SUCCESSFUL)
     393                                rtems_fatal_error_occurred (sc);
     394                        sc = rtems_event_send(
     395                                  tty->txTaskId,
     396                                  TERMIOS_TX_TERMINATE_EVENT);
     397                        if (sc != RTEMS_SUCCESSFUL)
     398                                rtems_fatal_error_occurred (sc);
     399                }
    325400                if (tty->device.lastClose)
    326401                         (*tty->device.lastClose)(tty->major, tty->minor, arg);
     
    335410                rtems_semaphore_delete (tty->isem);
    336411                rtems_semaphore_delete (tty->osem);
    337                 rtems_semaphore_delete (tty->rawOutBufSemaphore);
    338                 if (!tty->device.pollRead)
    339                         rtems_semaphore_delete (tty->rawInBufSemaphore);
     412                rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
     413                if ((tty->device.pollRead == NULL) ||
     414                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN))
     415                        rtems_semaphore_delete (tty->rawInBuf.Semaphore);
    340416                free (tty);
    341417        }
     
    367443        /* if chars available, call write function... */
    368444        (*tty->device.write)(tty->minor,
    369                              (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
     445                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
    370446      }
    371447      /* reenable interrupts */
     
    428504        switch (args->command) {
    429505        default:
    430                 sc = RTEMS_INVALID_NUMBER;
     506                if (linesw[tty->t_line].l_ioctl != NULL) {
     507                        sc = linesw[tty->t_line].l_ioctl(tty,args);
     508                }
     509                else {
     510                        sc = RTEMS_INVALID_NUMBER;
     511                }
    431512                break;
    432513
     
    477558                break;
    478559
     560                /*
     561                 * FIXME: add various ioctl code handlers
     562                 */
     563
     564#if 1 /* FIXME */
     565        case TIOCSETD:
     566                /*
     567                 * close old line discipline
     568                 */
     569                if (linesw[tty->t_line].l_close != NULL) {
     570                        sc = linesw[tty->t_line].l_close(tty);
     571                }
     572                tty->t_line=*(int*)(args->buffer);
     573                tty->t_sc = NULL; /* ensure that no more valid data */
     574                /*
     575                 * open new line discipline
     576                 */
     577                if (linesw[tty->t_line].l_open != NULL) {
     578                        sc = linesw[tty->t_line].l_open(tty);
     579                }
     580                break;
     581        case TIOCGETD: 
     582                *(int*)(args->buffer)=tty->t_line;
     583                break;         
     584#endif
    479585        case FIONREAD:
    480586                /* Half guess that this is the right operation */
     
    490596 * Send characters to device-specific code
    491597 */
    492 static void
    493 osend (const char *buf, int len, struct rtems_termios_tty *tty)
     598void
     599rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty)
    494600{
    495601        unsigned int newHead;
     
    497603        rtems_status_code sc;
    498604
    499         if (!tty->device.outputUsesInterrupts) {
     605        if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) {
    500606                (*tty->device.write)(tty->minor, buf, len);
    501607                return;
    502608        }
    503         newHead = tty->rawOutBufHead;
     609        newHead = tty->rawOutBuf.Head;
    504610        while (len) {
    505611                /*
     
    515621                 * with interrupts enabled.
    516622                 */
    517                 newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
     623                newHead = (newHead + 1) % tty->rawOutBuf.Size;
    518624                rtems_interrupt_disable (level);
    519                 while (newHead == tty->rawOutBufTail) {
     625                while (newHead == tty->rawOutBuf.Tail) {
    520626                        tty->rawOutBufState = rob_wait;
    521627                        rtems_interrupt_enable (level);
    522                         sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
     628                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
    523629                                                        RTEMS_WAIT,
    524630                                                        RTEMS_NO_TIMEOUT);
     
    527633                        rtems_interrupt_disable (level);
    528634                }
    529                 tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
    530                 tty->rawOutBufHead = newHead;
     635                tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++;
     636                tty->rawOutBuf.Head = newHead;
    531637                if (tty->rawOutBufState == rob_idle) {
    532638                  /* check, whether XOFF has been received */
    533639                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
    534640                    (*tty->device.write)(tty->minor,
    535                                 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);
     641                        (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
    536642                  }
    537643                  else {
     
    560666                                tty->column = 0;
    561667                        if (tty->termios.c_oflag & ONLCR) {
    562                                 osend ("\r", 1, tty);
     668                                rtems_termios_puts ("\r", 1, tty);
    563669                                tty->column = 0;
    564670                        }
     
    581687                        if ((tty->termios.c_oflag & TABDLY) == XTABS) {
    582688                                tty->column += i;
    583                                 osend ( "        ",  i, tty);
     689                                rtems_termios_puts ( "        ",  i, tty);
    584690                                return;
    585691                        }
     
    600706                }
    601707        }
    602         osend (&c, 1, tty);
     708        rtems_termios_puts (&c, 1, tty);
    603709}
    604710
     
    613719        if (sc != RTEMS_SUCCESSFUL)
    614720                return sc;
     721        if (linesw[tty->t_line].l_write != NULL) {
     722                sc = linesw[tty->t_line].l_write(tty,args);
     723                rtems_semaphore_release (tty->osem);
     724                return sc;
     725        }
    615726        if (tty->termios.c_oflag & OPOST) {
    616727                unsigned32 count = args->count;
     
    621732        }
    622733        else {
    623                 osend (args->buffer, args->count, tty);
     734                rtems_termios_puts (args->buffer, args->count, tty);
    624735                args->bytes_moved = args->count;
    625736        }
     
    639750                echobuf[0] = '^';
    640751                echobuf[1] = c ^ 0x40;
    641                 osend (echobuf, 2, tty);
     752                rtems_termios_puts (echobuf, 2, tty);
    642753                tty->column += 2;
    643754        }
     
    702813                                 */
    703814                                while (tty->column > col) {
    704                                         osend ("\b", 1, tty);
     815                                        rtems_termios_puts ("\b", 1, tty);
    705816                                        tty->column--;
    706817                                }
     
    708819                        else {
    709820                                if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
    710                                         osend ("\b \b", 3, tty);
     821                                        rtems_termios_puts ("\b \b", 3, tty);
    711822                                        if (tty->column)
    712823                                                tty->column--;
    713824                                }
    714825                                if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
    715                                         osend ("\b \b", 3, tty);
     826                                        rtems_termios_puts ("\b \b", 3, tty);
    716827                                        if (tty->column)
    717828                                                tty->column--;
     
    873984                 * Process characters read from raw queue
    874985                 */
    875                 while (tty->rawInBufHead != tty->rawInBufTail) {
     986                while (tty->rawInBuf.Head != tty->rawInBuf.Tail) {
    876987                        unsigned char c;
    877988                        unsigned int newHead;
    878989
    879                         newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
    880                         c = tty->rawInBuf[newHead];
    881                         tty->rawInBufHead = newHead;
    882                         if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE)
    883                             % RAW_INPUT_BUFFER_SIZE)
     990                        newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
     991                        c = tty->rawInBuf.theBuf[newHead];
     992                        tty->rawInBuf.Head = newHead;
     993                        if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
     994                            % tty->rawInBuf.Size)
    884995                           < tty->lowwater) {
    885996                          tty->flow_ctrl &= ~FL_IREQXOF;
     
    9191030                 * Wait for characters
    9201031                 */
    921                 sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
     1032                sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore,
    9221033                                                tty->rawInBufSemaphoreOptions,
    9231034                                                timeout);
     
    9401051        if (sc != RTEMS_SUCCESSFUL)
    9411052                return sc;
     1053        if (linesw[tty->t_line].l_read != NULL) {
     1054                sc = linesw[tty->t_line].l_read(tty,args);
     1055                rtems_semaphore_release (tty->isem);
     1056                return sc;
     1057        }
    9421058        if (tty->cindex == tty->ccount) {
    9431059                tty->cindex = tty->ccount = 0;
    9441060                tty->read_start_column = tty->column;
    945                 if (tty->device.pollRead)
     1061                if (tty->device.pollRead != NULL
     1062                    && tty->device.outputUsesInterrupts == TERMIOS_POLLED)
    9461063                        sc = fillBufferPoll (tty);
    9471064                else
     
    9571074        rtems_semaphore_release (tty->isem);
    9581075        return sc;
     1076}
     1077
     1078/*
     1079 * signal receive interrupt to rx daemon
     1080 * NOTE: This routine runs in the context of the
     1081 *       device receive interrupt handler.
     1082 */
     1083void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
     1084{
     1085        /*
     1086         * send event to rx daemon task
     1087         */
     1088        rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
    9591089}
    9601090
     
    9741104        boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
    9751105        rtems_interrupt_level level;
     1106
     1107        if (linesw[tty->t_line].l_rint != NULL) {
     1108          while (len--) {
     1109            c = *buf++;
     1110            linesw[tty->t_line].l_rint(c,tty);
     1111          }
     1112          return 0;
     1113        }
    9761114
    9771115        while (len--) {
     
    10111149              /* if chars available, call write function... */
    10121150                (*tty->device.write)(tty->minor,
    1013                                      (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
     1151                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
    10141152              }
    10151153              /* reenable interrupts */
     
    10181156          }     
    10191157          else {
    1020                 newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
     1158                newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
    10211159                /* if chars_in_buffer > highwater                */
    10221160                rtems_interrupt_disable(level);
    1023                 if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE)
    1024                       % RAW_INPUT_BUFFER_SIZE)
     1161                if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
     1162                      % tty->rawInBuf.Size)
    10251163                     > tty->highwater) &&
    10261164                    !(tty->flow_ctrl & FL_IREQXOF)) {
     
    10511189                rtems_interrupt_enable(level);
    10521190
    1053                 if (newTail == tty->rawInBufHead) {
     1191                if (newTail == tty->rawInBuf.Head) {
    10541192                        dropped++;
    10551193                }
    10561194                else {
    1057                         tty->rawInBuf[newTail] = c;
    1058                         tty->rawInBufTail = newTail;
     1195                        tty->rawInBuf.theBuf[newTail] = c;
     1196                        tty->rawInBuf.Tail = newTail;
    10591197                }               
    10601198          }
    10611199        }
    10621200        tty->rawInBufDropped += dropped;
    1063         rtems_semaphore_release (tty->rawInBufSemaphore);
     1201        rtems_semaphore_release (tty->rawInBuf.Semaphore);
    10641202        return dropped;
     1203}
     1204
     1205/*
     1206 * in task-driven mode, this function is called in Tx task context
     1207 * in interrupt-driven mode, this function is called in TxIRQ context
     1208 */
     1209int
     1210rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
     1211{
     1212        unsigned int newTail;
     1213        int nToSend;
     1214        rtems_interrupt_level level;
     1215        int len;
     1216
     1217        /* check for XOF/XON to send */
     1218        if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
     1219            == (FL_MDXOF | FL_IREQXOF)) {
     1220          /* XOFF should be sent now... */
     1221          (*tty->device.write)(tty->minor,
     1222                               &(tty->termios.c_cc[VSTOP]), 1);
     1223
     1224          rtems_interrupt_disable(level);
     1225          tty->t_dqlen--;
     1226          tty->flow_ctrl |= FL_ISNTXOF;
     1227          rtems_interrupt_enable(level);
     1228
     1229          nToSend = 1;
     1230        }
     1231        else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
     1232                 == FL_ISNTXOF) {
     1233          /* NOTE: send XON even, if no longer in XON/XOFF mode... */
     1234          /* XON should be sent now... */
     1235                /*
     1236                 * FIXME: this .write call will generate another
     1237                 * dequeue callback. This will advance the "Tail" in the data
     1238                 * buffer, although the corresponding data is not yet out!
     1239                 * Therefore the dequeue "length" should be reduced by 1
     1240                 */
     1241          (*tty->device.write)(tty->minor,
     1242                               &(tty->termios.c_cc[VSTART]), 1);
     1243
     1244          rtems_interrupt_disable(level);
     1245          tty->t_dqlen--;
     1246          tty->flow_ctrl &= ~FL_ISNTXOF;
     1247          rtems_interrupt_enable(level);
     1248
     1249          nToSend = 1;
     1250        }
     1251        else {
     1252          if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
     1253            /*
     1254             * buffer was empty
     1255             */
     1256            if (tty->rawOutBufState == rob_wait) {
     1257              /*
     1258               * this should never happen...
     1259               */
     1260              rtems_semaphore_release (tty->rawOutBuf.Semaphore);
     1261            }
     1262            return 0;   
     1263          }
     1264
     1265          rtems_interrupt_disable(level);
     1266          len = tty->t_dqlen;
     1267          tty->t_dqlen = 0;
     1268          rtems_interrupt_enable(level);
     1269
     1270          newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
     1271          tty->rawOutBuf.Tail = newTail;
     1272          if (tty->rawOutBufState == rob_wait) {
     1273            /*
     1274             * wake up any pending writer task
     1275             */
     1276            rtems_semaphore_release (tty->rawOutBuf.Semaphore);
     1277          }
     1278          if (newTail == tty->rawOutBuf.Head) {
     1279            /*
     1280             * Buffer has become empty
     1281             */
     1282            tty->rawOutBufState = rob_idle;
     1283            nToSend = 0;
     1284          }
     1285          /* check, whether output should stop due to received XOFF */
     1286          else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
     1287                   ==                (FL_MDXON | FL_ORCVXOF)) {
     1288                  /* Buffer not empty, but output stops due to XOFF */
     1289                  /* set flag, that output has been stopped */
     1290                  rtems_interrupt_disable(level);
     1291                  tty->flow_ctrl |= FL_OSTOP;
     1292                  tty->rawOutBufState = rob_busy; /*apm*/
     1293                  rtems_interrupt_enable(level);
     1294                  nToSend = 0;
     1295          }
     1296          else {
     1297            /*
     1298             * Buffer not empty, start tranmitter
     1299             */
     1300            if (newTail > tty->rawOutBuf.Head)
     1301                    nToSend = tty->rawOutBuf.Size - newTail;
     1302            else
     1303                    nToSend = tty->rawOutBuf.Head - newTail;
     1304            /* when flow control XON or XOF, don't send blocks of data     */
     1305            /* to allow fast reaction on incoming flow ctrl and low latency*/
     1306            /* for outgoing flow control                                   */
     1307            if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
     1308                    nToSend = 1;
     1309            }
     1310            tty->rawOutBufState = rob_busy; /*apm*/
     1311            (*tty->device.write)(tty->minor,
     1312                                 (char *)&tty->rawOutBuf.theBuf[newTail],
     1313                                 nToSend);
     1314          }
     1315          tty->rawOutBuf.Tail = newTail; /*apm*/
     1316        }
     1317        return nToSend;
    10651318}
    10661319
     
    10781331{
    10791332        struct rtems_termios_tty *tty = ttyp;
    1080         unsigned int newTail;
    1081         int nToSend;
    1082 
    1083         /* check for XOF/XON to send */
    1084         if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
    1085             == (FL_MDXOF | FL_IREQXOF)) {
    1086           /* XOFF should be sent now... */
    1087           (*tty->device.write)(tty->minor,
    1088                                &(tty->termios.c_cc[VSTOP]), 1);
    1089           tty->flow_ctrl |= FL_ISNTXOF;
    1090           nToSend = 1;
    1091         }
    1092         else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
    1093                  == FL_ISNTXOF) {
    1094           /* NOTE: send XON even, if no longer in XON/XOFF mode... */
    1095           /* XON should be sent now... */
    1096           (*tty->device.write)(tty->minor,
    1097                                &(tty->termios.c_cc[VSTART]), 1);
    1098           tty->flow_ctrl &= ~FL_ISNTXOF;
    1099           nToSend = 1;
     1333        rtems_status_code sc;
     1334
     1335        /*
     1336         * sum up character count already sent
     1337         */
     1338        tty->t_dqlen += len;
     1339
     1340        if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     1341                /*
     1342                 * send wake up to transmitter task
     1343                 */
     1344                sc = rtems_event_send(tty->txTaskId,
     1345                                      TERMIOS_TX_START_EVENT);
     1346                if (sc != RTEMS_SUCCESSFUL)
     1347                        rtems_fatal_error_occurred (sc);
     1348                return 0; /* nothing to output in IRQ... */
    11001349        }
    11011350        else {
    1102           if (tty->rawOutBufState == rob_wait)
    1103             rtems_semaphore_release (tty->rawOutBufSemaphore);
    1104           if ( tty->rawOutBufHead == tty->rawOutBufTail ) {
    1105             tty->rawOutBufState = rob_idle;
    1106             return 0;   
    1107           }
    1108           newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
    1109           if (newTail == tty->rawOutBufHead) {
    1110             /*
    1111              * Buffer empty
    1112              */
    1113             tty->rawOutBufState = rob_idle;
    1114             nToSend = 0;
    1115           }
    1116           /* check, whether output should stop due to received XOFF */
    1117           else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
    1118                    ==                (FL_MDXON | FL_ORCVXOF)) {
    1119             /* Buffer not empty, but output stops due to XOFF */
    1120             /* set flag, that output has been stopped */
    1121             tty->flow_ctrl |= FL_OSTOP;
    1122             tty->rawOutBufState = rob_busy;
    1123             nToSend = 0;
    1124           }
    1125           else {
    1126             /*
    1127              * Buffer not empty, start tranmitter
    1128              */
    1129             if (newTail > tty->rawOutBufHead)
    1130               nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
    1131             else
    1132               nToSend = tty->rawOutBufHead - newTail;
    1133             /* when flow control XON or XOF, don't send blocks of data     */
    1134             /* to allow fast reaction on incoming flow ctrl and low latency*/
    1135             /* for outgoing flow control                                   */
    1136             if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF))
    1137               nToSend = 1;
    1138             tty->rawOutBufState = rob_busy;
    1139             (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
    1140           }
    1141           tty->rawOutBufTail = newTail;
    1142         }
    1143         return nToSend;
    1144 }
     1351                return rtems_termios_refill_transmitter(tty);
     1352        }
     1353}
     1354
     1355/*
     1356 * this task actually processes any transmit events
     1357 */
     1358static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
     1359{
     1360        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
     1361        rtems_event_set the_event;
     1362
     1363        while (1) {
     1364                /*
     1365                 * wait for rtems event
     1366                 */
     1367                rtems_event_receive((TERMIOS_TX_START_EVENT |
     1368                                     TERMIOS_TX_TERMINATE_EVENT),
     1369                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
     1370                                    RTEMS_NO_TIMEOUT,
     1371                                    &the_event);
     1372                if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
     1373                        tty->txTaskId = 0;
     1374                        rtems_task_delete(RTEMS_SELF);
     1375                }
     1376                else {
     1377                        /*
     1378                         * call any line discipline start function
     1379                         */
     1380                        if (linesw[tty->t_line].l_start != NULL) {
     1381                                linesw[tty->t_line].l_start(tty);
     1382                        }
     1383                        /*
     1384                         * try to push further characters to device
     1385                         */
     1386                        rtems_termios_refill_transmitter(tty);
     1387                }
     1388        }
     1389}
     1390
     1391/*
     1392 * this task actually processes any receive events
     1393 */
     1394static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
     1395{
     1396        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
     1397        rtems_event_set the_event;
     1398        int c;
     1399        char c_buf;
     1400        while (1) {
     1401                /*
     1402                 * wait for rtems event
     1403                 */
     1404                rtems_event_receive((TERMIOS_RX_PROC_EVENT |
     1405                                     TERMIOS_RX_TERMINATE_EVENT),
     1406                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
     1407                                    RTEMS_NO_TIMEOUT,
     1408                                    &the_event);
     1409                if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
     1410                        tty->rxTaskId = 0;
     1411                        rtems_task_delete(RTEMS_SELF);
     1412                }
     1413                else {
     1414                        /*
     1415                         * do something
     1416                         */
     1417                        c = tty->device.pollRead(tty->minor);
     1418                        if (c != EOF) {
     1419                                /*
     1420                                 * pollRead did call enqueue on its own
     1421                                 */
     1422                                c_buf = c;
     1423                                rtems_termios_enqueue_raw_characters (
     1424                                      tty,&c_buf,1);
     1425                        }
     1426                }
     1427        }
     1428}
  • c/src/lib/ChangeLog

    rc8471315 re2af631  
     1
     22000-11-25  Antti P Miettinen  <antti.p.miettinen@nokia.com>
     3
     4        * libc/termios.c, libc/termiostypes.h: Task driver driver model
     5        and line discipline support from Thomas Doerfler
     6        <Thomas.Doerfler@imd-systems.de>.
    17
    282000-11-20       Dmitry Kargapolov <dk@gentex.ru>
  • c/src/lib/libc/Makefile.am

    rc8471315 re2af631  
    8282
    8383EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \
    84     $(UNIX_C_FILES)
     84    $(UNIX_C_FILES) termiostypes.h
    8585
    8686include $(top_srcdir)/../../../automake/local.am
  • c/src/lib/libc/termios.c

    rc8471315 re2af631  
    2424#include <termios.h>
    2525#include <unistd.h>
     26#include <sys/ttycom.h>
     27
     28#include "termiostypes.h"
    2629
    2730/*
     
    6164#define RAW_OUTPUT_BUFFER_SIZE  64
    6265
    63 /*
    64  * Variables associated with each termios instance.
    65  * One structure for each hardware I/O device.
    66  */
    67 struct rtems_termios_tty {
    68         /*
    69          * Linked-list of active TERMIOS devices
    70          */
    71         struct rtems_termios_tty        *forw;
    72         struct rtems_termios_tty        *back;
    73 
    74         /*
    75          * How many times has this device been opened
    76          */
    77         int             refcount;
    78 
    79         /*
    80          * This device
    81          */
    82         rtems_device_major_number       major;
    83         rtems_device_major_number       minor;
    84 
    85         /*
    86          * Mutual-exclusion semaphores
    87          */
    88         rtems_id        isem;
    89         rtems_id        osem;
    90 
    91         /*
    92          * The canonical (cooked) character buffer
    93          */
    94         char            cbuf[CBUFSIZE];
    95         int             ccount;
    96         int             cindex;
    97 
    98         /*
    99          * Keep track of cursor (printhead) position
    100          */
    101         int             column;
    102         int             read_start_column;
    103 
    104         /*
    105          * The ioctl settings
    106          */
    107         struct termios  termios;
    108         rtems_interval  vtimeTicks;
    109 
    110         /*
    111          * Raw input character buffer
    112          */
    113         volatile char           rawInBuf[RAW_INPUT_BUFFER_SIZE];
    114         volatile unsigned int   rawInBufHead;
    115         volatile unsigned int   rawInBufTail;
    116         rtems_id                rawInBufSemaphore;
    117         rtems_unsigned32        rawInBufSemaphoreOptions;
    118         rtems_interval          rawInBufSemaphoreTimeout;
    119         rtems_interval          rawInBufSemaphoreFirstTimeout;
    120         unsigned int            rawInBufDropped;        /* Statistics */
    121 
    122         /*
    123          * Raw output character buffer
    124          */
    125         volatile char           rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
    126         volatile unsigned int   rawOutBufHead;
    127         volatile unsigned int   rawOutBufTail;
    128         rtems_id                rawOutBufSemaphore;
    129         volatile enum {rob_idle, rob_busy, rob_wait }   rawOutBufState;
    130 
    131         /*
    132          * Callbacks to device-specific routines
    133          */
    134         rtems_termios_callbacks device;
    135         volatile unsigned int   flow_ctrl;
    136         unsigned int            lowwater,highwater;
    137 };
    138 
    13966/* fields for "flow_ctrl" status */
    14067#define FL_IREQXOF 1        /* input queue requests stop of incoming data */
     
    14976#define FL_MDXOF   0x400    /* output controlled with XON/XOFF protocol   */
    15077
     78#define NODISC(n) \
     79        { NULL, NULL,   NULL,   NULL, \
     80          NULL, NULL,   NULL,   NULL }
     81/*
     82 * FIXME: change linesw entries consistant with linesw entry usage...
     83 */
     84struct  linesw linesw[MAXLDISC] =
     85{
     86        NODISC(0),              /* 0- termios-built-in */
     87        NODISC(1),              /* 1- defunct */
     88        NODISC(2),              /* 2- NTTYDISC */
     89        NODISC(3),              /* TABLDISC */
     90        NODISC(4),              /* SLIPDISC */
     91        NODISC(5),              /* PPPDISC */
     92        NODISC(6),              /* loadable */
     93        NODISC(7),              /* loadable */
     94};
     95
     96int     nlinesw = sizeof (linesw) / sizeof (linesw[0]);
     97
    15198extern struct rtems_termios_tty *rtems_termios_ttyHead;
    15299extern struct rtems_termios_tty *rtems_termios_ttyTail;
    153100extern rtems_id rtems_termios_ttyMutex;
     101
     102static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
     103static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
     104/*
     105 * some constants for I/O daemon task creation
     106 */
     107#define TERMIOS_TXTASK_PRIO 10
     108#define TERMIOS_RXTASK_PRIO 9
     109#define TERMIOS_TXTASK_STACKSIZE 1024
     110#define TERMIOS_RXTASK_STACKSIZE 1024
     111/*
     112 * some events to be sent to the I/O tasks
     113 */
     114#define TERMIOS_TX_START_EVENT     RTEMS_EVENT_1
     115#define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0
     116
     117#define TERMIOS_RX_PROC_EVENT      RTEMS_EVENT_1
     118#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
    154119
    155120/*
     
    171136         * See if the device has already been opened
    172137         */
    173         sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     138        sc = rtems_semaphore_obtain (rtems_termios_ttyMutex,
     139                                     RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    174140        if (sc != RTEMS_SUCCESSFUL)
    175141                return sc;
     
    189155                        return RTEMS_NO_MEMORY;
    190156                }
     157                /*
     158                 * allocate raw input buffer
     159                 */
     160                tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
     161                tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
     162                if (tty->rawInBuf.theBuf == NULL) {
     163                        free(tty);
     164                        rtems_semaphore_release (rtems_termios_ttyMutex);
     165                        return RTEMS_NO_MEMORY;
     166                }
     167                /*
     168                 * allocate raw output buffer
     169                 */
     170                tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
     171                tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
     172                if (tty->rawInBuf.theBuf == NULL) {
     173                        free((void *)(tty->rawInBuf.theBuf));
     174                        free(tty);
     175                        rtems_semaphore_release (rtems_termios_ttyMutex);
     176                        return RTEMS_NO_MEMORY;
     177                }
     178                /*
     179                 * allocate cooked buffer
     180                 */
     181                tty->cbuf  = malloc (CBUFSIZE);
     182                if (tty->cbuf == NULL) {
     183                        free((void *)(tty->rawOutBuf.theBuf));
     184                        free((void *)(tty->rawInBuf.theBuf));
     185                        free(tty);
     186                        rtems_semaphore_release (rtems_termios_ttyMutex);
     187                        return RTEMS_NO_MEMORY;
     188                }
     189                /*
     190                 * link tty
     191                 */
    191192                if (rtems_termios_ttyHead)
    192193                        rtems_termios_ttyHead->back = tty;
     
    222223                        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
    223224                        RTEMS_NO_PRIORITY,
    224                         &tty->rawOutBufSemaphore);
     225                        &tty->rawOutBuf.Semaphore);
    225226                if (sc != RTEMS_SUCCESSFUL)
    226227                        rtems_fatal_error_occurred (sc);
     
    231232                 */
    232233                tty->device = *callbacks;
    233                 if (!tty->device.pollRead) {
     234
     235                /*
     236                 * Create I/O tasks
     237                 */
     238                if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     239                        sc = rtems_task_create (
     240                                   rtems_build_name ('T', 'x', 'T', c),
     241                                   TERMIOS_TXTASK_PRIO,
     242                                   TERMIOS_TXTASK_STACKSIZE,
     243                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
     244                                   RTEMS_NO_ASR,
     245                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
     246                                   &tty->txTaskId);
     247                        if (sc != RTEMS_SUCCESSFUL)
     248                                rtems_fatal_error_occurred (sc);
     249                        sc = rtems_task_create (
     250                                   rtems_build_name ('R', 'x', 'T', c),
     251                                   TERMIOS_RXTASK_PRIO,
     252                                   TERMIOS_RXTASK_STACKSIZE,
     253                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
     254                                   RTEMS_NO_ASR,
     255                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
     256                                   &tty->rxTaskId);
     257                        if (sc != RTEMS_SUCCESSFUL)
     258                                rtems_fatal_error_occurred (sc);
     259                               
     260                }
     261                if ((tty->device.pollRead == NULL) ||
     262                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){
    234263                        sc = rtems_semaphore_create (
    235264                                rtems_build_name ('T', 'R', 'r', c),
     
    237266                                RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
    238267                                RTEMS_NO_PRIORITY,
    239                                 &tty->rawInBufSemaphore);
     268                                &tty->rawInBuf.Semaphore);
    240269                        if (sc != RTEMS_SUCCESSFUL)
    241270                                rtems_fatal_error_occurred (sc);
     
    270299                 * set low/highwater mark for XON/XOFF support
    271300                 */
    272                 tty->lowwater  = RAW_INPUT_BUFFER_SIZE * 1/2;
    273                 tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4;
     301                tty->lowwater  = tty->rawInBuf.Size * 1/2;
     302                tty->highwater = tty->rawInBuf.Size * 3/4;
    274303                /*
    275304                 * Bump name characer
     
    280309        }
    281310        args->iop->data1 = tty;
    282         if (!tty->refcount++ && tty->device.firstOpen)
     311        if (!tty->refcount++) {
     312          if (tty->device.firstOpen)
    283313                (*tty->device.firstOpen)(major, minor, arg);
     314          /*
     315           * start I/O tasks, if needed
     316           */
     317          if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     318            sc = rtems_task_start(tty->rxTaskId,
     319                                  rtems_termios_rxdaemon,
     320                                  (rtems_task_argument)tty);
     321            if (sc != RTEMS_SUCCESSFUL)
     322              rtems_fatal_error_occurred (sc);
     323           
     324            sc = rtems_task_start(tty->txTaskId,
     325                                  rtems_termios_txdaemon,
     326                                  (rtems_task_argument)tty);
     327            if (sc != RTEMS_SUCCESSFUL)
     328              rtems_fatal_error_occurred (sc);
     329          }
     330        }
    284331        rtems_semaphore_release (rtems_termios_ttyMutex);
    285332        return RTEMS_SUCCESSFUL;
     
    295342        rtems_status_code sc;
    296343
    297         if (tty->device.outputUsesInterrupts) {
     344        if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) {
    298345                rtems_interrupt_disable (level);
    299                 while (tty->rawOutBufTail != tty->rawOutBufHead) {
     346                while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
    300347                        tty->rawOutBufState = rob_wait;
    301348                        rtems_interrupt_enable (level);
    302                         sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
     349                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
    303350                                                        RTEMS_WAIT,
    304351                                                        RTEMS_NO_TIMEOUT);
     
    322369                rtems_fatal_error_occurred (sc);
    323370        if (--tty->refcount == 0) {
    324                 drainOutput (tty);
     371                if (linesw[tty->t_line].l_close != NULL) {
     372                        /*
     373                         * call discipline-specific close
     374                         */
     375                        sc = linesw[tty->t_line].l_close(tty);
     376                }
     377                else {
     378                        /*
     379                         * default: just flush output buffer
     380                         */
     381                        drainOutput (tty);
     382                }
     383         
     384                if (tty->device.outputUsesInterrupts
     385                    == TERMIOS_TASK_DRIVEN) {
     386                        /*
     387                         * send "terminate" to I/O tasks
     388                         */
     389                        sc = rtems_event_send(
     390                                  tty->rxTaskId,
     391                                  TERMIOS_RX_TERMINATE_EVENT);
     392                        if (sc != RTEMS_SUCCESSFUL)
     393                                rtems_fatal_error_occurred (sc);
     394                        sc = rtems_event_send(
     395                                  tty->txTaskId,
     396                                  TERMIOS_TX_TERMINATE_EVENT);
     397                        if (sc != RTEMS_SUCCESSFUL)
     398                                rtems_fatal_error_occurred (sc);
     399                }
    325400                if (tty->device.lastClose)
    326401                         (*tty->device.lastClose)(tty->major, tty->minor, arg);
     
    335410                rtems_semaphore_delete (tty->isem);
    336411                rtems_semaphore_delete (tty->osem);
    337                 rtems_semaphore_delete (tty->rawOutBufSemaphore);
    338                 if (!tty->device.pollRead)
    339                         rtems_semaphore_delete (tty->rawInBufSemaphore);
     412                rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
     413                if ((tty->device.pollRead == NULL) ||
     414                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN))
     415                        rtems_semaphore_delete (tty->rawInBuf.Semaphore);
    340416                free (tty);
    341417        }
     
    367443        /* if chars available, call write function... */
    368444        (*tty->device.write)(tty->minor,
    369                              (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
     445                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
    370446      }
    371447      /* reenable interrupts */
     
    428504        switch (args->command) {
    429505        default:
    430                 sc = RTEMS_INVALID_NUMBER;
     506                if (linesw[tty->t_line].l_ioctl != NULL) {
     507                        sc = linesw[tty->t_line].l_ioctl(tty,args);
     508                }
     509                else {
     510                        sc = RTEMS_INVALID_NUMBER;
     511                }
    431512                break;
    432513
     
    477558                break;
    478559
     560                /*
     561                 * FIXME: add various ioctl code handlers
     562                 */
     563
     564#if 1 /* FIXME */
     565        case TIOCSETD:
     566                /*
     567                 * close old line discipline
     568                 */
     569                if (linesw[tty->t_line].l_close != NULL) {
     570                        sc = linesw[tty->t_line].l_close(tty);
     571                }
     572                tty->t_line=*(int*)(args->buffer);
     573                tty->t_sc = NULL; /* ensure that no more valid data */
     574                /*
     575                 * open new line discipline
     576                 */
     577                if (linesw[tty->t_line].l_open != NULL) {
     578                        sc = linesw[tty->t_line].l_open(tty);
     579                }
     580                break;
     581        case TIOCGETD: 
     582                *(int*)(args->buffer)=tty->t_line;
     583                break;         
     584#endif
    479585        case FIONREAD:
    480586                /* Half guess that this is the right operation */
     
    490596 * Send characters to device-specific code
    491597 */
    492 static void
    493 osend (const char *buf, int len, struct rtems_termios_tty *tty)
     598void
     599rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty)
    494600{
    495601        unsigned int newHead;
     
    497603        rtems_status_code sc;
    498604
    499         if (!tty->device.outputUsesInterrupts) {
     605        if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) {
    500606                (*tty->device.write)(tty->minor, buf, len);
    501607                return;
    502608        }
    503         newHead = tty->rawOutBufHead;
     609        newHead = tty->rawOutBuf.Head;
    504610        while (len) {
    505611                /*
     
    515621                 * with interrupts enabled.
    516622                 */
    517                 newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
     623                newHead = (newHead + 1) % tty->rawOutBuf.Size;
    518624                rtems_interrupt_disable (level);
    519                 while (newHead == tty->rawOutBufTail) {
     625                while (newHead == tty->rawOutBuf.Tail) {
    520626                        tty->rawOutBufState = rob_wait;
    521627                        rtems_interrupt_enable (level);
    522                         sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
     628                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
    523629                                                        RTEMS_WAIT,
    524630                                                        RTEMS_NO_TIMEOUT);
     
    527633                        rtems_interrupt_disable (level);
    528634                }
    529                 tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
    530                 tty->rawOutBufHead = newHead;
     635                tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++;
     636                tty->rawOutBuf.Head = newHead;
    531637                if (tty->rawOutBufState == rob_idle) {
    532638                  /* check, whether XOFF has been received */
    533639                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
    534640                    (*tty->device.write)(tty->minor,
    535                                 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);
     641                        (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
    536642                  }
    537643                  else {
     
    560666                                tty->column = 0;
    561667                        if (tty->termios.c_oflag & ONLCR) {
    562                                 osend ("\r", 1, tty);
     668                                rtems_termios_puts ("\r", 1, tty);
    563669                                tty->column = 0;
    564670                        }
     
    581687                        if ((tty->termios.c_oflag & TABDLY) == XTABS) {
    582688                                tty->column += i;
    583                                 osend ( "        ",  i, tty);
     689                                rtems_termios_puts ( "        ",  i, tty);
    584690                                return;
    585691                        }
     
    600706                }
    601707        }
    602         osend (&c, 1, tty);
     708        rtems_termios_puts (&c, 1, tty);
    603709}
    604710
     
    613719        if (sc != RTEMS_SUCCESSFUL)
    614720                return sc;
     721        if (linesw[tty->t_line].l_write != NULL) {
     722                sc = linesw[tty->t_line].l_write(tty,args);
     723                rtems_semaphore_release (tty->osem);
     724                return sc;
     725        }
    615726        if (tty->termios.c_oflag & OPOST) {
    616727                unsigned32 count = args->count;
     
    621732        }
    622733        else {
    623                 osend (args->buffer, args->count, tty);
     734                rtems_termios_puts (args->buffer, args->count, tty);
    624735                args->bytes_moved = args->count;
    625736        }
     
    639750                echobuf[0] = '^';
    640751                echobuf[1] = c ^ 0x40;
    641                 osend (echobuf, 2, tty);
     752                rtems_termios_puts (echobuf, 2, tty);
    642753                tty->column += 2;
    643754        }
     
    702813                                 */
    703814                                while (tty->column > col) {
    704                                         osend ("\b", 1, tty);
     815                                        rtems_termios_puts ("\b", 1, tty);
    705816                                        tty->column--;
    706817                                }
     
    708819                        else {
    709820                                if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
    710                                         osend ("\b \b", 3, tty);
     821                                        rtems_termios_puts ("\b \b", 3, tty);
    711822                                        if (tty->column)
    712823                                                tty->column--;
    713824                                }
    714825                                if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
    715                                         osend ("\b \b", 3, tty);
     826                                        rtems_termios_puts ("\b \b", 3, tty);
    716827                                        if (tty->column)
    717828                                                tty->column--;
     
    873984                 * Process characters read from raw queue
    874985                 */
    875                 while (tty->rawInBufHead != tty->rawInBufTail) {
     986                while (tty->rawInBuf.Head != tty->rawInBuf.Tail) {
    876987                        unsigned char c;
    877988                        unsigned int newHead;
    878989
    879                         newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
    880                         c = tty->rawInBuf[newHead];
    881                         tty->rawInBufHead = newHead;
    882                         if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE)
    883                             % RAW_INPUT_BUFFER_SIZE)
     990                        newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
     991                        c = tty->rawInBuf.theBuf[newHead];
     992                        tty->rawInBuf.Head = newHead;
     993                        if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
     994                            % tty->rawInBuf.Size)
    884995                           < tty->lowwater) {
    885996                          tty->flow_ctrl &= ~FL_IREQXOF;
     
    9191030                 * Wait for characters
    9201031                 */
    921                 sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
     1032                sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore,
    9221033                                                tty->rawInBufSemaphoreOptions,
    9231034                                                timeout);
     
    9401051        if (sc != RTEMS_SUCCESSFUL)
    9411052                return sc;
     1053        if (linesw[tty->t_line].l_read != NULL) {
     1054                sc = linesw[tty->t_line].l_read(tty,args);
     1055                rtems_semaphore_release (tty->isem);
     1056                return sc;
     1057        }
    9421058        if (tty->cindex == tty->ccount) {
    9431059                tty->cindex = tty->ccount = 0;
    9441060                tty->read_start_column = tty->column;
    945                 if (tty->device.pollRead)
     1061                if (tty->device.pollRead != NULL
     1062                    && tty->device.outputUsesInterrupts == TERMIOS_POLLED)
    9461063                        sc = fillBufferPoll (tty);
    9471064                else
     
    9571074        rtems_semaphore_release (tty->isem);
    9581075        return sc;
     1076}
     1077
     1078/*
     1079 * signal receive interrupt to rx daemon
     1080 * NOTE: This routine runs in the context of the
     1081 *       device receive interrupt handler.
     1082 */
     1083void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
     1084{
     1085        /*
     1086         * send event to rx daemon task
     1087         */
     1088        rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
    9591089}
    9601090
     
    9741104        boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
    9751105        rtems_interrupt_level level;
     1106
     1107        if (linesw[tty->t_line].l_rint != NULL) {
     1108          while (len--) {
     1109            c = *buf++;
     1110            linesw[tty->t_line].l_rint(c,tty);
     1111          }
     1112          return 0;
     1113        }
    9761114
    9771115        while (len--) {
     
    10111149              /* if chars available, call write function... */
    10121150                (*tty->device.write)(tty->minor,
    1013                                      (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
     1151                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
    10141152              }
    10151153              /* reenable interrupts */
     
    10181156          }     
    10191157          else {
    1020                 newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
     1158                newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
    10211159                /* if chars_in_buffer > highwater                */
    10221160                rtems_interrupt_disable(level);
    1023                 if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE)
    1024                       % RAW_INPUT_BUFFER_SIZE)
     1161                if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
     1162                      % tty->rawInBuf.Size)
    10251163                     > tty->highwater) &&
    10261164                    !(tty->flow_ctrl & FL_IREQXOF)) {
     
    10511189                rtems_interrupt_enable(level);
    10521190
    1053                 if (newTail == tty->rawInBufHead) {
     1191                if (newTail == tty->rawInBuf.Head) {
    10541192                        dropped++;
    10551193                }
    10561194                else {
    1057                         tty->rawInBuf[newTail] = c;
    1058                         tty->rawInBufTail = newTail;
     1195                        tty->rawInBuf.theBuf[newTail] = c;
     1196                        tty->rawInBuf.Tail = newTail;
    10591197                }               
    10601198          }
    10611199        }
    10621200        tty->rawInBufDropped += dropped;
    1063         rtems_semaphore_release (tty->rawInBufSemaphore);
     1201        rtems_semaphore_release (tty->rawInBuf.Semaphore);
    10641202        return dropped;
     1203}
     1204
     1205/*
     1206 * in task-driven mode, this function is called in Tx task context
     1207 * in interrupt-driven mode, this function is called in TxIRQ context
     1208 */
     1209int
     1210rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
     1211{
     1212        unsigned int newTail;
     1213        int nToSend;
     1214        rtems_interrupt_level level;
     1215        int len;
     1216
     1217        /* check for XOF/XON to send */
     1218        if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
     1219            == (FL_MDXOF | FL_IREQXOF)) {
     1220          /* XOFF should be sent now... */
     1221          (*tty->device.write)(tty->minor,
     1222                               &(tty->termios.c_cc[VSTOP]), 1);
     1223
     1224          rtems_interrupt_disable(level);
     1225          tty->t_dqlen--;
     1226          tty->flow_ctrl |= FL_ISNTXOF;
     1227          rtems_interrupt_enable(level);
     1228
     1229          nToSend = 1;
     1230        }
     1231        else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
     1232                 == FL_ISNTXOF) {
     1233          /* NOTE: send XON even, if no longer in XON/XOFF mode... */
     1234          /* XON should be sent now... */
     1235                /*
     1236                 * FIXME: this .write call will generate another
     1237                 * dequeue callback. This will advance the "Tail" in the data
     1238                 * buffer, although the corresponding data is not yet out!
     1239                 * Therefore the dequeue "length" should be reduced by 1
     1240                 */
     1241          (*tty->device.write)(tty->minor,
     1242                               &(tty->termios.c_cc[VSTART]), 1);
     1243
     1244          rtems_interrupt_disable(level);
     1245          tty->t_dqlen--;
     1246          tty->flow_ctrl &= ~FL_ISNTXOF;
     1247          rtems_interrupt_enable(level);
     1248
     1249          nToSend = 1;
     1250        }
     1251        else {
     1252          if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
     1253            /*
     1254             * buffer was empty
     1255             */
     1256            if (tty->rawOutBufState == rob_wait) {
     1257              /*
     1258               * this should never happen...
     1259               */
     1260              rtems_semaphore_release (tty->rawOutBuf.Semaphore);
     1261            }
     1262            return 0;   
     1263          }
     1264
     1265          rtems_interrupt_disable(level);
     1266          len = tty->t_dqlen;
     1267          tty->t_dqlen = 0;
     1268          rtems_interrupt_enable(level);
     1269
     1270          newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
     1271          tty->rawOutBuf.Tail = newTail;
     1272          if (tty->rawOutBufState == rob_wait) {
     1273            /*
     1274             * wake up any pending writer task
     1275             */
     1276            rtems_semaphore_release (tty->rawOutBuf.Semaphore);
     1277          }
     1278          if (newTail == tty->rawOutBuf.Head) {
     1279            /*
     1280             * Buffer has become empty
     1281             */
     1282            tty->rawOutBufState = rob_idle;
     1283            nToSend = 0;
     1284          }
     1285          /* check, whether output should stop due to received XOFF */
     1286          else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
     1287                   ==                (FL_MDXON | FL_ORCVXOF)) {
     1288                  /* Buffer not empty, but output stops due to XOFF */
     1289                  /* set flag, that output has been stopped */
     1290                  rtems_interrupt_disable(level);
     1291                  tty->flow_ctrl |= FL_OSTOP;
     1292                  tty->rawOutBufState = rob_busy; /*apm*/
     1293                  rtems_interrupt_enable(level);
     1294                  nToSend = 0;
     1295          }
     1296          else {
     1297            /*
     1298             * Buffer not empty, start tranmitter
     1299             */
     1300            if (newTail > tty->rawOutBuf.Head)
     1301                    nToSend = tty->rawOutBuf.Size - newTail;
     1302            else
     1303                    nToSend = tty->rawOutBuf.Head - newTail;
     1304            /* when flow control XON or XOF, don't send blocks of data     */
     1305            /* to allow fast reaction on incoming flow ctrl and low latency*/
     1306            /* for outgoing flow control                                   */
     1307            if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
     1308                    nToSend = 1;
     1309            }
     1310            tty->rawOutBufState = rob_busy; /*apm*/
     1311            (*tty->device.write)(tty->minor,
     1312                                 (char *)&tty->rawOutBuf.theBuf[newTail],
     1313                                 nToSend);
     1314          }
     1315          tty->rawOutBuf.Tail = newTail; /*apm*/
     1316        }
     1317        return nToSend;
    10651318}
    10661319
     
    10781331{
    10791332        struct rtems_termios_tty *tty = ttyp;
    1080         unsigned int newTail;
    1081         int nToSend;
    1082 
    1083         /* check for XOF/XON to send */
    1084         if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
    1085             == (FL_MDXOF | FL_IREQXOF)) {
    1086           /* XOFF should be sent now... */
    1087           (*tty->device.write)(tty->minor,
    1088                                &(tty->termios.c_cc[VSTOP]), 1);
    1089           tty->flow_ctrl |= FL_ISNTXOF;
    1090           nToSend = 1;
    1091         }
    1092         else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
    1093                  == FL_ISNTXOF) {
    1094           /* NOTE: send XON even, if no longer in XON/XOFF mode... */
    1095           /* XON should be sent now... */
    1096           (*tty->device.write)(tty->minor,
    1097                                &(tty->termios.c_cc[VSTART]), 1);
    1098           tty->flow_ctrl &= ~FL_ISNTXOF;
    1099           nToSend = 1;
     1333        rtems_status_code sc;
     1334
     1335        /*
     1336         * sum up character count already sent
     1337         */
     1338        tty->t_dqlen += len;
     1339
     1340        if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     1341                /*
     1342                 * send wake up to transmitter task
     1343                 */
     1344                sc = rtems_event_send(tty->txTaskId,
     1345                                      TERMIOS_TX_START_EVENT);
     1346                if (sc != RTEMS_SUCCESSFUL)
     1347                        rtems_fatal_error_occurred (sc);
     1348                return 0; /* nothing to output in IRQ... */
    11001349        }
    11011350        else {
    1102           if (tty->rawOutBufState == rob_wait)
    1103             rtems_semaphore_release (tty->rawOutBufSemaphore);
    1104           if ( tty->rawOutBufHead == tty->rawOutBufTail ) {
    1105             tty->rawOutBufState = rob_idle;
    1106             return 0;   
    1107           }
    1108           newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
    1109           if (newTail == tty->rawOutBufHead) {
    1110             /*
    1111              * Buffer empty
    1112              */
    1113             tty->rawOutBufState = rob_idle;
    1114             nToSend = 0;
    1115           }
    1116           /* check, whether output should stop due to received XOFF */
    1117           else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
    1118                    ==                (FL_MDXON | FL_ORCVXOF)) {
    1119             /* Buffer not empty, but output stops due to XOFF */
    1120             /* set flag, that output has been stopped */
    1121             tty->flow_ctrl |= FL_OSTOP;
    1122             tty->rawOutBufState = rob_busy;
    1123             nToSend = 0;
    1124           }
    1125           else {
    1126             /*
    1127              * Buffer not empty, start tranmitter
    1128              */
    1129             if (newTail > tty->rawOutBufHead)
    1130               nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
    1131             else
    1132               nToSend = tty->rawOutBufHead - newTail;
    1133             /* when flow control XON or XOF, don't send blocks of data     */
    1134             /* to allow fast reaction on incoming flow ctrl and low latency*/
    1135             /* for outgoing flow control                                   */
    1136             if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF))
    1137               nToSend = 1;
    1138             tty->rawOutBufState = rob_busy;
    1139             (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
    1140           }
    1141           tty->rawOutBufTail = newTail;
    1142         }
    1143         return nToSend;
    1144 }
     1351                return rtems_termios_refill_transmitter(tty);
     1352        }
     1353}
     1354
     1355/*
     1356 * this task actually processes any transmit events
     1357 */
     1358static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
     1359{
     1360        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
     1361        rtems_event_set the_event;
     1362
     1363        while (1) {
     1364                /*
     1365                 * wait for rtems event
     1366                 */
     1367                rtems_event_receive((TERMIOS_TX_START_EVENT |
     1368                                     TERMIOS_TX_TERMINATE_EVENT),
     1369                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
     1370                                    RTEMS_NO_TIMEOUT,
     1371                                    &the_event);
     1372                if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
     1373                        tty->txTaskId = 0;
     1374                        rtems_task_delete(RTEMS_SELF);
     1375                }
     1376                else {
     1377                        /*
     1378                         * call any line discipline start function
     1379                         */
     1380                        if (linesw[tty->t_line].l_start != NULL) {
     1381                                linesw[tty->t_line].l_start(tty);
     1382                        }
     1383                        /*
     1384                         * try to push further characters to device
     1385                         */
     1386                        rtems_termios_refill_transmitter(tty);
     1387                }
     1388        }
     1389}
     1390
     1391/*
     1392 * this task actually processes any receive events
     1393 */
     1394static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
     1395{
     1396        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
     1397        rtems_event_set the_event;
     1398        int c;
     1399        char c_buf;
     1400        while (1) {
     1401                /*
     1402                 * wait for rtems event
     1403                 */
     1404                rtems_event_receive((TERMIOS_RX_PROC_EVENT |
     1405                                     TERMIOS_RX_TERMINATE_EVENT),
     1406                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
     1407                                    RTEMS_NO_TIMEOUT,
     1408                                    &the_event);
     1409                if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
     1410                        tty->rxTaskId = 0;
     1411                        rtems_task_delete(RTEMS_SELF);
     1412                }
     1413                else {
     1414                        /*
     1415                         * do something
     1416                         */
     1417                        c = tty->device.pollRead(tty->minor);
     1418                        if (c != EOF) {
     1419                                /*
     1420                                 * pollRead did call enqueue on its own
     1421                                 */
     1422                                c_buf = c;
     1423                                rtems_termios_enqueue_raw_characters (
     1424                                      tty,&c_buf,1);
     1425                        }
     1426                }
     1427        }
     1428}
  • cpukit/libcsupport/src/termios.c

    rc8471315 re2af631  
    2424#include <termios.h>
    2525#include <unistd.h>
     26#include <sys/ttycom.h>
     27
     28#include "termiostypes.h"
    2629
    2730/*
     
    6164#define RAW_OUTPUT_BUFFER_SIZE  64
    6265
    63 /*
    64  * Variables associated with each termios instance.
    65  * One structure for each hardware I/O device.
    66  */
    67 struct rtems_termios_tty {
    68         /*
    69          * Linked-list of active TERMIOS devices
    70          */
    71         struct rtems_termios_tty        *forw;
    72         struct rtems_termios_tty        *back;
    73 
    74         /*
    75          * How many times has this device been opened
    76          */
    77         int             refcount;
    78 
    79         /*
    80          * This device
    81          */
    82         rtems_device_major_number       major;
    83         rtems_device_major_number       minor;
    84 
    85         /*
    86          * Mutual-exclusion semaphores
    87          */
    88         rtems_id        isem;
    89         rtems_id        osem;
    90 
    91         /*
    92          * The canonical (cooked) character buffer
    93          */
    94         char            cbuf[CBUFSIZE];
    95         int             ccount;
    96         int             cindex;
    97 
    98         /*
    99          * Keep track of cursor (printhead) position
    100          */
    101         int             column;
    102         int             read_start_column;
    103 
    104         /*
    105          * The ioctl settings
    106          */
    107         struct termios  termios;
    108         rtems_interval  vtimeTicks;
    109 
    110         /*
    111          * Raw input character buffer
    112          */
    113         volatile char           rawInBuf[RAW_INPUT_BUFFER_SIZE];
    114         volatile unsigned int   rawInBufHead;
    115         volatile unsigned int   rawInBufTail;
    116         rtems_id                rawInBufSemaphore;
    117         rtems_unsigned32        rawInBufSemaphoreOptions;
    118         rtems_interval          rawInBufSemaphoreTimeout;
    119         rtems_interval          rawInBufSemaphoreFirstTimeout;
    120         unsigned int            rawInBufDropped;        /* Statistics */
    121 
    122         /*
    123          * Raw output character buffer
    124          */
    125         volatile char           rawOutBuf[RAW_OUTPUT_BUFFER_SIZE];
    126         volatile unsigned int   rawOutBufHead;
    127         volatile unsigned int   rawOutBufTail;
    128         rtems_id                rawOutBufSemaphore;
    129         volatile enum {rob_idle, rob_busy, rob_wait }   rawOutBufState;
    130 
    131         /*
    132          * Callbacks to device-specific routines
    133          */
    134         rtems_termios_callbacks device;
    135         volatile unsigned int   flow_ctrl;
    136         unsigned int            lowwater,highwater;
    137 };
    138 
    13966/* fields for "flow_ctrl" status */
    14067#define FL_IREQXOF 1        /* input queue requests stop of incoming data */
     
    14976#define FL_MDXOF   0x400    /* output controlled with XON/XOFF protocol   */
    15077
     78#define NODISC(n) \
     79        { NULL, NULL,   NULL,   NULL, \
     80          NULL, NULL,   NULL,   NULL }
     81/*
     82 * FIXME: change linesw entries consistant with linesw entry usage...
     83 */
     84struct  linesw linesw[MAXLDISC] =
     85{
     86        NODISC(0),              /* 0- termios-built-in */
     87        NODISC(1),              /* 1- defunct */
     88        NODISC(2),              /* 2- NTTYDISC */
     89        NODISC(3),              /* TABLDISC */
     90        NODISC(4),              /* SLIPDISC */
     91        NODISC(5),              /* PPPDISC */
     92        NODISC(6),              /* loadable */
     93        NODISC(7),              /* loadable */
     94};
     95
     96int     nlinesw = sizeof (linesw) / sizeof (linesw[0]);
     97
    15198extern struct rtems_termios_tty *rtems_termios_ttyHead;
    15299extern struct rtems_termios_tty *rtems_termios_ttyTail;
    153100extern rtems_id rtems_termios_ttyMutex;
     101
     102static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
     103static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
     104/*
     105 * some constants for I/O daemon task creation
     106 */
     107#define TERMIOS_TXTASK_PRIO 10
     108#define TERMIOS_RXTASK_PRIO 9
     109#define TERMIOS_TXTASK_STACKSIZE 1024
     110#define TERMIOS_RXTASK_STACKSIZE 1024
     111/*
     112 * some events to be sent to the I/O tasks
     113 */
     114#define TERMIOS_TX_START_EVENT     RTEMS_EVENT_1
     115#define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0
     116
     117#define TERMIOS_RX_PROC_EVENT      RTEMS_EVENT_1
     118#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
    154119
    155120/*
     
    171136         * See if the device has already been opened
    172137         */
    173         sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     138        sc = rtems_semaphore_obtain (rtems_termios_ttyMutex,
     139                                     RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    174140        if (sc != RTEMS_SUCCESSFUL)
    175141                return sc;
     
    189155                        return RTEMS_NO_MEMORY;
    190156                }
     157                /*
     158                 * allocate raw input buffer
     159                 */
     160                tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
     161                tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
     162                if (tty->rawInBuf.theBuf == NULL) {
     163                        free(tty);
     164                        rtems_semaphore_release (rtems_termios_ttyMutex);
     165                        return RTEMS_NO_MEMORY;
     166                }
     167                /*
     168                 * allocate raw output buffer
     169                 */
     170                tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
     171                tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
     172                if (tty->rawInBuf.theBuf == NULL) {
     173                        free((void *)(tty->rawInBuf.theBuf));
     174                        free(tty);
     175                        rtems_semaphore_release (rtems_termios_ttyMutex);
     176                        return RTEMS_NO_MEMORY;
     177                }
     178                /*
     179                 * allocate cooked buffer
     180                 */
     181                tty->cbuf  = malloc (CBUFSIZE);
     182                if (tty->cbuf == NULL) {
     183                        free((void *)(tty->rawOutBuf.theBuf));
     184                        free((void *)(tty->rawInBuf.theBuf));
     185                        free(tty);
     186                        rtems_semaphore_release (rtems_termios_ttyMutex);
     187                        return RTEMS_NO_MEMORY;
     188                }
     189                /*
     190                 * link tty
     191                 */
    191192                if (rtems_termios_ttyHead)
    192193                        rtems_termios_ttyHead->back = tty;
     
    222223                        RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,
    223224                        RTEMS_NO_PRIORITY,
    224                         &tty->rawOutBufSemaphore);
     225                        &tty->rawOutBuf.Semaphore);
    225226                if (sc != RTEMS_SUCCESSFUL)
    226227                        rtems_fatal_error_occurred (sc);
     
    231232                 */
    232233                tty->device = *callbacks;
    233                 if (!tty->device.pollRead) {
     234
     235                /*
     236                 * Create I/O tasks
     237                 */
     238                if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     239                        sc = rtems_task_create (
     240                                   rtems_build_name ('T', 'x', 'T', c),
     241                                   TERMIOS_TXTASK_PRIO,
     242                                   TERMIOS_TXTASK_STACKSIZE,
     243                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
     244                                   RTEMS_NO_ASR,
     245                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
     246                                   &tty->txTaskId);
     247                        if (sc != RTEMS_SUCCESSFUL)
     248                                rtems_fatal_error_occurred (sc);
     249                        sc = rtems_task_create (
     250                                   rtems_build_name ('R', 'x', 'T', c),
     251                                   TERMIOS_RXTASK_PRIO,
     252                                   TERMIOS_RXTASK_STACKSIZE,
     253                                   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
     254                                   RTEMS_NO_ASR,
     255                                   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
     256                                   &tty->rxTaskId);
     257                        if (sc != RTEMS_SUCCESSFUL)
     258                                rtems_fatal_error_occurred (sc);
     259                               
     260                }
     261                if ((tty->device.pollRead == NULL) ||
     262                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){
    234263                        sc = rtems_semaphore_create (
    235264                                rtems_build_name ('T', 'R', 'r', c),
     
    237266                                RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
    238267                                RTEMS_NO_PRIORITY,
    239                                 &tty->rawInBufSemaphore);
     268                                &tty->rawInBuf.Semaphore);
    240269                        if (sc != RTEMS_SUCCESSFUL)
    241270                                rtems_fatal_error_occurred (sc);
     
    270299                 * set low/highwater mark for XON/XOFF support
    271300                 */
    272                 tty->lowwater  = RAW_INPUT_BUFFER_SIZE * 1/2;
    273                 tty->highwater = RAW_INPUT_BUFFER_SIZE * 3/4;
     301                tty->lowwater  = tty->rawInBuf.Size * 1/2;
     302                tty->highwater = tty->rawInBuf.Size * 3/4;
    274303                /*
    275304                 * Bump name characer
     
    280309        }
    281310        args->iop->data1 = tty;
    282         if (!tty->refcount++ && tty->device.firstOpen)
     311        if (!tty->refcount++) {
     312          if (tty->device.firstOpen)
    283313                (*tty->device.firstOpen)(major, minor, arg);
     314          /*
     315           * start I/O tasks, if needed
     316           */
     317          if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     318            sc = rtems_task_start(tty->rxTaskId,
     319                                  rtems_termios_rxdaemon,
     320                                  (rtems_task_argument)tty);
     321            if (sc != RTEMS_SUCCESSFUL)
     322              rtems_fatal_error_occurred (sc);
     323           
     324            sc = rtems_task_start(tty->txTaskId,
     325                                  rtems_termios_txdaemon,
     326                                  (rtems_task_argument)tty);
     327            if (sc != RTEMS_SUCCESSFUL)
     328              rtems_fatal_error_occurred (sc);
     329          }
     330        }
    284331        rtems_semaphore_release (rtems_termios_ttyMutex);
    285332        return RTEMS_SUCCESSFUL;
     
    295342        rtems_status_code sc;
    296343
    297         if (tty->device.outputUsesInterrupts) {
     344        if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) {
    298345                rtems_interrupt_disable (level);
    299                 while (tty->rawOutBufTail != tty->rawOutBufHead) {
     346                while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
    300347                        tty->rawOutBufState = rob_wait;
    301348                        rtems_interrupt_enable (level);
    302                         sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
     349                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
    303350                                                        RTEMS_WAIT,
    304351                                                        RTEMS_NO_TIMEOUT);
     
    322369                rtems_fatal_error_occurred (sc);
    323370        if (--tty->refcount == 0) {
    324                 drainOutput (tty);
     371                if (linesw[tty->t_line].l_close != NULL) {
     372                        /*
     373                         * call discipline-specific close
     374                         */
     375                        sc = linesw[tty->t_line].l_close(tty);
     376                }
     377                else {
     378                        /*
     379                         * default: just flush output buffer
     380                         */
     381                        drainOutput (tty);
     382                }
     383         
     384                if (tty->device.outputUsesInterrupts
     385                    == TERMIOS_TASK_DRIVEN) {
     386                        /*
     387                         * send "terminate" to I/O tasks
     388                         */
     389                        sc = rtems_event_send(
     390                                  tty->rxTaskId,
     391                                  TERMIOS_RX_TERMINATE_EVENT);
     392                        if (sc != RTEMS_SUCCESSFUL)
     393                                rtems_fatal_error_occurred (sc);
     394                        sc = rtems_event_send(
     395                                  tty->txTaskId,
     396                                  TERMIOS_TX_TERMINATE_EVENT);
     397                        if (sc != RTEMS_SUCCESSFUL)
     398                                rtems_fatal_error_occurred (sc);
     399                }
    325400                if (tty->device.lastClose)
    326401                         (*tty->device.lastClose)(tty->major, tty->minor, arg);
     
    335410                rtems_semaphore_delete (tty->isem);
    336411                rtems_semaphore_delete (tty->osem);
    337                 rtems_semaphore_delete (tty->rawOutBufSemaphore);
    338                 if (!tty->device.pollRead)
    339                         rtems_semaphore_delete (tty->rawInBufSemaphore);
     412                rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
     413                if ((tty->device.pollRead == NULL) ||
     414                    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN))
     415                        rtems_semaphore_delete (tty->rawInBuf.Semaphore);
    340416                free (tty);
    341417        }
     
    367443        /* if chars available, call write function... */
    368444        (*tty->device.write)(tty->minor,
    369                              (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
     445                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
    370446      }
    371447      /* reenable interrupts */
     
    428504        switch (args->command) {
    429505        default:
    430                 sc = RTEMS_INVALID_NUMBER;
     506                if (linesw[tty->t_line].l_ioctl != NULL) {
     507                        sc = linesw[tty->t_line].l_ioctl(tty,args);
     508                }
     509                else {
     510                        sc = RTEMS_INVALID_NUMBER;
     511                }
    431512                break;
    432513
     
    477558                break;
    478559
     560                /*
     561                 * FIXME: add various ioctl code handlers
     562                 */
     563
     564#if 1 /* FIXME */
     565        case TIOCSETD:
     566                /*
     567                 * close old line discipline
     568                 */
     569                if (linesw[tty->t_line].l_close != NULL) {
     570                        sc = linesw[tty->t_line].l_close(tty);
     571                }
     572                tty->t_line=*(int*)(args->buffer);
     573                tty->t_sc = NULL; /* ensure that no more valid data */
     574                /*
     575                 * open new line discipline
     576                 */
     577                if (linesw[tty->t_line].l_open != NULL) {
     578                        sc = linesw[tty->t_line].l_open(tty);
     579                }
     580                break;
     581        case TIOCGETD: 
     582                *(int*)(args->buffer)=tty->t_line;
     583                break;         
     584#endif
    479585        case FIONREAD:
    480586                /* Half guess that this is the right operation */
     
    490596 * Send characters to device-specific code
    491597 */
    492 static void
    493 osend (const char *buf, int len, struct rtems_termios_tty *tty)
     598void
     599rtems_termios_puts (const char *buf, int len, struct rtems_termios_tty *tty)
    494600{
    495601        unsigned int newHead;
     
    497603        rtems_status_code sc;
    498604
    499         if (!tty->device.outputUsesInterrupts) {
     605        if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) {
    500606                (*tty->device.write)(tty->minor, buf, len);
    501607                return;
    502608        }
    503         newHead = tty->rawOutBufHead;
     609        newHead = tty->rawOutBuf.Head;
    504610        while (len) {
    505611                /*
     
    515621                 * with interrupts enabled.
    516622                 */
    517                 newHead = (newHead + 1) % RAW_OUTPUT_BUFFER_SIZE;
     623                newHead = (newHead + 1) % tty->rawOutBuf.Size;
    518624                rtems_interrupt_disable (level);
    519                 while (newHead == tty->rawOutBufTail) {
     625                while (newHead == tty->rawOutBuf.Tail) {
    520626                        tty->rawOutBufState = rob_wait;
    521627                        rtems_interrupt_enable (level);
    522                         sc = rtems_semaphore_obtain (tty->rawOutBufSemaphore,
     628                        sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,
    523629                                                        RTEMS_WAIT,
    524630                                                        RTEMS_NO_TIMEOUT);
     
    527633                        rtems_interrupt_disable (level);
    528634                }
    529                 tty->rawOutBuf[tty->rawOutBufHead] = *buf++;
    530                 tty->rawOutBufHead = newHead;
     635                tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++;
     636                tty->rawOutBuf.Head = newHead;
    531637                if (tty->rawOutBufState == rob_idle) {
    532638                  /* check, whether XOFF has been received */
    533639                  if (!(tty->flow_ctrl & FL_ORCVXOF)) {
    534640                    (*tty->device.write)(tty->minor,
    535                                 (char *)&tty->rawOutBuf[tty->rawOutBufTail],1);
     641                        (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
    536642                  }
    537643                  else {
     
    560666                                tty->column = 0;
    561667                        if (tty->termios.c_oflag & ONLCR) {
    562                                 osend ("\r", 1, tty);
     668                                rtems_termios_puts ("\r", 1, tty);
    563669                                tty->column = 0;
    564670                        }
     
    581687                        if ((tty->termios.c_oflag & TABDLY) == XTABS) {
    582688                                tty->column += i;
    583                                 osend ( "        ",  i, tty);
     689                                rtems_termios_puts ( "        ",  i, tty);
    584690                                return;
    585691                        }
     
    600706                }
    601707        }
    602         osend (&c, 1, tty);
     708        rtems_termios_puts (&c, 1, tty);
    603709}
    604710
     
    613719        if (sc != RTEMS_SUCCESSFUL)
    614720                return sc;
     721        if (linesw[tty->t_line].l_write != NULL) {
     722                sc = linesw[tty->t_line].l_write(tty,args);
     723                rtems_semaphore_release (tty->osem);
     724                return sc;
     725        }
    615726        if (tty->termios.c_oflag & OPOST) {
    616727                unsigned32 count = args->count;
     
    621732        }
    622733        else {
    623                 osend (args->buffer, args->count, tty);
     734                rtems_termios_puts (args->buffer, args->count, tty);
    624735                args->bytes_moved = args->count;
    625736        }
     
    639750                echobuf[0] = '^';
    640751                echobuf[1] = c ^ 0x40;
    641                 osend (echobuf, 2, tty);
     752                rtems_termios_puts (echobuf, 2, tty);
    642753                tty->column += 2;
    643754        }
     
    702813                                 */
    703814                                while (tty->column > col) {
    704                                         osend ("\b", 1, tty);
     815                                        rtems_termios_puts ("\b", 1, tty);
    705816                                        tty->column--;
    706817                                }
     
    708819                        else {
    709820                                if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
    710                                         osend ("\b \b", 3, tty);
     821                                        rtems_termios_puts ("\b \b", 3, tty);
    711822                                        if (tty->column)
    712823                                                tty->column--;
    713824                                }
    714825                                if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
    715                                         osend ("\b \b", 3, tty);
     826                                        rtems_termios_puts ("\b \b", 3, tty);
    716827                                        if (tty->column)
    717828                                                tty->column--;
     
    873984                 * Process characters read from raw queue
    874985                 */
    875                 while (tty->rawInBufHead != tty->rawInBufTail) {
     986                while (tty->rawInBuf.Head != tty->rawInBuf.Tail) {
    876987                        unsigned char c;
    877988                        unsigned int newHead;
    878989
    879                         newHead = (tty->rawInBufHead + 1) % RAW_INPUT_BUFFER_SIZE;
    880                         c = tty->rawInBuf[newHead];
    881                         tty->rawInBufHead = newHead;
    882                         if(((tty->rawInBufTail-newHead+RAW_INPUT_BUFFER_SIZE)
    883                             % RAW_INPUT_BUFFER_SIZE)
     990                        newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
     991                        c = tty->rawInBuf.theBuf[newHead];
     992                        tty->rawInBuf.Head = newHead;
     993                        if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
     994                            % tty->rawInBuf.Size)
    884995                           < tty->lowwater) {
    885996                          tty->flow_ctrl &= ~FL_IREQXOF;
     
    9191030                 * Wait for characters
    9201031                 */
    921                 sc = rtems_semaphore_obtain (tty->rawInBufSemaphore,
     1032                sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore,
    9221033                                                tty->rawInBufSemaphoreOptions,
    9231034                                                timeout);
     
    9401051        if (sc != RTEMS_SUCCESSFUL)
    9411052                return sc;
     1053        if (linesw[tty->t_line].l_read != NULL) {
     1054                sc = linesw[tty->t_line].l_read(tty,args);
     1055                rtems_semaphore_release (tty->isem);
     1056                return sc;
     1057        }
    9421058        if (tty->cindex == tty->ccount) {
    9431059                tty->cindex = tty->ccount = 0;
    9441060                tty->read_start_column = tty->column;
    945                 if (tty->device.pollRead)
     1061                if (tty->device.pollRead != NULL
     1062                    && tty->device.outputUsesInterrupts == TERMIOS_POLLED)
    9461063                        sc = fillBufferPoll (tty);
    9471064                else
     
    9571074        rtems_semaphore_release (tty->isem);
    9581075        return sc;
     1076}
     1077
     1078/*
     1079 * signal receive interrupt to rx daemon
     1080 * NOTE: This routine runs in the context of the
     1081 *       device receive interrupt handler.
     1082 */
     1083void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
     1084{
     1085        /*
     1086         * send event to rx daemon task
     1087         */
     1088        rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
    9591089}
    9601090
     
    9741104        boolean flow_rcv = FALSE; /* TRUE, if flow control char received */
    9751105        rtems_interrupt_level level;
     1106
     1107        if (linesw[tty->t_line].l_rint != NULL) {
     1108          while (len--) {
     1109            c = *buf++;
     1110            linesw[tty->t_line].l_rint(c,tty);
     1111          }
     1112          return 0;
     1113        }
    9761114
    9771115        while (len--) {
     
    10111149              /* if chars available, call write function... */
    10121150                (*tty->device.write)(tty->minor,
    1013                                      (char *)&tty->rawOutBuf[tty->rawOutBufTail], 1);
     1151                     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
    10141152              }
    10151153              /* reenable interrupts */
     
    10181156          }     
    10191157          else {
    1020                 newTail = (tty->rawInBufTail + 1) % RAW_INPUT_BUFFER_SIZE;
     1158                newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
    10211159                /* if chars_in_buffer > highwater                */
    10221160                rtems_interrupt_disable(level);
    1023                 if ((((newTail - tty->rawInBufHead + RAW_INPUT_BUFFER_SIZE)
    1024                       % RAW_INPUT_BUFFER_SIZE)
     1161                if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
     1162                      % tty->rawInBuf.Size)
    10251163                     > tty->highwater) &&
    10261164                    !(tty->flow_ctrl & FL_IREQXOF)) {
     
    10511189                rtems_interrupt_enable(level);
    10521190
    1053                 if (newTail == tty->rawInBufHead) {
     1191                if (newTail == tty->rawInBuf.Head) {
    10541192                        dropped++;
    10551193                }
    10561194                else {
    1057                         tty->rawInBuf[newTail] = c;
    1058                         tty->rawInBufTail = newTail;
     1195                        tty->rawInBuf.theBuf[newTail] = c;
     1196                        tty->rawInBuf.Tail = newTail;
    10591197                }               
    10601198          }
    10611199        }
    10621200        tty->rawInBufDropped += dropped;
    1063         rtems_semaphore_release (tty->rawInBufSemaphore);
     1201        rtems_semaphore_release (tty->rawInBuf.Semaphore);
    10641202        return dropped;
     1203}
     1204
     1205/*
     1206 * in task-driven mode, this function is called in Tx task context
     1207 * in interrupt-driven mode, this function is called in TxIRQ context
     1208 */
     1209int
     1210rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
     1211{
     1212        unsigned int newTail;
     1213        int nToSend;
     1214        rtems_interrupt_level level;
     1215        int len;
     1216
     1217        /* check for XOF/XON to send */
     1218        if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
     1219            == (FL_MDXOF | FL_IREQXOF)) {
     1220          /* XOFF should be sent now... */
     1221          (*tty->device.write)(tty->minor,
     1222                               &(tty->termios.c_cc[VSTOP]), 1);
     1223
     1224          rtems_interrupt_disable(level);
     1225          tty->t_dqlen--;
     1226          tty->flow_ctrl |= FL_ISNTXOF;
     1227          rtems_interrupt_enable(level);
     1228
     1229          nToSend = 1;
     1230        }
     1231        else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
     1232                 == FL_ISNTXOF) {
     1233          /* NOTE: send XON even, if no longer in XON/XOFF mode... */
     1234          /* XON should be sent now... */
     1235                /*
     1236                 * FIXME: this .write call will generate another
     1237                 * dequeue callback. This will advance the "Tail" in the data
     1238                 * buffer, although the corresponding data is not yet out!
     1239                 * Therefore the dequeue "length" should be reduced by 1
     1240                 */
     1241          (*tty->device.write)(tty->minor,
     1242                               &(tty->termios.c_cc[VSTART]), 1);
     1243
     1244          rtems_interrupt_disable(level);
     1245          tty->t_dqlen--;
     1246          tty->flow_ctrl &= ~FL_ISNTXOF;
     1247          rtems_interrupt_enable(level);
     1248
     1249          nToSend = 1;
     1250        }
     1251        else {
     1252          if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
     1253            /*
     1254             * buffer was empty
     1255             */
     1256            if (tty->rawOutBufState == rob_wait) {
     1257              /*
     1258               * this should never happen...
     1259               */
     1260              rtems_semaphore_release (tty->rawOutBuf.Semaphore);
     1261            }
     1262            return 0;   
     1263          }
     1264
     1265          rtems_interrupt_disable(level);
     1266          len = tty->t_dqlen;
     1267          tty->t_dqlen = 0;
     1268          rtems_interrupt_enable(level);
     1269
     1270          newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
     1271          tty->rawOutBuf.Tail = newTail;
     1272          if (tty->rawOutBufState == rob_wait) {
     1273            /*
     1274             * wake up any pending writer task
     1275             */
     1276            rtems_semaphore_release (tty->rawOutBuf.Semaphore);
     1277          }
     1278          if (newTail == tty->rawOutBuf.Head) {
     1279            /*
     1280             * Buffer has become empty
     1281             */
     1282            tty->rawOutBufState = rob_idle;
     1283            nToSend = 0;
     1284          }
     1285          /* check, whether output should stop due to received XOFF */
     1286          else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
     1287                   ==                (FL_MDXON | FL_ORCVXOF)) {
     1288                  /* Buffer not empty, but output stops due to XOFF */
     1289                  /* set flag, that output has been stopped */
     1290                  rtems_interrupt_disable(level);
     1291                  tty->flow_ctrl |= FL_OSTOP;
     1292                  tty->rawOutBufState = rob_busy; /*apm*/
     1293                  rtems_interrupt_enable(level);
     1294                  nToSend = 0;
     1295          }
     1296          else {
     1297            /*
     1298             * Buffer not empty, start tranmitter
     1299             */
     1300            if (newTail > tty->rawOutBuf.Head)
     1301                    nToSend = tty->rawOutBuf.Size - newTail;
     1302            else
     1303                    nToSend = tty->rawOutBuf.Head - newTail;
     1304            /* when flow control XON or XOF, don't send blocks of data     */
     1305            /* to allow fast reaction on incoming flow ctrl and low latency*/
     1306            /* for outgoing flow control                                   */
     1307            if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {
     1308                    nToSend = 1;
     1309            }
     1310            tty->rawOutBufState = rob_busy; /*apm*/
     1311            (*tty->device.write)(tty->minor,
     1312                                 (char *)&tty->rawOutBuf.theBuf[newTail],
     1313                                 nToSend);
     1314          }
     1315          tty->rawOutBuf.Tail = newTail; /*apm*/
     1316        }
     1317        return nToSend;
    10651318}
    10661319
     
    10781331{
    10791332        struct rtems_termios_tty *tty = ttyp;
    1080         unsigned int newTail;
    1081         int nToSend;
    1082 
    1083         /* check for XOF/XON to send */
    1084         if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
    1085             == (FL_MDXOF | FL_IREQXOF)) {
    1086           /* XOFF should be sent now... */
    1087           (*tty->device.write)(tty->minor,
    1088                                &(tty->termios.c_cc[VSTOP]), 1);
    1089           tty->flow_ctrl |= FL_ISNTXOF;
    1090           nToSend = 1;
    1091         }
    1092         else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))
    1093                  == FL_ISNTXOF) {
    1094           /* NOTE: send XON even, if no longer in XON/XOFF mode... */
    1095           /* XON should be sent now... */
    1096           (*tty->device.write)(tty->minor,
    1097                                &(tty->termios.c_cc[VSTART]), 1);
    1098           tty->flow_ctrl &= ~FL_ISNTXOF;
    1099           nToSend = 1;
     1333        rtems_status_code sc;
     1334
     1335        /*
     1336         * sum up character count already sent
     1337         */
     1338        tty->t_dqlen += len;
     1339
     1340        if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
     1341                /*
     1342                 * send wake up to transmitter task
     1343                 */
     1344                sc = rtems_event_send(tty->txTaskId,
     1345                                      TERMIOS_TX_START_EVENT);
     1346                if (sc != RTEMS_SUCCESSFUL)
     1347                        rtems_fatal_error_occurred (sc);
     1348                return 0; /* nothing to output in IRQ... */
    11001349        }
    11011350        else {
    1102           if (tty->rawOutBufState == rob_wait)
    1103             rtems_semaphore_release (tty->rawOutBufSemaphore);
    1104           if ( tty->rawOutBufHead == tty->rawOutBufTail ) {
    1105             tty->rawOutBufState = rob_idle;
    1106             return 0;   
    1107           }
    1108           newTail = (tty->rawOutBufTail + len) % RAW_OUTPUT_BUFFER_SIZE;
    1109           if (newTail == tty->rawOutBufHead) {
    1110             /*
    1111              * Buffer empty
    1112              */
    1113             tty->rawOutBufState = rob_idle;
    1114             nToSend = 0;
    1115           }
    1116           /* check, whether output should stop due to received XOFF */
    1117           else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF))
    1118                    ==                (FL_MDXON | FL_ORCVXOF)) {
    1119             /* Buffer not empty, but output stops due to XOFF */
    1120             /* set flag, that output has been stopped */
    1121             tty->flow_ctrl |= FL_OSTOP;
    1122             tty->rawOutBufState = rob_busy;
    1123             nToSend = 0;
    1124           }
    1125           else {
    1126             /*
    1127              * Buffer not empty, start tranmitter
    1128              */
    1129             if (newTail > tty->rawOutBufHead)
    1130               nToSend = RAW_OUTPUT_BUFFER_SIZE - newTail;
    1131             else
    1132               nToSend = tty->rawOutBufHead - newTail;
    1133             /* when flow control XON or XOF, don't send blocks of data     */
    1134             /* to allow fast reaction on incoming flow ctrl and low latency*/
    1135             /* for outgoing flow control                                   */
    1136             if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF))
    1137               nToSend = 1;
    1138             tty->rawOutBufState = rob_busy;
    1139             (*tty->device.write)(tty->minor, (char *)&tty->rawOutBuf[newTail], nToSend);
    1140           }
    1141           tty->rawOutBufTail = newTail;
    1142         }
    1143         return nToSend;
    1144 }
     1351                return rtems_termios_refill_transmitter(tty);
     1352        }
     1353}
     1354
     1355/*
     1356 * this task actually processes any transmit events
     1357 */
     1358static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
     1359{
     1360        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
     1361        rtems_event_set the_event;
     1362
     1363        while (1) {
     1364                /*
     1365                 * wait for rtems event
     1366                 */
     1367                rtems_event_receive((TERMIOS_TX_START_EVENT |
     1368                                     TERMIOS_TX_TERMINATE_EVENT),
     1369                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
     1370                                    RTEMS_NO_TIMEOUT,
     1371                                    &the_event);
     1372                if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
     1373                        tty->txTaskId = 0;
     1374                        rtems_task_delete(RTEMS_SELF);
     1375                }
     1376                else {
     1377                        /*
     1378                         * call any line discipline start function
     1379                         */
     1380                        if (linesw[tty->t_line].l_start != NULL) {
     1381                                linesw[tty->t_line].l_start(tty);
     1382                        }
     1383                        /*
     1384                         * try to push further characters to device
     1385                         */
     1386                        rtems_termios_refill_transmitter(tty);
     1387                }
     1388        }
     1389}
     1390
     1391/*
     1392 * this task actually processes any receive events
     1393 */
     1394static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
     1395{
     1396        struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
     1397        rtems_event_set the_event;
     1398        int c;
     1399        char c_buf;
     1400        while (1) {
     1401                /*
     1402                 * wait for rtems event
     1403                 */
     1404                rtems_event_receive((TERMIOS_RX_PROC_EVENT |
     1405                                     TERMIOS_RX_TERMINATE_EVENT),
     1406                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
     1407                                    RTEMS_NO_TIMEOUT,
     1408                                    &the_event);
     1409                if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
     1410                        tty->rxTaskId = 0;
     1411                        rtems_task_delete(RTEMS_SELF);
     1412                }
     1413                else {
     1414                        /*
     1415                         * do something
     1416                         */
     1417                        c = tty->device.pollRead(tty->minor);
     1418                        if (c != EOF) {
     1419                                /*
     1420                                 * pollRead did call enqueue on its own
     1421                                 */
     1422                                c_buf = c;
     1423                                rtems_termios_enqueue_raw_characters (
     1424                                      tty,&c_buf,1);
     1425                        }
     1426                }
     1427        }
     1428}
Note: See TracChangeset for help on using the changeset viewer.