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