xref: /titanic_51/usr/src/uts/common/io/tty_common.c (revision 19d32b9ab53d17ac6605971e14c45a5281f8d9bb)
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
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
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
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
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
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