17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
87c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
97c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
107c478bd9Sstevel@tonic-gate */
117c478bd9Sstevel@tonic-gate
127c478bd9Sstevel@tonic-gate #include <sys/types.h>
137c478bd9Sstevel@tonic-gate #include <sys/param.h>
147c478bd9Sstevel@tonic-gate #include <sys/signal.h>
157c478bd9Sstevel@tonic-gate #include <sys/systm.h>
167c478bd9Sstevel@tonic-gate #include <sys/termio.h>
177c478bd9Sstevel@tonic-gate #include <sys/ttold.h>
187c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
197c478bd9Sstevel@tonic-gate #include <sys/stream.h>
207c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
217c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
227c478bd9Sstevel@tonic-gate #include <sys/tty.h>
237c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
247c478bd9Sstevel@tonic-gate #include <sys/errno.h>
257c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
267c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
277c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * The default (sane) set of termios values, unless
317c478bd9Sstevel@tonic-gate * otherwise set by the user.
327c478bd9Sstevel@tonic-gate */
337c478bd9Sstevel@tonic-gate static struct termios default_termios = {
347c478bd9Sstevel@tonic-gate BRKINT|ICRNL|IXON|IMAXBEL, /* c_iflag */
357c478bd9Sstevel@tonic-gate OPOST|ONLCR|TAB3, /* c_oflag */
367c478bd9Sstevel@tonic-gate B9600|CS8|CREAD, /* c_cflag */
377c478bd9Sstevel@tonic-gate ISIG|ICANON|IEXTEN|ECHO|ECHOK|ECHOE|ECHOKE|ECHOCTL, /* c_lflag */
387c478bd9Sstevel@tonic-gate {
397c478bd9Sstevel@tonic-gate CINTR,
407c478bd9Sstevel@tonic-gate CQUIT,
417c478bd9Sstevel@tonic-gate CERASE,
427c478bd9Sstevel@tonic-gate CKILL,
437c478bd9Sstevel@tonic-gate CEOF,
447c478bd9Sstevel@tonic-gate CEOL,
457c478bd9Sstevel@tonic-gate CEOL2,
467c478bd9Sstevel@tonic-gate CNSWTCH,
477c478bd9Sstevel@tonic-gate CSTART,
487c478bd9Sstevel@tonic-gate CSTOP,
497c478bd9Sstevel@tonic-gate CSUSP,
507c478bd9Sstevel@tonic-gate CDSUSP,
517c478bd9Sstevel@tonic-gate CRPRNT,
527c478bd9Sstevel@tonic-gate CFLUSH,
537c478bd9Sstevel@tonic-gate CWERASE,
547c478bd9Sstevel@tonic-gate CLNEXT,
55*19d32b9aSRobert Mustacchi CSTATUS
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate };
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate static int termioval(char **, uint_t *, char *);
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate void
ttycommon_close(tty_common_t * tc)637c478bd9Sstevel@tonic-gate ttycommon_close(tty_common_t *tc)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
667c478bd9Sstevel@tonic-gate tc->t_flags &= ~TS_XCLUDE;
677c478bd9Sstevel@tonic-gate tc->t_readq = NULL;
687c478bd9Sstevel@tonic-gate tc->t_writeq = NULL;
697c478bd9Sstevel@tonic-gate if (tc->t_iocpending != NULL) {
707c478bd9Sstevel@tonic-gate mblk_t *mp;
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate mp = tc->t_iocpending;
737c478bd9Sstevel@tonic-gate tc->t_iocpending = NULL;
747c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * We were holding an "ioctl" response pending the
777c478bd9Sstevel@tonic-gate * availability of an "mblk" to hold data to be passed up;
787c478bd9Sstevel@tonic-gate * another "ioctl" came through, which means that "ioctl"
797c478bd9Sstevel@tonic-gate * must have timed out or been aborted.
807c478bd9Sstevel@tonic-gate */
817c478bd9Sstevel@tonic-gate freemsg(mp);
827c478bd9Sstevel@tonic-gate } else
837c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate * A "line discipline" module's queue is full.
887c478bd9Sstevel@tonic-gate * Check whether IMAXBEL is set; if so, output a ^G, otherwise send an M_FLUSH
897c478bd9Sstevel@tonic-gate * upstream flushing all the read queues.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate void
ttycommon_qfull(tty_common_t * tc,queue_t * q)927c478bd9Sstevel@tonic-gate ttycommon_qfull(tty_common_t *tc, queue_t *q)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate mblk_t *mp;
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate if (tc->t_iflag & IMAXBEL) {
977c478bd9Sstevel@tonic-gate if (canput(WR(q))) {
987c478bd9Sstevel@tonic-gate if ((mp = allocb(1, BPRI_HI)) != NULL) {
997c478bd9Sstevel@tonic-gate *mp->b_wptr++ = CTRL('g');
1007c478bd9Sstevel@tonic-gate (void) putq(WR(q), mp);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate } else {
1047c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA);
1057c478bd9Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHR);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate * Process an "ioctl" message sent down to us, and return a reply message,
1117c478bd9Sstevel@tonic-gate * even if we don't understand the "ioctl". Our client may want to use
1127c478bd9Sstevel@tonic-gate * that reply message for its own purposes if we don't understand it but
1137c478bd9Sstevel@tonic-gate * they do, and may want to modify it if we both understand it but they
1147c478bd9Sstevel@tonic-gate * understand it better than we do.
1157c478bd9Sstevel@tonic-gate * If the "ioctl" reply requires additional data to be passed up to the
1167c478bd9Sstevel@tonic-gate * caller, and we cannot allocate an mblk to hold the data, we return the
1177c478bd9Sstevel@tonic-gate * amount of data to be sent, so that our caller can do a "bufcall" and try
1187c478bd9Sstevel@tonic-gate * again later; otherwise, we return 0.
1197c478bd9Sstevel@tonic-gate */
1207c478bd9Sstevel@tonic-gate size_t
ttycommon_ioctl(tty_common_t * tc,queue_t * q,mblk_t * mp,int * errorp)1217c478bd9Sstevel@tonic-gate ttycommon_ioctl(tty_common_t *tc, queue_t *q, mblk_t *mp, int *errorp)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate struct iocblk *iocp;
1247c478bd9Sstevel@tonic-gate size_t ioctlrespsize;
1257c478bd9Sstevel@tonic-gate mblk_t *tmp;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate *errorp = 0; /* no error detected yet */
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) {
1327c478bd9Sstevel@tonic-gate *errorp = -1; /* we don't understand it, maybe they do */
1337c478bd9Sstevel@tonic-gate return (0);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate case TCSETSF:
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate * Flush the driver's queue, and send an M_FLUSH upstream
1417c478bd9Sstevel@tonic-gate * to flush everybody above us.
1427c478bd9Sstevel@tonic-gate */
1437c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA);
1447c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR);
1457c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate case TCSETSW:
1487c478bd9Sstevel@tonic-gate case TCSETS: {
1497c478bd9Sstevel@tonic-gate struct termios *cb;
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (struct termios)) != 0) {
1527c478bd9Sstevel@tonic-gate *errorp = -1;
1537c478bd9Sstevel@tonic-gate break;
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * The only information we look at are the iflag word,
1587c478bd9Sstevel@tonic-gate * the cflag word, and the start and stop characters.
1597c478bd9Sstevel@tonic-gate */
1607c478bd9Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr;
1617c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
1627c478bd9Sstevel@tonic-gate tc->t_iflag = cb->c_iflag;
1637c478bd9Sstevel@tonic-gate tc->t_cflag = cb->c_cflag;
1647c478bd9Sstevel@tonic-gate tc->t_stopc = cb->c_cc[VSTOP];
1657c478bd9Sstevel@tonic-gate tc->t_startc = cb->c_cc[VSTART];
1667c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
1677c478bd9Sstevel@tonic-gate break;
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate case TCSETAF:
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate * Flush the driver's queue, and send an M_FLUSH upstream
1737c478bd9Sstevel@tonic-gate * to flush everybody above us.
1747c478bd9Sstevel@tonic-gate */
1757c478bd9Sstevel@tonic-gate flushq(RD(q), FLUSHDATA);
1767c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHR);
1777c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate case TCSETAW:
1807c478bd9Sstevel@tonic-gate case TCSETA: {
1817c478bd9Sstevel@tonic-gate struct termio *cb;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (struct termio)) != 0) {
1847c478bd9Sstevel@tonic-gate *errorp = -1;
1857c478bd9Sstevel@tonic-gate break;
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate * The only information we look at are the iflag word
1907c478bd9Sstevel@tonic-gate * and the cflag word. Don't touch the unset portions.
1917c478bd9Sstevel@tonic-gate */
1927c478bd9Sstevel@tonic-gate cb = (struct termio *)mp->b_cont->b_rptr;
1937c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
1947c478bd9Sstevel@tonic-gate tc->t_iflag = (tc->t_iflag & 0xffff0000 | cb->c_iflag);
1957c478bd9Sstevel@tonic-gate tc->t_cflag = (tc->t_cflag & 0xffff0000 | cb->c_cflag);
1967c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
1977c478bd9Sstevel@tonic-gate break;
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate case TIOCSWINSZ: {
2017c478bd9Sstevel@tonic-gate struct winsize *ws;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (struct winsize)) != 0) {
2047c478bd9Sstevel@tonic-gate *errorp = -1;
2057c478bd9Sstevel@tonic-gate break;
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate * If the window size changed, send a SIGWINCH.
2107c478bd9Sstevel@tonic-gate */
2117c478bd9Sstevel@tonic-gate ws = (struct winsize *)mp->b_cont->b_rptr;
2127c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
2137c478bd9Sstevel@tonic-gate if (bcmp(&tc->t_size, ws, sizeof (struct winsize)) != 0) {
2147c478bd9Sstevel@tonic-gate tc->t_size = *ws;
2157c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
2167c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_PCSIG, SIGWINCH);
2177c478bd9Sstevel@tonic-gate } else
2187c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
2197c478bd9Sstevel@tonic-gate break;
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate * Prevent more opens.
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate case TIOCEXCL:
2267c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
2277c478bd9Sstevel@tonic-gate tc->t_flags |= TS_XCLUDE;
2287c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
2297c478bd9Sstevel@tonic-gate break;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate * Permit more opens.
2337c478bd9Sstevel@tonic-gate */
2347c478bd9Sstevel@tonic-gate case TIOCNXCL:
2357c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
2367c478bd9Sstevel@tonic-gate tc->t_flags &= ~TS_XCLUDE;
2377c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
2387c478bd9Sstevel@tonic-gate break;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate * Set or clear the "soft carrier" flag.
2427c478bd9Sstevel@tonic-gate */
2437c478bd9Sstevel@tonic-gate case TIOCSSOFTCAR:
2447c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (int)) != 0) {
2457c478bd9Sstevel@tonic-gate *errorp = -1;
2467c478bd9Sstevel@tonic-gate break;
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
2507c478bd9Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr)
2517c478bd9Sstevel@tonic-gate tc->t_flags |= TS_SOFTCAR;
2527c478bd9Sstevel@tonic-gate else
2537c478bd9Sstevel@tonic-gate tc->t_flags &= ~TS_SOFTCAR;
2547c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
2557c478bd9Sstevel@tonic-gate break;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * The permission checking has already been done at the stream
2597c478bd9Sstevel@tonic-gate * head, since it has to be done in the context of the process
2607c478bd9Sstevel@tonic-gate * doing the call.
2617c478bd9Sstevel@tonic-gate */
2627c478bd9Sstevel@tonic-gate case TIOCSTI: {
2637c478bd9Sstevel@tonic-gate mblk_t *bp;
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate if (miocpullup(mp, sizeof (char)) != 0) {
2667c478bd9Sstevel@tonic-gate *errorp = -1;
2677c478bd9Sstevel@tonic-gate break;
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate * Simulate typing of a character at the terminal.
2727c478bd9Sstevel@tonic-gate */
2737c478bd9Sstevel@tonic-gate if ((bp = allocb(1, BPRI_MED)) != NULL) {
2747c478bd9Sstevel@tonic-gate if (!canput(tc->t_readq->q_next))
2757c478bd9Sstevel@tonic-gate freemsg(bp);
2767c478bd9Sstevel@tonic-gate else {
2777c478bd9Sstevel@tonic-gate *bp->b_wptr++ = *mp->b_cont->b_rptr;
2787c478bd9Sstevel@tonic-gate putnext(tc->t_readq, bp);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate break;
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate * Turn the ioctl message into an ioctl ACK message.
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; /* no data returned unless we say so */
2897c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate case TCSETSF:
2947c478bd9Sstevel@tonic-gate case TCSETSW:
2957c478bd9Sstevel@tonic-gate case TCSETS:
2967c478bd9Sstevel@tonic-gate case TCSETAF:
2977c478bd9Sstevel@tonic-gate case TCSETAW:
2987c478bd9Sstevel@tonic-gate case TCSETA:
2997c478bd9Sstevel@tonic-gate case TIOCSWINSZ:
3007c478bd9Sstevel@tonic-gate case TIOCEXCL:
3017c478bd9Sstevel@tonic-gate case TIOCNXCL:
3027c478bd9Sstevel@tonic-gate case TIOCSSOFTCAR:
3037c478bd9Sstevel@tonic-gate case TIOCSTI:
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate * We've done all the important work on these already;
3067c478bd9Sstevel@tonic-gate * just reply with an ACK.
3077c478bd9Sstevel@tonic-gate */
3087c478bd9Sstevel@tonic-gate break;
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate case TCGETS: {
3117c478bd9Sstevel@tonic-gate struct termios *cb;
3127c478bd9Sstevel@tonic-gate mblk_t *datap;
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct termios),
3157c478bd9Sstevel@tonic-gate BPRI_HI)) == NULL) {
3167c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (struct termios);
3177c478bd9Sstevel@tonic-gate goto allocfailure;
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate cb = (struct termios *)datap->b_wptr;
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate * The only information we supply is the cflag word.
3227c478bd9Sstevel@tonic-gate * Our copy of the iflag word is just that, a copy.
3237c478bd9Sstevel@tonic-gate */
3247c478bd9Sstevel@tonic-gate bzero(cb, sizeof (struct termios));
3257c478bd9Sstevel@tonic-gate cb->c_cflag = tc->t_cflag;
3267c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct termios);
3277c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct termios);
3287c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL)
3297c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
3307c478bd9Sstevel@tonic-gate mp->b_cont = datap;
3317c478bd9Sstevel@tonic-gate break;
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate case TCGETA: {
3357c478bd9Sstevel@tonic-gate struct termio *cb;
3367c478bd9Sstevel@tonic-gate mblk_t *datap;
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct termio), BPRI_HI)) == NULL) {
3397c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (struct termio);
3407c478bd9Sstevel@tonic-gate goto allocfailure;
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate cb = (struct termio *)datap->b_wptr;
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate * The only information we supply is the cflag word.
3467c478bd9Sstevel@tonic-gate * Our copy of the iflag word is just that, a copy.
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate bzero(cb, sizeof (struct termio));
3497c478bd9Sstevel@tonic-gate cb->c_cflag = tc->t_cflag;
3507c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct termio);
3517c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct termio);
3527c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL)
3537c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
3547c478bd9Sstevel@tonic-gate mp->b_cont = datap;
3557c478bd9Sstevel@tonic-gate break;
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate * Get the "soft carrier" flag.
3607c478bd9Sstevel@tonic-gate */
3617c478bd9Sstevel@tonic-gate case TIOCGSOFTCAR: {
3627c478bd9Sstevel@tonic-gate mblk_t *datap;
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
3657c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (int);
3667c478bd9Sstevel@tonic-gate goto allocfailure;
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate if (tc->t_flags & TS_SOFTCAR)
3697c478bd9Sstevel@tonic-gate *(int *)datap->b_wptr = 1;
3707c478bd9Sstevel@tonic-gate else
3717c478bd9Sstevel@tonic-gate *(int *)datap->b_wptr = 0;
3727c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (int);
3737c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (int);
3747c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL)
3757c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
3767c478bd9Sstevel@tonic-gate mp->b_cont = datap;
3777c478bd9Sstevel@tonic-gate break;
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate case TIOCGWINSZ: {
3817c478bd9Sstevel@tonic-gate mblk_t *datap;
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate if ((datap = allocb(sizeof (struct winsize),
3847c478bd9Sstevel@tonic-gate BPRI_HI)) == NULL) {
3857c478bd9Sstevel@tonic-gate ioctlrespsize = sizeof (struct winsize);
3867c478bd9Sstevel@tonic-gate goto allocfailure;
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate * Return the current size.
3907c478bd9Sstevel@tonic-gate */
3917c478bd9Sstevel@tonic-gate *(struct winsize *)datap->b_wptr = tc->t_size;
3927c478bd9Sstevel@tonic-gate datap->b_wptr += sizeof (struct winsize);
3937c478bd9Sstevel@tonic-gate iocp->ioc_count = sizeof (struct winsize);
3947c478bd9Sstevel@tonic-gate if (mp->b_cont != NULL)
3957c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
3967c478bd9Sstevel@tonic-gate mp->b_cont = datap;
3977c478bd9Sstevel@tonic-gate break;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate default:
4017c478bd9Sstevel@tonic-gate *errorp = -1; /* we don't understand it, maybe they do */
4027c478bd9Sstevel@tonic-gate break;
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate return (0);
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate allocfailure:
4077c478bd9Sstevel@tonic-gate
4087c478bd9Sstevel@tonic-gate mutex_enter(&tc->t_excl);
4097c478bd9Sstevel@tonic-gate tmp = tc->t_iocpending;
4107c478bd9Sstevel@tonic-gate tc->t_iocpending = mp; /* hold this ioctl */
4117c478bd9Sstevel@tonic-gate mutex_exit(&tc->t_excl);
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate * We needed to allocate something to handle this "ioctl", but
4147c478bd9Sstevel@tonic-gate * couldn't; save this "ioctl" and arrange to get called back when
4157c478bd9Sstevel@tonic-gate * it's more likely that we can get what we need.
4167c478bd9Sstevel@tonic-gate * If there's already one being saved, throw it out, since it
4177c478bd9Sstevel@tonic-gate * must have timed out.
4187c478bd9Sstevel@tonic-gate */
4197c478bd9Sstevel@tonic-gate if (tmp != NULL)
4207c478bd9Sstevel@tonic-gate freemsg(tmp);
4217c478bd9Sstevel@tonic-gate return (ioctlrespsize);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate
424*19d32b9aSRobert Mustacchi #define NFIELDS 21 /* 16 control characters + 4 sets of modes */
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate * Init routine run from main at boot time.
4287c478bd9Sstevel@tonic-gate * Creates a property in the "options" node that is
4297c478bd9Sstevel@tonic-gate * the default set of termios modes upon driver open.
4307c478bd9Sstevel@tonic-gate * If the property already existed, then it was
4317c478bd9Sstevel@tonic-gate * defined in the options.conf file. In this case we
4327c478bd9Sstevel@tonic-gate * need to convert this string (stty -g style) to an
4337c478bd9Sstevel@tonic-gate * actual termios structure and store the new property
4347c478bd9Sstevel@tonic-gate * value.
4357c478bd9Sstevel@tonic-gate */
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate void
ttyinit()4387c478bd9Sstevel@tonic-gate ttyinit()
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate dev_info_t *dip;
4417c478bd9Sstevel@tonic-gate struct termios new_termios;
4427c478bd9Sstevel@tonic-gate struct termios *tp;
4437c478bd9Sstevel@tonic-gate char *property = "ttymodes";
4447c478bd9Sstevel@tonic-gate char **modesp, *cp;
4457c478bd9Sstevel@tonic-gate int i;
4467c478bd9Sstevel@tonic-gate uint_t val;
4477c478bd9Sstevel@tonic-gate uint_t len;
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate * If the termios defaults were NOT set up by the
4527c478bd9Sstevel@tonic-gate * user via the options.conf file, create it using the
4537c478bd9Sstevel@tonic-gate * "sane" set of termios modes.
4547c478bd9Sstevel@tonic-gate * Note that if the property had been created via the
4557c478bd9Sstevel@tonic-gate * options.conf file, it would have been created as
4567c478bd9Sstevel@tonic-gate * a string property. Since we would like to store
4577c478bd9Sstevel@tonic-gate * a structure (termios) in this property, we need
4587c478bd9Sstevel@tonic-gate * to change the property type to byte array.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(), 0,
4617c478bd9Sstevel@tonic-gate property, (char ***)&modesp, &len) != DDI_PROP_SUCCESS) {
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) {
4647c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC,
4657c478bd9Sstevel@tonic-gate "ttyinit: Can't find options node!\n");
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate * Create the property.
4697c478bd9Sstevel@tonic-gate */
4707c478bd9Sstevel@tonic-gate if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
4717c478bd9Sstevel@tonic-gate property, (uchar_t *)&default_termios,
4727c478bd9Sstevel@tonic-gate sizeof (struct termios)) != DDI_PROP_SUCCESS) {
4737c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "ttyinit: can't create %s property\n",
4747c478bd9Sstevel@tonic-gate property);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate return;
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate * This property was already set in the options.conf
4817c478bd9Sstevel@tonic-gate * file. We must convert it from a "stty -g" string
4827c478bd9Sstevel@tonic-gate * to an actual termios structure.
4837c478bd9Sstevel@tonic-gate */
4847c478bd9Sstevel@tonic-gate bzero(&new_termios, sizeof (struct termios));
4857c478bd9Sstevel@tonic-gate tp = &new_termios;
4867c478bd9Sstevel@tonic-gate cp = *modesp;
4877c478bd9Sstevel@tonic-gate for (i = 0; i < NFIELDS; i++) {
4887c478bd9Sstevel@tonic-gate /*
4897c478bd9Sstevel@tonic-gate * Check for bad field/string.
4907c478bd9Sstevel@tonic-gate */
4917c478bd9Sstevel@tonic-gate if (termioval(&cp, &val, *modesp+strlen(*modesp)) == -1) {
4927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
4937c478bd9Sstevel@tonic-gate "ttyinit: property '%s' %s\n", property,
4947c478bd9Sstevel@tonic-gate "set incorrectly, using sane value");
4957c478bd9Sstevel@tonic-gate tp = &default_termios;
4967c478bd9Sstevel@tonic-gate break;
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate switch (i) {
4997c478bd9Sstevel@tonic-gate case 0:
5007c478bd9Sstevel@tonic-gate new_termios.c_iflag = (tcflag_t)val;
5017c478bd9Sstevel@tonic-gate break;
5027c478bd9Sstevel@tonic-gate case 1:
5037c478bd9Sstevel@tonic-gate new_termios.c_oflag = (tcflag_t)val;
5047c478bd9Sstevel@tonic-gate break;
5057c478bd9Sstevel@tonic-gate case 2:
5067c478bd9Sstevel@tonic-gate new_termios.c_cflag = (tcflag_t)val;
5077c478bd9Sstevel@tonic-gate break;
5087c478bd9Sstevel@tonic-gate case 3:
5097c478bd9Sstevel@tonic-gate new_termios.c_lflag = (tcflag_t)val;
5107c478bd9Sstevel@tonic-gate break;
5117c478bd9Sstevel@tonic-gate default:
5127c478bd9Sstevel@tonic-gate new_termios.c_cc[i - 4] = (cc_t)val;
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) {
5167c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "ttyinit: Can't find options node!\n");
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate /*
5207c478bd9Sstevel@tonic-gate * We need to create ttymode property as a byte array
5217c478bd9Sstevel@tonic-gate * since it will be interpreted as a termios struct.
5227c478bd9Sstevel@tonic-gate * The property was created as a string by default.
5237c478bd9Sstevel@tonic-gate * So remove the old property and add the new one -
5247c478bd9Sstevel@tonic-gate * otherwise we end up with two ttymodes properties.
5257c478bd9Sstevel@tonic-gate */
5267c478bd9Sstevel@tonic-gate if (e_ddi_prop_remove(DDI_DEV_T_NONE, dip, property)
5277c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) {
5287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ttyinit: cannot remove '%s' property\n",
5297c478bd9Sstevel@tonic-gate property);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate * Store the new defaults. Since, this property was
5337c478bd9Sstevel@tonic-gate * autoconfig'ed, we must use e_ddi_prop_update_byte_array().
5347c478bd9Sstevel@tonic-gate */
5357c478bd9Sstevel@tonic-gate if (e_ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip, property,
5367c478bd9Sstevel@tonic-gate (uchar_t *)tp, sizeof (struct termios)) != DDI_PROP_SUCCESS) {
5377c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "ttyinit: cannot modify '%s' property\n",
5387c478bd9Sstevel@tonic-gate property);
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate ddi_prop_free(modesp);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate /*
5447c478bd9Sstevel@tonic-gate * Convert hex string representation of termios field
5457c478bd9Sstevel@tonic-gate * to a uint_t. Increments string pointer to the next
5467c478bd9Sstevel@tonic-gate * field, and assigns value. Returns -1 if no more fields
5477c478bd9Sstevel@tonic-gate * or an error.
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate static int
termioval(char ** sp,uint_t * valp,char * ep)5517c478bd9Sstevel@tonic-gate termioval(char **sp, uint_t *valp, char *ep)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate char *s = *sp;
5547c478bd9Sstevel@tonic-gate uint_t digit;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate if (s == 0)
5577c478bd9Sstevel@tonic-gate return (-1);
5587c478bd9Sstevel@tonic-gate *valp = 0;
5597c478bd9Sstevel@tonic-gate while (s < ep) {
5607c478bd9Sstevel@tonic-gate if (*s >= '0' && *s <= '9')
5617c478bd9Sstevel@tonic-gate digit = *s++ - '0';
5627c478bd9Sstevel@tonic-gate else if (*s >= 'a' && *s <= 'f')
5637c478bd9Sstevel@tonic-gate digit = *s++ - 'a' + 10;
5647c478bd9Sstevel@tonic-gate else if (*s >= 'A' && *s <= 'F')
5657c478bd9Sstevel@tonic-gate digit = *s++ - 'A' + 10;
5667c478bd9Sstevel@tonic-gate else if (*s == ':' || *s == '\0')
5677c478bd9Sstevel@tonic-gate break;
5687c478bd9Sstevel@tonic-gate else
5697c478bd9Sstevel@tonic-gate return (-1);
5707c478bd9Sstevel@tonic-gate *valp = (*valp * 16) + digit;
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate * Null string or empty field.
5747c478bd9Sstevel@tonic-gate */
5757c478bd9Sstevel@tonic-gate if (s == *sp)
5767c478bd9Sstevel@tonic-gate return (-1);
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate if (s < ep && *s == ':')
5797c478bd9Sstevel@tonic-gate s++;
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate *sp = s;
5827c478bd9Sstevel@tonic-gate return (0);
5837c478bd9Sstevel@tonic-gate }
584