Annotation of Gnu-Mach/device/chario.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * Mach Operating System
        !             3:  * Copyright (c) 1993-1988 Carnegie Mellon University
        !             4:  * All Rights Reserved.
        !             5:  * 
        !             6:  * Permission to use, copy, modify and distribute this software and its
        !             7:  * documentation is hereby granted, provided that both the copyright
        !             8:  * notice and this permission notice appear in all copies of the
        !             9:  * software, derivative works or modified versions, and any portions
        !            10:  * thereof, and that both notices appear in supporting documentation.
        !            11:  * 
        !            12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            15:  * 
        !            16:  * Carnegie Mellon requests users of this software to return to
        !            17:  * 
        !            18:  *  Software Distribution Coordinator  or  [email protected]
        !            19:  *  School of Computer Science
        !            20:  *  Carnegie Mellon University
        !            21:  *  Pittsburgh PA 15213-3890
        !            22:  * 
        !            23:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            24:  * the rights to redistribute these changes.
        !            25:  */
        !            26: /*
        !            27:  *     Author: David B. Golub, Carnegie Mellon University
        !            28:  *     Date:   8/88
        !            29:  *
        !            30:  *     TTY io.
        !            31:  *     Compatibility with old TTY device drivers.
        !            32:  */
        !            33: 
        !            34: #include <mach/kern_return.h>
        !            35: #include <mach/mig_errors.h>
        !            36: #include <mach/vm_param.h>
        !            37: #include <machine/machspl.h>           /* spl definitions */
        !            38: 
        !            39: #include <ipc/ipc_port.h>
        !            40: 
        !            41: #include <kern/lock.h>
        !            42: #include <kern/queue.h>
        !            43: 
        !            44: #include <vm/vm_map.h>
        !            45: #include <vm/vm_kern.h>
        !            46: 
        !            47: #include <device/device_types.h>
        !            48: #include <device/io_req.h>
        !            49: #include <device/ds_routines.h>
        !            50: #include "device_reply.h"
        !            51: 
        !            52: #include <device/tty.h>
        !            53: 
        !            54: /* If you change these, check that tty_outq_size and tty_inq_size
        !            55:  * is greater than largest tthiwat entry.
        !            56:  */
        !            57: short  tthiwat[16] =
        !            58:    { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 };
        !            59: short  ttlowat[16] =
        !            60:    {  30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125, 125, 125 };
        !            61: 
        !            62: /*
        !            63:  * forward declarations
        !            64:  */
        !            65: void   queue_delayed_reply(
        !            66:        queue_t, io_req_t, boolean_t (*)(io_req_t));
        !            67: void   tty_output(struct tty *);
        !            68: void   tty_flush(struct tty *, int);
        !            69: boolean_t char_open_done(io_req_t);
        !            70: boolean_t char_read_done(io_req_t);
        !            71: boolean_t char_write_done(io_req_t);
        !            72: 
        !            73: /*
        !            74:  * Fake 'line discipline' switch for the benefit of old code
        !            75:  * that wants to call through it.
        !            76:  */
        !            77: struct ldisc_switch    linesw[] = {
        !            78:        {
        !            79:            char_read,
        !            80:            char_write,
        !            81:            ttyinput,
        !            82:            ttymodem,
        !            83:            tty_output
        !            84:        }
        !            85: };
        !            86: 
        !            87: /*
        !            88:  * Sizes for input and output circular buffers.
        !            89:  */
        !            90: int    tty_inq_size = 4096;    /* big nuf */
        !            91: int    tty_outq_size = 2048;   /* Must be bigger that tthiwat */
        !            92: int    pdma_default = 1;       /* turn pseudo dma on by default */
        !            93: 
        !            94: /*
        !            95:  * compute pseudo-dma tables 
        !            96:  */
        !            97: 
        !            98: int pdma_timeouts[NSPEEDS]; /* how many ticks in timeout */
        !            99: int pdma_water_mark[NSPEEDS];
        !           100: 
        !           101: 
        !           102: void chario_init(void)
        !           103: {
        !           104:   /* the basic idea with the timeouts is two allow enough
        !           105:      time for a character to show up if data is coming in at full data rate
        !           106:      plus a little slack. 2 ticks is considered slack
        !           107:      Below 300 baud we just glob a character at a time */
        !           108: #define _PR(x) ((hz/x) + 2)
        !           109: 
        !           110:   int i;
        !           111: 
        !           112:   for (i = B0; i < B300; i++)
        !           113:     pdma_timeouts[i] = 0;
        !           114:   
        !           115:   pdma_timeouts[B300] = _PR(30);
        !           116:   pdma_timeouts[B600] = _PR(60);
        !           117:   pdma_timeouts[B1200] = _PR(120);
        !           118:   pdma_timeouts[B1800] = _PR(180);
        !           119:   pdma_timeouts[B2400] = _PR(240);
        !           120:   pdma_timeouts[B4800] = _PR(480);
        !           121:   pdma_timeouts[B9600] = _PR(960);
        !           122:   pdma_timeouts[EXTA]  = _PR(1440); /* >14400 baud */
        !           123:   pdma_timeouts[EXTB]  = _PR(1920); /* >19200 baud */
        !           124: 
        !           125:   for (i = B0; i < B300; i++)
        !           126:     pdma_water_mark[i] = 0;
        !           127: 
        !           128:   /* for the slow speeds, we try to buffer 0.02 of the baud rate
        !           129:      (20% of the character rate). For the faster lines,
        !           130:      we try to buffer 1/2 the input queue size */
        !           131: 
        !           132: #undef _PR
        !           133: #define _PR(x) (0.20 * x)
        !           134: 
        !           135:   pdma_water_mark[B300] = _PR(120);
        !           136:   pdma_water_mark[B600] = _PR(120);
        !           137:   pdma_water_mark[B1200] = _PR(120);
        !           138:   pdma_water_mark[B1800] = _PR(180);
        !           139:   pdma_water_mark[B2400] = _PR(240);
        !           140:   pdma_water_mark[B4800] = _PR(480);
        !           141:   i = tty_inq_size/2;
        !           142:   pdma_water_mark[B9600] = i;
        !           143:   pdma_water_mark[EXTA]  = i; /* >14400 baud */
        !           144:   pdma_water_mark[EXTB]  = i; /* >19200 baud */
        !           145: 
        !           146:   return; 
        !           147: }
        !           148: 
        !           149: /*
        !           150:  * Open TTY, waiting for CARR_ON.
        !           151:  * No locks may be held.
        !           152:  * May run on any CPU.
        !           153:  */
        !           154: io_return_t char_open(
        !           155:        int             dev,
        !           156:        struct tty *    tp,
        !           157:        dev_mode_t      mode,
        !           158:        io_req_t        ior)
        !           159: {
        !           160:        spl_t   s;
        !           161:        io_return_t     rc = D_SUCCESS;
        !           162: 
        !           163:        s = spltty();
        !           164:        simple_lock(&tp->t_lock);
        !           165: 
        !           166:        tp->t_dev = dev;
        !           167: 
        !           168:        if (tp->t_mctl)
        !           169:                (*tp->t_mctl)(tp, TM_DTR, DMSET);
        !           170: 
        !           171:        if (pdma_default)
        !           172:          tp->t_state |= TS_MIN;
        !           173: 
        !           174:        if ((tp->t_state & TS_CARR_ON) == 0) {
        !           175:            /*
        !           176:             * No carrier.
        !           177:             */
        !           178:            if (mode & D_NODELAY) {
        !           179:                tp->t_state |= TS_ONDELAY;
        !           180:            }
        !           181:            else {
        !           182:                /*
        !           183:                 * Don`t return from open until carrier detected.
        !           184:                 */
        !           185:                tp->t_state |= TS_WOPEN;
        !           186: 
        !           187:                ior->io_dev_ptr = (char *)tp;
        !           188: 
        !           189:                queue_delayed_reply(&tp->t_delayed_open, ior, char_open_done);
        !           190:                rc = D_IO_QUEUED;
        !           191:                goto out;
        !           192:            }
        !           193:        }
        !           194:        tp->t_state |= TS_ISOPEN;
        !           195:        if (tp->t_mctl)
        !           196:                (*tp->t_mctl)(tp, TM_RTS, DMBIS);
        !           197: out:
        !           198:        simple_unlock(&tp->t_lock);
        !           199:        splx(s);
        !           200:        return rc;
        !           201: }
        !           202: 
        !           203: /*
        !           204:  * Retry wait for CARR_ON for open.
        !           205:  * No locks may be held.
        !           206:  * May run on any CPU.
        !           207:  */
        !           208: boolean_t char_open_done(
        !           209:        io_req_t        ior)
        !           210: {
        !           211:        register struct tty *tp = (struct tty *)ior->io_dev_ptr;
        !           212:        spl_t s = spltty();
        !           213: 
        !           214:        simple_lock(&tp->t_lock);
        !           215:        if ((tp->t_state & TS_ISOPEN) == 0) {
        !           216:            queue_delayed_reply(&tp->t_delayed_open, ior, char_open_done);
        !           217:            simple_unlock(&tp->t_lock);
        !           218:            splx(s);
        !           219:            return FALSE;
        !           220:        }
        !           221: 
        !           222:        tp->t_state |= TS_ISOPEN;
        !           223:        tp->t_state &= ~TS_WOPEN;
        !           224: 
        !           225:        if (tp->t_mctl)
        !           226:                (*tp->t_mctl)(tp, TM_RTS, DMBIS);
        !           227: 
        !           228:        simple_unlock(&tp->t_lock);
        !           229:        splx(s);
        !           230: 
        !           231:        ior->io_error = D_SUCCESS;
        !           232:        (void) ds_open_done(ior);
        !           233:        return TRUE;
        !           234: }
        !           235: 
        !           236: boolean_t tty_close_open_reply(
        !           237:        io_req_t        ior)
        !           238: {
        !           239:        ior->io_error = D_DEVICE_DOWN;
        !           240:        (void) ds_open_done(ior);
        !           241:        return TRUE;
        !           242: }
        !           243: 
        !           244: /*
        !           245:  * Write to TTY.
        !           246:  * No locks may be held.
        !           247:  * Calls device start routine; must already be on master if
        !           248:  * device needs to run on master.
        !           249:  */
        !           250: io_return_t char_write(
        !           251:        register struct tty *   tp,
        !           252:        register io_req_t       ior)
        !           253: {
        !           254:        spl_t           s;
        !           255:        register int    count;
        !           256:        register char   *data;
        !           257:        vm_offset_t     addr;
        !           258:        io_return_t     rc = D_SUCCESS;
        !           259: 
        !           260:        data  = ior->io_data;
        !           261:        count = ior->io_count;
        !           262:        if (count == 0)
        !           263:            return rc;
        !           264: 
        !           265:        if (!(ior->io_op & IO_INBAND)) {
        !           266:            /*
        !           267:             * Copy out-of-line data into kernel address space.
        !           268:             * Since data is copied as page list, it will be
        !           269:             * accessible.
        !           270:             */
        !           271:            vm_map_copy_t copy = (vm_map_copy_t) data;
        !           272:            kern_return_t kr;
        !           273: 
        !           274:            kr = vm_map_copyout(device_io_map, &addr, copy);
        !           275:            if (kr != KERN_SUCCESS)
        !           276:                return kr;
        !           277:            data = (char *) addr;
        !           278:        }
        !           279: 
        !           280:        /*
        !           281:         * Check for tty operating.
        !           282:         */
        !           283:        s = spltty();
        !           284:        simple_lock(&tp->t_lock);
        !           285: 
        !           286:        if ((tp->t_state & TS_CARR_ON) == 0) {
        !           287: 
        !           288:            if ((tp->t_state & TS_ONDELAY) == 0) {
        !           289:                /*
        !           290:                 * No delayed writes - tell caller that device is down
        !           291:                 */
        !           292:                rc = D_IO_ERROR;
        !           293:                goto out;
        !           294:            }
        !           295: 
        !           296:            if (ior->io_mode & D_NOWAIT) {
        !           297:                rc = D_WOULD_BLOCK;
        !           298:                goto out;
        !           299:            }
        !           300:        }
        !           301: 
        !           302:        /*
        !           303:         * Copy data into the output buffer.
        !           304:         * Report the amount not copied.
        !           305:         */
        !           306: 
        !           307:        ior->io_residual = b_to_q(data, count, &tp->t_outq);
        !           308: 
        !           309:        /*
        !           310:         * Start hardware output.
        !           311:         */
        !           312: 
        !           313:        tp->t_state &= ~TS_TTSTOP;
        !           314:        tty_output(tp);
        !           315: 
        !           316:        if (tp->t_outq.c_cc > TTHIWAT(tp) ||
        !           317:            (tp->t_state & TS_CARR_ON) == 0) {
        !           318: 
        !           319:            /*
        !           320:             * Do not send reply until some characters have been sent.
        !           321:             */
        !           322:            ior->io_dev_ptr = (char *)tp;
        !           323:            queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done);
        !           324: 
        !           325:            rc = D_IO_QUEUED;
        !           326:        }
        !           327: out:
        !           328:        simple_unlock(&tp->t_lock);
        !           329:        splx(s);
        !           330: 
        !           331:        if (!(ior->io_op & IO_INBAND))
        !           332:            (void) vm_deallocate(device_io_map, addr, ior->io_count);
        !           333:        return rc;
        !           334: }
        !           335: 
        !           336: /*
        !           337:  * Retry wait for output queue emptied, for write.
        !           338:  * No locks may be held.
        !           339:  * May run on any CPU.
        !           340:  */
        !           341: boolean_t char_write_done(
        !           342:        register io_req_t       ior)
        !           343: {
        !           344:        register struct tty *tp = (struct tty *)ior->io_dev_ptr;
        !           345:        register spl_t s = spltty();
        !           346: 
        !           347:        simple_lock(&tp->t_lock);
        !           348:        if (tp->t_outq.c_cc > TTHIWAT(tp) ||
        !           349:            (tp->t_state & TS_CARR_ON) == 0) {
        !           350: 
        !           351:            queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done);
        !           352:            simple_unlock(&tp->t_lock);
        !           353:            splx(s);
        !           354:            return FALSE;
        !           355:        }
        !           356:        simple_unlock(&tp->t_lock);
        !           357:        splx(s);
        !           358: 
        !           359:        if (IP_VALID(ior->io_reply_port)) {
        !           360:          (void) (*((ior->io_op & IO_INBAND) ?
        !           361:                    ds_device_write_reply_inband :
        !           362:                    ds_device_write_reply))(ior->io_reply_port,
        !           363:                                            ior->io_reply_port_type,
        !           364:                                            ior->io_error,
        !           365:                                            (int) (ior->io_total -
        !           366:                                                   ior->io_residual));
        !           367:        }
        !           368:        mach_device_deallocate(ior->io_device);
        !           369:        return TRUE;
        !           370: }
        !           371: 
        !           372: boolean_t tty_close_write_reply(
        !           373:        register io_req_t       ior)
        !           374: {
        !           375:        ior->io_residual = ior->io_count;
        !           376:        ior->io_error = D_DEVICE_DOWN;
        !           377:        (void) ds_write_done(ior);
        !           378:        return TRUE;
        !           379: }
        !           380: 
        !           381: /*
        !           382:  * Read from TTY.
        !           383:  * No locks may be held.
        !           384:  * May run on any CPU - does not talk to device driver.
        !           385:  */
        !           386: io_return_t char_read(
        !           387:        register struct tty *tp,
        !           388:        register io_req_t ior)
        !           389: {
        !           390:        spl_t           s;
        !           391:        kern_return_t   rc;
        !           392: 
        !           393:        /*
        !           394:         * Allocate memory for read buffer.
        !           395:         */
        !           396:        rc = device_read_alloc(ior, (vm_size_t)ior->io_count);
        !           397:        if (rc != KERN_SUCCESS)
        !           398:            return rc;
        !           399: 
        !           400:        s = spltty();
        !           401:        simple_lock(&tp->t_lock);
        !           402:        if ((tp->t_state & TS_CARR_ON) == 0) {
        !           403: 
        !           404:            if ((tp->t_state & TS_ONDELAY) == 0) {
        !           405:                /*
        !           406:                 * No delayed writes - tell caller that device is down
        !           407:                 */
        !           408:                rc = D_IO_ERROR;
        !           409:                goto out;
        !           410:            }
        !           411: 
        !           412:            if (ior->io_mode & D_NOWAIT) {
        !           413:                rc = D_WOULD_BLOCK;
        !           414:                goto out;
        !           415:            }
        !           416: 
        !           417:        }
        !           418: 
        !           419:        if (tp->t_inq.c_cc <= 0 ||
        !           420:            (tp->t_state & TS_CARR_ON) == 0) {
        !           421: 
        !           422:            ior->io_dev_ptr = (char *)tp;
        !           423:            queue_delayed_reply(&tp->t_delayed_read, ior, char_read_done);
        !           424:            rc = D_IO_QUEUED;
        !           425:            goto out;
        !           426:        }
        !           427:        
        !           428:        ior->io_residual = ior->io_count - q_to_b(&tp->t_inq,
        !           429:                                                  ior->io_data,
        !           430:                                                  (int)ior->io_count);
        !           431:        if (tp->t_state & TS_RTS_DOWN) {
        !           432:            (*tp->t_mctl)(tp, TM_RTS, DMBIS);
        !           433:            tp->t_state &= ~TS_RTS_DOWN;
        !           434:        }
        !           435: 
        !           436:     out:
        !           437:        simple_unlock(&tp->t_lock);
        !           438:        splx(s);
        !           439:        return rc;
        !           440: }
        !           441: 
        !           442: /*
        !           443:  * Retry wait for characters, for read.
        !           444:  * No locks may be held.
        !           445:  * May run on any CPU - does not talk to device driver.
        !           446:  */
        !           447: boolean_t char_read_done(
        !           448:        register io_req_t       ior)
        !           449: {
        !           450:        register struct tty *tp = (struct tty *)ior->io_dev_ptr;
        !           451:        register spl_t s = spltty();
        !           452: 
        !           453:        simple_lock(&tp->t_lock);
        !           454: 
        !           455:        if (tp->t_inq.c_cc <= 0 ||
        !           456:            (tp->t_state & TS_CARR_ON) == 0) {
        !           457: 
        !           458:            queue_delayed_reply(&tp->t_delayed_read, ior, char_read_done);
        !           459:            simple_unlock(&tp->t_lock);
        !           460:            splx(s);
        !           461:            return FALSE;
        !           462:        }
        !           463: 
        !           464:        ior->io_residual = ior->io_count - q_to_b(&tp->t_inq,
        !           465:                                                  ior->io_data,
        !           466:                                                  (int)ior->io_count);
        !           467:        if (tp->t_state & TS_RTS_DOWN) {
        !           468:            (*tp->t_mctl)(tp, TM_RTS, DMBIS);
        !           469:            tp->t_state &= ~TS_RTS_DOWN;
        !           470:        }
        !           471: 
        !           472:        simple_unlock(&tp->t_lock);
        !           473:        splx(s);
        !           474: 
        !           475:        (void) ds_read_done(ior);
        !           476:        return TRUE;
        !           477: }
        !           478: 
        !           479: boolean_t tty_close_read_reply(
        !           480:        register io_req_t       ior)
        !           481: {
        !           482:        ior->io_residual = ior->io_count;
        !           483:        ior->io_error = D_DEVICE_DOWN;
        !           484:        (void) ds_read_done(ior);
        !           485:        return TRUE;
        !           486: }
        !           487: 
        !           488: /*
        !           489:  * Close the tty.
        !           490:  * Tty must be locked (at spltty).
        !           491:  * Iff modem control should run on master.
        !           492:  */
        !           493: void ttyclose(
        !           494:        register struct tty *tp)
        !           495: {
        !           496:        register io_req_t       ior;
        !           497: 
        !           498:        /*
        !           499:         * Flush the read and write queues.  Signal
        !           500:         * the open queue so that those waiting for open
        !           501:         * to complete will see that the tty is closed.
        !           502:         */
        !           503:        while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_read)) != 0) {
        !           504:            ior->io_done = tty_close_read_reply;
        !           505:            iodone(ior);
        !           506:        }
        !           507:        while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_write)) != 0) {
        !           508:            ior->io_done = tty_close_write_reply;
        !           509:            iodone(ior);
        !           510:        }
        !           511:        while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_open)) != 0) {
        !           512:            ior->io_done = tty_close_open_reply;
        !           513:            iodone(ior);
        !           514:        }
        !           515: 
        !           516:        /* Close down modem */
        !           517:        if (tp->t_mctl) {
        !           518:                (*tp->t_mctl)(tp, TM_BRK|TM_RTS, DMBIC);
        !           519:                if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0)
        !           520:                        (*tp->t_mctl)(tp, TM_HUP, DMSET);
        !           521:        }
        !           522: 
        !           523:        /* only save buffering bit, and carrier */
        !           524:        tp->t_state = tp->t_state & (TS_MIN|TS_CARR_ON);
        !           525: }
        !           526: 
        !           527: /*
        !           528:  * Port-death routine to clean up reply messages.
        !           529:  */
        !           530: boolean_t
        !           531: tty_queue_clean(
        !           532:        queue_t         q,
        !           533:        ipc_port_t      port,
        !           534:        boolean_t       (*routine)(io_req_t) )
        !           535: {
        !           536:        register io_req_t       ior;
        !           537: 
        !           538:        ior = (io_req_t)queue_first(q);
        !           539:        while (!queue_end(q, (queue_entry_t)ior)) {
        !           540:            if (ior->io_reply_port == port) {
        !           541:                remqueue(q, (queue_entry_t)ior);
        !           542:                ior->io_done = routine;
        !           543:                iodone(ior);
        !           544:                return TRUE;
        !           545:            }
        !           546:            ior = ior->io_next;
        !           547:        }
        !           548:        return FALSE;
        !           549: }
        !           550: 
        !           551: /*
        !           552:  * Handle port-death (dead reply port) for tty.
        !           553:  * No locks may be held.
        !           554:  * May run on any CPU.
        !           555:  */
        !           556: boolean_t
        !           557: tty_portdeath(
        !           558:        struct tty *    tp,
        !           559:        ipc_port_t      port)
        !           560: {
        !           561:        register spl_t  spl = spltty();
        !           562:        register boolean_t      result;
        !           563: 
        !           564:        simple_lock(&tp->t_lock);
        !           565: 
        !           566:        /*
        !           567:         * The queues may never have been initialized
        !           568:         */
        !           569:        if (tp->t_delayed_read.next == 0) {
        !           570:            result = FALSE;
        !           571:        }
        !           572:        else {
        !           573:            result =
        !           574:                tty_queue_clean(&tp->t_delayed_read,  port,
        !           575:                                tty_close_read_reply)
        !           576:             || tty_queue_clean(&tp->t_delayed_write, port,
        !           577:                                tty_close_write_reply)
        !           578:             || tty_queue_clean(&tp->t_delayed_open,  port,
        !           579:                                tty_close_open_reply);
        !           580:        }
        !           581:        simple_unlock(&tp->t_lock);
        !           582:        splx(spl);
        !           583: 
        !           584:        return result;
        !           585: }
        !           586: 
        !           587: /*
        !           588:  * Get TTY status.
        !           589:  * No locks may be held.
        !           590:  * May run on any CPU.
        !           591:  */
        !           592: io_return_t tty_get_status(
        !           593:        register struct tty *tp,
        !           594:        dev_flavor_t    flavor,
        !           595:        int *           data,           /* pointer to OUT array */
        !           596:        natural_t       *count)         /* out */
        !           597: {
        !           598:        spl_t           s;
        !           599: 
        !           600:        switch (flavor) {
        !           601:            case TTY_STATUS:
        !           602:            {
        !           603:                register struct tty_status *tsp =
        !           604:                        (struct tty_status *) data;
        !           605: 
        !           606:                if (*count < TTY_STATUS_COUNT)
        !           607:                    return (D_INVALID_OPERATION);
        !           608: 
        !           609:                s = spltty();
        !           610:                simple_lock(&tp->t_lock);
        !           611: 
        !           612:                tsp->tt_ispeed = tp->t_ispeed;
        !           613:                tsp->tt_ospeed = tp->t_ospeed;
        !           614:                tsp->tt_breakc = tp->t_breakc;
        !           615:                tsp->tt_flags  = tp->t_flags;
        !           616:                if (tp->t_state & TS_HUPCLS)
        !           617:                    tsp->tt_flags |= TF_HUPCLS;
        !           618: 
        !           619:                simple_unlock(&tp->t_lock);
        !           620:                splx(s);
        !           621: 
        !           622:                *count = TTY_STATUS_COUNT;
        !           623:                break;
        !           624: 
        !           625:            }
        !           626:            default:
        !           627:                return D_INVALID_OPERATION;
        !           628:        }
        !           629:        return D_SUCCESS;
        !           630: }
        !           631: 
        !           632: /*
        !           633:  * Set TTY status.
        !           634:  * No locks may be held.
        !           635:  * Calls device start or stop routines; must already be on master if
        !           636:  * device needs to run on master.
        !           637:  */
        !           638: io_return_t tty_set_status(
        !           639:        register struct tty *tp,
        !           640:        dev_flavor_t    flavor,
        !           641:        int *           data,
        !           642:        natural_t       count)
        !           643: {
        !           644:        int     s;
        !           645: 
        !           646:        switch (flavor) {
        !           647:            case TTY_FLUSH:
        !           648:            {
        !           649:                register int    flags;
        !           650:                if (count < TTY_FLUSH_COUNT)
        !           651:                    return D_INVALID_OPERATION;
        !           652: 
        !           653:                flags = *data;
        !           654:                if (flags == 0)
        !           655:                    flags = D_READ | D_WRITE;
        !           656: 
        !           657:                s = spltty();
        !           658:                simple_lock(&tp->t_lock);
        !           659:                tty_flush(tp, flags);
        !           660:                simple_unlock(&tp->t_lock);
        !           661:                splx(s);
        !           662: 
        !           663:                break;
        !           664:            }
        !           665:            case TTY_STOP:
        !           666:                /* stop output */
        !           667:                s = spltty();
        !           668:                simple_lock(&tp->t_lock);
        !           669:                if ((tp->t_state & TS_TTSTOP) == 0) {
        !           670:                    tp->t_state |= TS_TTSTOP;
        !           671:                    (*tp->t_stop)(tp, 0);
        !           672:                }
        !           673:                simple_unlock(&tp->t_lock);
        !           674:                splx(s);
        !           675:                break;
        !           676: 
        !           677:            case TTY_START:
        !           678:                /* start output */
        !           679:                s = spltty();
        !           680:                simple_lock(&tp->t_lock);
        !           681:                if (tp->t_state & TS_TTSTOP) {
        !           682:                    tp->t_state &= ~TS_TTSTOP;
        !           683:                    tty_output(tp);
        !           684:                }
        !           685:                simple_unlock(&tp->t_lock);
        !           686:                splx(s);
        !           687:                break;
        !           688: 
        !           689:            case TTY_STATUS:
        !           690:                /* set special characters and speed */
        !           691:            {
        !           692:                register struct tty_status *tsp;
        !           693: 
        !           694:                if (count < TTY_STATUS_COUNT)
        !           695:                    return D_INVALID_OPERATION;
        !           696: 
        !           697:                tsp = (struct tty_status *)data;
        !           698: 
        !           699:                if (tsp->tt_ispeed < 0 ||
        !           700:                    tsp->tt_ispeed >= NSPEEDS ||
        !           701:                    tsp->tt_ospeed < 0 ||
        !           702:                    tsp->tt_ospeed >= NSPEEDS)
        !           703:                {
        !           704:                    return D_INVALID_OPERATION;
        !           705:                }
        !           706: 
        !           707:                s = spltty();
        !           708:                simple_lock(&tp->t_lock);
        !           709: 
        !           710:                tp->t_ispeed = tsp->tt_ispeed;
        !           711:                tp->t_ospeed = tsp->tt_ospeed;
        !           712:                tp->t_breakc = tsp->tt_breakc;
        !           713:                tp->t_flags  = tsp->tt_flags & ~TF_HUPCLS;
        !           714:                if (tsp->tt_flags & TF_HUPCLS)
        !           715:                    tp->t_state |= TS_HUPCLS;
        !           716: 
        !           717:                simple_unlock(&tp->t_lock);
        !           718:                splx(s);
        !           719:                break;
        !           720:            }
        !           721:            default:
        !           722:                return D_INVALID_OPERATION;
        !           723:        }
        !           724:        return D_SUCCESS;
        !           725: }
        !           726: 
        !           727: 
        !           728: /*
        !           729:  * [internal]
        !           730:  * Queue IOR on reply queue, to wait for TTY operation.
        !           731:  * TTY must be locked (at spltty).
        !           732:  */
        !           733: void queue_delayed_reply(
        !           734:        queue_t         qh,
        !           735:        io_req_t        ior,
        !           736:        boolean_t       (*io_done)(io_req_t) )
        !           737: {
        !           738:        ior->io_done = io_done;
        !           739:        enqueue_tail(qh, (queue_entry_t)ior);
        !           740: }
        !           741: 
        !           742: /*
        !           743:  * Retry delayed IO operations for TTY.
        !           744:  * TTY containing queue must be locked (at spltty).
        !           745:  */
        !           746: void tty_queue_completion(
        !           747:        register queue_t        qh)
        !           748: {
        !           749:        register io_req_t       ior;
        !           750: 
        !           751:        while ((ior = (io_req_t)dequeue_head(qh)) != 0) {
        !           752:            iodone(ior);
        !           753:        }
        !           754: }
        !           755: 
        !           756: /*
        !           757:  * Set the default special characters.
        !           758:  * Since this routine is called whenever a tty has never been opened,
        !           759:  * we can initialize the queues here.
        !           760:  */
        !           761: void ttychars(
        !           762:        register struct tty *tp)
        !           763: {
        !           764:        if ((tp->t_flags & TS_INIT) == 0) {
        !           765:            /*
        !           766:             * Initialize queues
        !           767:             */
        !           768:            queue_init(&tp->t_delayed_open);
        !           769:            queue_init(&tp->t_delayed_read);
        !           770:            queue_init(&tp->t_delayed_write);
        !           771: 
        !           772:            /*
        !           773:             * Initialize character buffers
        !           774:             */
        !           775:            cb_alloc(&tp->t_inq,  tty_inq_size);
        !           776: 
        !           777:            /* if we might do modem flow control */
        !           778:            if (tp->t_mctl && tp->t_inq.c_hog > 30)
        !           779:                tp->t_inq.c_hog -= 30;
        !           780: 
        !           781:            cb_alloc(&tp->t_outq, tty_outq_size);
        !           782: 
        !           783:            /*
        !           784:             * Mark initialized
        !           785:             */
        !           786:            tp->t_state |= TS_INIT;
        !           787:        }
        !           788: 
        !           789:        tp->t_breakc = 0;
        !           790: }
        !           791: 
        !           792: /*
        !           793:  * Flush all TTY queues.
        !           794:  * Called at spltty, tty already locked.
        !           795:  * Calls device STOP routine; must already be on master if
        !           796:  * device needs to run on master.
        !           797:  */
        !           798: void tty_flush(
        !           799:        register struct tty *tp,
        !           800:        int     rw)
        !           801: {
        !           802:        if (rw & D_READ) {
        !           803:            cb_clear(&tp->t_inq);
        !           804:            tty_queue_completion(&tp->t_delayed_read);
        !           805:        }
        !           806:        if (rw & D_WRITE) {
        !           807:            tp->t_state &= ~TS_TTSTOP;
        !           808:            (*tp->t_stop)(tp, rw);
        !           809:            cb_clear(&tp->t_outq);
        !           810:            tty_queue_completion(&tp->t_delayed_write);
        !           811:        }
        !           812: }
        !           813:                
        !           814: /*
        !           815:  * Restart character output after a delay timeout.
        !           816:  * Calls device start routine - must be on master CPU.
        !           817:  *
        !           818:  *     Timeout routines are called only on master CPU.
        !           819:  *     What if device runs on a different CPU?
        !           820:  */
        !           821: void ttrstrt(
        !           822:        register struct tty *tp)
        !           823: {
        !           824:        register spl_t  s;
        !           825: 
        !           826:        s = spltty();
        !           827:        simple_lock(&tp->t_lock);
        !           828: 
        !           829:        tp->t_state &= ~TS_TIMEOUT;
        !           830:        ttstart (tp);
        !           831: 
        !           832:        simple_unlock(&tp->t_lock);
        !           833:         splx(s);
        !           834: }
        !           835: 
        !           836: /*
        !           837:  * Start output on the typewriter. It is used from the top half
        !           838:  * after some characters have been put on the output queue,
        !           839:  * from the interrupt routine to transmit the next
        !           840:  * character, and after a timeout has finished.
        !           841:  *
        !           842:  * Called at spltty, tty already locked.
        !           843:  * Must be on master CPU if device runs on master.
        !           844:  */
        !           845: void ttstart(tp)
        !           846:        register struct tty *tp;
        !           847: {
        !           848:        if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0) {
        !           849:            /*
        !           850:             * Start up the hardware again
        !           851:             */
        !           852:            (*tp->t_start)(tp);
        !           853: 
        !           854:            /*
        !           855:             * Wake up those waiting for write completion.
        !           856:             */
        !           857:            if (tp->t_outq.c_cc <= TTLOWAT(tp))
        !           858:                tty_queue_completion(&tp->t_delayed_write);
        !           859:        }
        !           860: }
        !           861: 
        !           862: /*
        !           863:  * Start character output, if the device is not busy or
        !           864:  * stopped or waiting for a timeout.
        !           865:  *
        !           866:  * Called at spltty, tty already locked.
        !           867:  * Must be on master CPU if device runs on master.
        !           868:  */
        !           869: void tty_output(
        !           870:        register struct tty *tp)
        !           871: {
        !           872:        if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0) {
        !           873:            /*
        !           874:             * Not busy.  Start output.
        !           875:             */
        !           876:            (*tp->t_start)(tp);
        !           877: 
        !           878:            /*
        !           879:             * Wake up those waiting for write completion.
        !           880:             */
        !           881:            if (tp->t_outq.c_cc <= TTLOWAT(tp))
        !           882:                tty_queue_completion(&tp->t_delayed_write);
        !           883:        }
        !           884: }
        !           885: 
        !           886: /*
        !           887:  * Send any buffered recvd chars up to user
        !           888:  */
        !           889: void ttypush(
        !           890:        register struct tty     *tp)
        !           891: {
        !           892:        spl_t   s = spltty();
        !           893:        register int    state;
        !           894: 
        !           895:        simple_lock(&tp->t_lock);
        !           896: 
        !           897:        /*
        !           898:          The pdma timeout has gone off. 
        !           899:          If no character has been received since the timeout
        !           900:          was set, push any pending characters up.
        !           901:          If any characters were received in the last interval
        !           902:          then just reset the timeout and the character received bit.
        !           903:          */
        !           904: 
        !           905:        state = tp->t_state;
        !           906: 
        !           907:        if (state & TS_MIN_TO)
        !           908:          {
        !           909:            if (state & TS_MIN_TO_RCV)
        !           910:              { /* a character was received */
        !           911:                tp->t_state = state & ~TS_MIN_TO_RCV;
        !           912:                timeout(ttypush,tp,pdma_timeouts[tp->t_ispeed]);
        !           913:              }
        !           914:            else
        !           915:              {
        !           916:                tp->t_state = state & ~TS_MIN_TO;
        !           917:                if (tp->t_inq.c_cc) /* pending characters */
        !           918:                  tty_queue_completion(&tp->t_delayed_read);
        !           919:              }
        !           920:          }
        !           921:        else
        !           922:          {
        !           923:            tp->t_state = state & ~TS_MIN_TO_RCV;/* sanity */
        !           924:          }
        !           925: 
        !           926:        simple_unlock(&tp->t_lock);
        !           927:        splx(s);
        !           928: }
        !           929: 
        !           930: /*
        !           931:  * Put input character on input queue.
        !           932:  *
        !           933:  * Called at spltty, tty already locked.
        !           934:  */
        !           935: void ttyinput(
        !           936:        unsigned int    c,
        !           937:        struct tty      *tp)
        !           938: {
        !           939:   if (tp->t_inq.c_cc >= tp->t_inq.c_hog) {
        !           940:     /*
        !           941:      * Do not want to overflow input queue
        !           942:      */
        !           943:     if (tp->t_mctl) {
        !           944:        (*tp->t_mctl)(tp, TM_RTS, DMBIC);
        !           945:        tp->t_state |= TS_RTS_DOWN;
        !           946:     }
        !           947:     tty_queue_completion(&tp->t_delayed_read);
        !           948:     return;
        !           949: 
        !           950:   }
        !           951: 
        !           952:   c &= 0xff;
        !           953: 
        !           954:   (void) putc(c, &tp->t_inq);
        !           955:   if ((tp->t_state & TS_MIN) == 0 ||
        !           956:        tp->t_inq.c_cc > pdma_water_mark[tp->t_ispeed])
        !           957:      {
        !           958:          /*
        !           959:           * No input buffering, or input minimum exceeded.
        !           960:           * Grab a request from input queue and queue it
        !           961:           * to io_done thread.
        !           962:           */
        !           963:          if (tp->t_state & TS_MIN_TO) {
        !           964:            tp->t_state &= ~(TS_MIN_TO|TS_MIN_TO_RCV);
        !           965:            untimeout(ttypush, tp);
        !           966:          }
        !           967:          tty_queue_completion(&tp->t_delayed_read);
        !           968:       }
        !           969:       else {
        !           970:        /*
        !           971:         * Not enough characters. 
        !           972:         * If no timeout is set, initiate the timeout 
        !           973:         * Otherwise set the character received during timeout interval
        !           974:         * flag.
        !           975:         * One alternative approach would be just to reset the timeout
        !           976:         * into the future, but this involves making a timeout/untimeout
        !           977:         * call on every character.
        !           978:         */
        !           979:        register int ptime = pdma_timeouts[tp->t_ispeed];
        !           980:        if (ptime > 0)
        !           981:          {
        !           982:            if ((tp->t_state & TS_MIN_TO) == 0)
        !           983:              {
        !           984:                tp->t_state |= TS_MIN_TO;
        !           985:                timeout(ttypush, tp, ptime);
        !           986:              }
        !           987:            else
        !           988:              {
        !           989:                tp->t_state |= TS_MIN_TO_RCV;
        !           990:              }
        !           991:          }
        !           992:       }
        !           993: }
        !           994: 
        !           995: /*
        !           996:  * Put many characters on input queue.
        !           997:  *
        !           998:  * Called at spltty, tty already locked.
        !           999:  */
        !          1000: void ttyinput_many(
        !          1001:        struct tty      *tp,
        !          1002:        unsigned char   *chars,
        !          1003:        int             count)
        !          1004: {
        !          1005:        /*
        !          1006:         * Do not want to overflow input queue 
        !          1007:         */
        !          1008:        if (tp->t_inq.c_cc < tp->t_inq.c_hog)
        !          1009:                count -= b_to_q( chars, count, &tp->t_inq);
        !          1010: 
        !          1011:        tty_queue_completion(&tp->t_delayed_read);
        !          1012: }
        !          1013: 
        !          1014: 
        !          1015: /*
        !          1016:  * Handle modem control transition on a tty.
        !          1017:  * Flag indicates new state of carrier.
        !          1018:  * Returns FALSE if the line should be turned off.
        !          1019:  *
        !          1020:  * Called at spltty, tty already locked.
        !          1021:  */
        !          1022: boolean_t ttymodem(
        !          1023:        struct tty *    tp,
        !          1024:        boolean_t       carrier_up)
        !          1025: {
        !          1026:        if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) {
        !          1027:            /*
        !          1028:             * Flow control by carrier.  Carrier down stops
        !          1029:             * output; carrier up restarts output.
        !          1030:             */
        !          1031:            if (carrier_up) {
        !          1032:                tp->t_state &= ~TS_TTSTOP;
        !          1033:                tty_output(tp);
        !          1034:            }
        !          1035:            else if ((tp->t_state&TS_TTSTOP) == 0) {
        !          1036:                tp->t_state |= TS_TTSTOP;
        !          1037:                (*tp->t_stop)(tp, 0);
        !          1038:            }
        !          1039:        }
        !          1040:        else if (carrier_up) {
        !          1041:            /*
        !          1042:             * Carrier now on.
        !          1043:             */
        !          1044:            tp->t_state |= TS_CARR_ON;
        !          1045:            tt_open_wakeup(tp);
        !          1046:        }
        !          1047:        else {
        !          1048:            /*
        !          1049:             * Lost carrier.
        !          1050:             */
        !          1051:            tp->t_state &= ~TS_CARR_ON;
        !          1052:            if (tp->t_state & TS_ISOPEN &&
        !          1053:                (tp->t_flags & NOHANG) == 0)
        !          1054:            {
        !          1055:                /*
        !          1056:                 * Hang up TTY if carrier drops.
        !          1057:                 * Need to alert users, somehow...
        !          1058:                 */
        !          1059:                tty_flush(tp, D_READ|D_WRITE);
        !          1060:                return FALSE;
        !          1061:            }
        !          1062:        }
        !          1063:        return TRUE;
        !          1064: }
        !          1065: 
        !          1066: /*
        !          1067:  * Similarly, handle transitions on the ClearToSend
        !          1068:  * signal.  Nowadays, it is used by many modems as
        !          1069:  * a flow-control device: they turn it down to stop
        !          1070:  * us from sending more chars.  We do the same with
        !          1071:  * the RequestToSend signal. [Yes, that is exactly
        !          1072:  * why those signals are defined in the standard.]
        !          1073:  *
        !          1074:  * Tty must be locked and on master.
        !          1075:  */
        !          1076: tty_cts(
        !          1077:        struct tty *    tp,
        !          1078:        boolean_t       cts_up)
        !          1079: {
        !          1080:        if (tp->t_state & TS_ISOPEN){
        !          1081:                if (cts_up) {
        !          1082:                        tp->t_state &= ~(TS_TTSTOP|TS_BUSY);
        !          1083:                        tty_output(tp);
        !          1084:                } else {
        !          1085:                        tp->t_state |= (TS_TTSTOP|TS_BUSY);
        !          1086:                        (*tp->t_stop)(tp, D_WRITE);
        !          1087:                }
        !          1088:        }
        !          1089: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.