[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / prex-old / dev / gen

Annotation of prex-old/dev/gen/tty.c, Revision 1.1.1.1

1.1       nbrk        1: /*-
                      2:  * Copyright (c) 1982, 1986, 1990, 1991, 1993
                      3:  *     The Regents of the University of California.  All rights reserved.
                      4:  * (c) UNIX System Laboratories, Inc.
                      5:  * All or some portions of this file are derived from material licensed
                      6:  * to the University of California by American Telephone and Telegraph
                      7:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                      8:  * the permission of UNIX System Laboratories, Inc.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. Neither the name of the University nor the names of its contributors
                     19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
                     34:  *     @(#)tty.c       8.13 (Berkeley) 1/9/95
                     35:  */
                     36:
                     37: /*
                     38:  * tty.c - TTY device
                     39:  */
                     40:
                     41: #include <driver.h>
                     42: #include <sys/signal.h>
                     43: #include <sys/tty.h>
                     44: #include <sys/ttycom.h>
                     45: #include <sys/termios.h>
                     46:
                     47: #define        FREAD           0x0001
                     48: #define        FWRITE          0x0002
                     49:
                     50: void tty_output(int c, struct tty *tp);
                     51: static int tty_init(void);
                     52:
                     53: /*
                     54:  * Driver structure
                     55:  */
                     56: struct driver tty_drv = {
                     57:        /* name */      "TTY device",
                     58:        /* order */     10,             /* must be larger than console */
                     59:        /* init */      tty_init,
                     60: };
                     61:
                     62: static device_t tty_dev;
                     63:
                     64: /* task to dispatch the tty signal */
                     65: static task_t sig_task;
                     66:
                     67: /* default control characters */
                     68: static cc_t    ttydefchars[NCCS] = TTYDEFCHARS;
                     69:
                     70: #define is_ctrl(c)   ((c) < 32 || (c) == 0x7f)
                     71:
                     72: /*
                     73:  * TTY queue operations
                     74:  */
                     75: #define ttyq_next(i)   (((i) + 1) & (TTYQ_SIZE - 1))
                     76: #define ttyq_prev(i)   (((i) - 1) & (TTYQ_SIZE - 1))
                     77: #define ttyq_full(q)   ((q)->count >= TTYQ_SIZE)
                     78: #define ttyq_empty(q)  ((q)->count == 0)
                     79:
                     80: /*
                     81:  * Get a character from a queue.
                     82:  */
                     83: int
                     84: ttyq_getc(struct tty_queue *tq)
                     85: {
                     86:        int c;
                     87:
                     88:        if (ttyq_empty(tq))
                     89:                return -1;
                     90:        irq_lock();
                     91:        c = tq->buf[tq->head];
                     92:        tq->head = ttyq_next(tq->head);
                     93:        tq->count--;
                     94:        irq_unlock();
                     95:        return c;
                     96: }
                     97:
                     98: /*
                     99:  * Put a character into a queue.
                    100:  */
                    101: void
                    102: ttyq_putc(int c, struct tty_queue *tq)
                    103: {
                    104:
                    105:        if (ttyq_full(tq))
                    106:                return;
                    107:        irq_lock();
                    108:        tq->buf[tq->tail] = c;
                    109:        tq->tail = ttyq_next(tq->tail);
                    110:        tq->count++;
                    111:        irq_unlock();
                    112: }
                    113:
                    114: /*
                    115:  * Remove the last character in a queue and return it.
                    116:  */
                    117: int
                    118: ttyq_unputc(struct tty_queue *tq)
                    119: {
                    120:        int c;
                    121:
                    122:        if (ttyq_empty(tq))
                    123:                return -1;
                    124:        irq_lock();
                    125:        tq->tail = ttyq_prev(tq->tail);
                    126:        c = tq->buf[tq->tail];
                    127:        tq->count--;
                    128:        irq_unlock();
                    129:        return c;
                    130: }
                    131:
                    132: /*
                    133:  * Put the chars in the from queue on the end of the to queue.
                    134:  */
                    135: static void
                    136: tty_catq(struct tty_queue *from, struct tty_queue *to)
                    137: {
                    138:        int c;
                    139:
                    140:        while ((c = ttyq_getc(from)) != -1)
                    141:                ttyq_putc(c, to);
                    142: }
                    143:
                    144: /*
                    145:  * Rubout one character from the rawq of tp
                    146:  */
                    147: static void
                    148: tty_rubout(struct tty *tp)
                    149: {
                    150:
                    151:        if (!(tp->t_lflag & ECHO))
                    152:                return;
                    153:        if (tp->t_lflag & ECHOE) {
                    154:                tty_output('\b', tp);
                    155:                tty_output(' ', tp);
                    156:                tty_output('\b', tp);
                    157:        } else
                    158:                tty_output(tp->t_cc[VERASE], tp);
                    159: }
                    160:
                    161: /*
                    162:  * Echo char
                    163:  */
                    164: static void
                    165: tty_echo(int c, struct tty *tp)
                    166: {
                    167:
                    168:        if (!(tp->t_lflag & ECHO)) {
                    169:                if (c == '\n' && (tp->t_lflag & ECHONL))
                    170:                        tty_output('\n', tp);
                    171:                return;
                    172:        }
                    173:        if (is_ctrl(c) && c != '\n' && c != '\t' && c != '\b') {
                    174:                tty_output('^', tp);
                    175:                tty_output(c + 'A' - 1, tp);
                    176:        } else
                    177:                tty_output(c, tp);
                    178: }
                    179:
                    180: /*
                    181:  * Start output.
                    182:  */
                    183: void
                    184: tty_start(struct tty *tp)
                    185: {
                    186:
                    187:        if (tp->t_state & TS_TTSTOP)
                    188:                return;
                    189:        if (tp->t_output != NULL)
                    190:                (*tp->t_output)(tp);
                    191: }
                    192:
                    193: /*
                    194:  * Flush tty read and/or write queues, notifying anyone waiting.
                    195:  */
                    196: void
                    197: tty_flush(struct tty *tp, int rw)
                    198: {
                    199:
                    200:        if (rw & FREAD)
                    201:                sched_wakeup(&tp->t_input_event);
                    202:        if (rw & FWRITE) {
                    203:                tp->t_state &= ~TS_TTSTOP;
                    204:                tty_start(tp);
                    205:        }
                    206: }
                    207:
                    208: /*
                    209:  * Process input of a single character received on a tty.
                    210:  * echo if required.
                    211:  * This will be called with interrupt level.
                    212:  */
                    213: void
                    214: tty_input(int c, struct tty *tp)
                    215: {
                    216:        unsigned char *cc;
                    217:        tcflag_t iflag, lflag;
                    218:        int sig = -1;
                    219:
                    220:        lflag = tp->t_lflag;
                    221:        iflag = tp->t_iflag;
                    222:        cc = tp->t_cc;
                    223:
                    224:        /* IGNCR, ICRNL, INLCR */
                    225:        if (c == '\r') {
                    226:                if (iflag & IGNCR)
                    227:                        goto endcase;
                    228:                else if (iflag & ICRNL)
                    229:                        c = '\n';
                    230:        } else if (c == '\n' && (iflag & INLCR))
                    231:                c = '\r';
                    232:
                    233:        if (iflag & IXON) {
                    234:                /* stop (^S) */
                    235:                if (c == cc[VSTOP]) {
                    236:                        if (!(tp->t_state & TS_TTSTOP)) {
                    237:                                tp->t_state |= TS_TTSTOP;
                    238:                                return;
                    239:                        }
                    240:                        if (c != cc[VSTART])
                    241:                                return;
                    242:                        /* if VSTART == VSTOP then toggle */
                    243:                        goto endcase;
                    244:                }
                    245:                /* start (^Q) */
                    246:                if (c == cc[VSTART])
                    247:                        goto restartoutput;
                    248:        }
                    249:        if (lflag & ICANON) {
                    250:                /* erase (^H / ^?) or backspace */
                    251:                if (c == cc[VERASE] || c == '\b') {
                    252:                        if (!ttyq_empty(&tp->t_rawq)) {
                    253:                                ttyq_unputc(&tp->t_rawq);
                    254:                                tty_rubout(tp);
                    255:                        }
                    256:                        goto endcase;
                    257:                }
                    258:                /* kill (^U) */
                    259:                if (c == cc[VKILL]) {
                    260:                        while (!ttyq_empty(&tp->t_rawq)) {
                    261:                                ttyq_unputc(&tp->t_rawq);
                    262:                                tty_rubout(tp);
                    263:                        }
                    264:                        goto endcase;
                    265:                }
                    266:        }
                    267:        if (lflag & ISIG) {
                    268:                /* quit (^C) */
                    269:                if (c == cc[VINTR] || c == cc[VQUIT]) {
                    270:                        if (!(lflag & NOFLSH))
                    271:                                tty_flush(tp, FREAD | FWRITE);
                    272:                        tty_echo(c, tp);
                    273:                        sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT;
                    274:                        goto endcase;
                    275:                }
                    276:                /* suspend (^Z) */
                    277:                if (c == cc[VSUSP]) {
                    278:                        if (!(lflag & NOFLSH))
                    279:                                tty_flush(tp, FREAD | FWRITE);
                    280:                        tty_echo(c, tp);
                    281:                        sig = SIGTSTP;
                    282:                        goto endcase;
                    283:                }
                    284:        }
                    285:
                    286:        /*
                    287:         * Check for input buffer overflow
                    288:         */
                    289:        if (ttyq_full(&tp->t_rawq)) {
                    290:                tty_flush(tp, FREAD | FWRITE);
                    291:                goto endcase;
                    292:        }
                    293:        ttyq_putc(c, &tp->t_rawq);
                    294:
                    295:        if (lflag & ICANON) {
                    296:                if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) {
                    297:                        tty_catq(&tp->t_rawq, &tp->t_canq);
                    298:                        sched_wakeup(&tp->t_input_event);
                    299:                }
                    300:        } else
                    301:                sched_wakeup(&tp->t_input_event);
                    302:
                    303:        if (lflag & ECHO)
                    304:                tty_echo(c, tp);
                    305:  endcase:
                    306:        /*
                    307:         * IXANY means allow any character to restart output.
                    308:         */
                    309:        if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 &&
                    310:            cc[VSTART] != cc[VSTOP])
                    311:                return;
                    312:  restartoutput:
                    313:        tp->t_state &= ~TS_TTSTOP;
                    314:
                    315:        if (sig != -1) {
                    316:                if (sig_task)
                    317:                        exception_post(sig_task, sig);
                    318:        }
                    319:        tty_start(tp);
                    320: }
                    321:
                    322: /*
                    323:  * Output a single character on a tty, doing output processing
                    324:  * as needed (expanding tabs, newline processing, etc.).
                    325:  */
                    326: void
                    327: tty_output(int c, struct tty *tp)
                    328: {
                    329:        int i, col;
                    330:
                    331:        if ((tp->t_lflag & ICANON) == 0) {
                    332:                ttyq_putc(c, &tp->t_outq);
                    333:                return;
                    334:        }
                    335:        /* Expand tab */
                    336:        if (c == '\t' && (tp->t_oflag & OXTABS)) {
                    337:                i = 8 - (tp->t_column & 7);
                    338:                tp->t_column += i;
                    339:                do
                    340:                        ttyq_putc(' ', &tp->t_outq);
                    341:                while (--i > 0);
                    342:                return;
                    343:        }
                    344:        /* Translate newline into "\r\n" */
                    345:        if (c == '\n' && (tp->t_oflag & ONLCR))
                    346:                ttyq_putc('\r', &tp->t_outq);
                    347:
                    348:        ttyq_putc(c, &tp->t_outq);
                    349:
                    350:        col = tp->t_column;
                    351:        switch (c) {
                    352:        case '\b':      /* back space */
                    353:                if (col > 0)
                    354:                        --col;
                    355:                break;
                    356:        case '\t':      /* tab */
                    357:                col = (col + 8) & ~7;
                    358:                break;
                    359:        case '\n':      /* newline */
                    360:                col = 0;
                    361:                break;
                    362:        case '\r':      /* return */
                    363:                col = 0;
                    364:                break;
                    365:        default:
                    366:                if (!is_ctrl(c))
                    367:                    ++col;
                    368:                break;
                    369:        }
                    370:        tp->t_column = col;
                    371:        return;
                    372: }
                    373:
                    374: /*
                    375:  * Read
                    376:  */
                    377: int
                    378: tty_read(struct tty *tp, char *buf, size_t *nbytes)
                    379: {
                    380:        unsigned char *cc;
                    381:        struct tty_queue *qp;
                    382:        int rc, c;
                    383:        size_t count = 0;
                    384:        tcflag_t lflag;
                    385:
                    386:        lflag = tp->t_lflag;
                    387:        cc = tp->t_cc;
                    388:        qp = (lflag & ICANON) ? &tp->t_canq : &tp->t_rawq;
                    389:
                    390:        /* If there is no input, wait it */
                    391:        while (ttyq_empty(qp)) {
                    392:                rc = sched_sleep(&tp->t_input_event);
                    393:                if (rc == SLP_INTR)
                    394:                        return EINTR;
                    395:        }
                    396:        while (count < *nbytes) {
                    397:                if ((c = ttyq_getc(qp)) == -1)
                    398:                        break;
                    399:                count++;
                    400:                if (c == cc[VEOF] && (lflag & ICANON))
                    401:                        break;
                    402:                *buf = c;
                    403:                if ((lflag & ICANON) && (c == '\n' || c == cc[VEOL]))
                    404:                        break;
                    405:                buf++;
                    406:        }
                    407:        *nbytes = count;
                    408:        return 0;
                    409: }
                    410:
                    411: /*
                    412:  * Write
                    413:  */
                    414: int
                    415: tty_write(struct tty *tp, char *buf, size_t *nbyte)
                    416: {
                    417:        size_t remain, count = 0;
                    418:
                    419:        remain = *nbyte;
                    420:        while (remain > 0) {
                    421:                if (tp->t_outq.count >= TTYQ_HIWAT) {
                    422:                        tty_start(tp);
                    423:                        continue;
                    424:                }
                    425:                tty_output(*buf, tp);
                    426:                buf++;
                    427:                remain--;
                    428:                count++;
                    429:        }
                    430:        tty_start(tp);
                    431:        *nbyte = count;
                    432:        return 0;
                    433: }
                    434:
                    435: /*
                    436:  * Ioctls for all tty devices.
                    437:  */
                    438: int
                    439: tty_ioctl(struct tty *tp, u_long cmd, void *data)
                    440: {
                    441:        int flags;
                    442:
                    443:        switch (cmd) {
                    444:        case TIOCGETA:
                    445:                if (umem_copyout(&tp->t_termios, data,
                    446:                                 sizeof(struct termios)))
                    447:                        return EFAULT;
                    448:                break;
                    449:        case TIOCSETAW:
                    450:        case TIOCSETAF:
                    451:                tty_flush(tp, flags);
                    452:                /* fallthrouth */
                    453:        case TIOCSETA:
                    454:                if (umem_copyin(data, &tp->t_termios,
                    455:                                 sizeof(struct termios)))
                    456:                        return EFAULT;
                    457:                break;
                    458:        case TIOCSPGRP:                 /* set pgrp of tty */
                    459:                if (umem_copyin(data, &tp->t_pgid, sizeof(pid_t)))
                    460:                        return EFAULT;
                    461:                break;
                    462:        case TIOCGPGRP:
                    463:                if (umem_copyout(&tp->t_pgid, data, sizeof(pid_t)))
                    464:                        return EFAULT;
                    465:                break;
                    466:        case TIOCFLUSH:
                    467:                if (umem_copyin(data, &flags, sizeof(flags)))
                    468:                        return EFAULT;
                    469:                break;
                    470:                if (flags == 0)
                    471:                        flags = FREAD | FWRITE;
                    472:                else
                    473:                        flags &= FREAD | FWRITE;
                    474:                tty_flush(tp, flags);
                    475:                break;
                    476:        case TIOCSTART:
                    477:                if (tp->t_state & TS_TTSTOP) {
                    478:                        tp->t_state &= ~TS_TTSTOP;
                    479:                        tty_start(tp);
                    480:                }
                    481:                break;
                    482:        case TIOCSTOP:
                    483:                if (!(tp->t_state & TS_TTSTOP)) {
                    484:                        tp->t_state |= TS_TTSTOP;
                    485:                }
                    486:                break;
                    487:        case TIOCGWINSZ:
                    488:                if (umem_copyout(&tp->t_winsize, data,
                    489:                                 sizeof(struct winsize)))
                    490:                        return EFAULT;
                    491:                break;
                    492:        case TIOCSWINSZ:
                    493:                if (umem_copyin(&tp->t_winsize, data,
                    494:                                 sizeof(struct winsize)))
                    495:                        return EFAULT;
                    496:                break;
                    497:        case TIOCSETSIGT:
                    498:                if (umem_copyin(data, &sig_task, sizeof(task_t)))
                    499:                        return EFAULT;
                    500:                break;
                    501:        }
                    502:        return 0;
                    503: }
                    504:
                    505: /*
                    506:  * Register tty device.
                    507:  */
                    508: int
                    509: tty_register(struct devio *io, struct tty *tp, void (*output)(struct tty*))
                    510: {
                    511:
                    512:        /* We support only one tty device */
                    513:        if (tty_dev != NULL_DEVICE)
                    514:                return -1;
                    515:
                    516:        /* Create TTY device as an alias of the registered device. */
                    517:        tty_dev = device_create(io, "tty", DF_CHR);
                    518:        if (tty_dev == NULL_DEVICE)
                    519:                return -1;
                    520:
                    521:        /* Initialize tty */
                    522:        memset(tp, 0, sizeof(struct tty));
                    523:        memcpy(&tp->t_termios.c_cc, ttydefchars, sizeof(ttydefchars));
                    524:        event_init(&tp->t_input_event, "TTY input");
                    525:        tp->t_iflag = TTYDEF_IFLAG;
                    526:        tp->t_oflag = TTYDEF_OFLAG;
                    527:        tp->t_cflag = TTYDEF_CFLAG;
                    528:        tp->t_lflag = TTYDEF_LFLAG;
                    529:        tp->t_ispeed = TTYDEF_SPEED;
                    530:        tp->t_ospeed = TTYDEF_SPEED;
                    531:        tp->t_output = output;
                    532:        return 0;
                    533: }
                    534:
                    535: /*
                    536:  * Init
                    537:  */
                    538: static int
                    539: tty_init(void)
                    540: {
                    541:
                    542:        return 0;
                    543: }

CVSweb