xref: /onnv-gate/usr/src/uts/common/io/tty_common.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*
7*0Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
8*0Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
9*0Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
10*0Sstevel@tonic-gate  */
11*0Sstevel@tonic-gate 
12*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
13*0Sstevel@tonic-gate 
14*0Sstevel@tonic-gate #include <sys/types.h>
15*0Sstevel@tonic-gate #include <sys/param.h>
16*0Sstevel@tonic-gate #include <sys/signal.h>
17*0Sstevel@tonic-gate #include <sys/systm.h>
18*0Sstevel@tonic-gate #include <sys/termio.h>
19*0Sstevel@tonic-gate #include <sys/ttold.h>
20*0Sstevel@tonic-gate #include <sys/stropts.h>
21*0Sstevel@tonic-gate #include <sys/stream.h>
22*0Sstevel@tonic-gate #include <sys/strsubr.h>
23*0Sstevel@tonic-gate #include <sys/strsun.h>
24*0Sstevel@tonic-gate #include <sys/tty.h>
25*0Sstevel@tonic-gate #include <sys/kmem.h>
26*0Sstevel@tonic-gate #include <sys/errno.h>
27*0Sstevel@tonic-gate #include <sys/ddi.h>
28*0Sstevel@tonic-gate #include <sys/sunddi.h>
29*0Sstevel@tonic-gate #include <sys/esunddi.h>
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate /*
32*0Sstevel@tonic-gate  * The default (sane) set of termios values, unless
33*0Sstevel@tonic-gate  * otherwise set by the user.
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate static struct termios default_termios = {
36*0Sstevel@tonic-gate 	BRKINT|ICRNL|IXON|IMAXBEL,		/* c_iflag */
37*0Sstevel@tonic-gate 	OPOST|ONLCR|TAB3,			/* c_oflag */
38*0Sstevel@tonic-gate 	B9600|CS8|CREAD,			/* c_cflag */
39*0Sstevel@tonic-gate 	ISIG|ICANON|IEXTEN|ECHO|ECHOK|ECHOE|ECHOKE|ECHOCTL, /* c_lflag */
40*0Sstevel@tonic-gate 	{
41*0Sstevel@tonic-gate 		CINTR,
42*0Sstevel@tonic-gate 		CQUIT,
43*0Sstevel@tonic-gate 		CERASE,
44*0Sstevel@tonic-gate 		CKILL,
45*0Sstevel@tonic-gate 		CEOF,
46*0Sstevel@tonic-gate 		CEOL,
47*0Sstevel@tonic-gate 		CEOL2,
48*0Sstevel@tonic-gate 		CNSWTCH,
49*0Sstevel@tonic-gate 		CSTART,
50*0Sstevel@tonic-gate 		CSTOP,
51*0Sstevel@tonic-gate 		CSUSP,
52*0Sstevel@tonic-gate 		CDSUSP,
53*0Sstevel@tonic-gate 		CRPRNT,
54*0Sstevel@tonic-gate 		CFLUSH,
55*0Sstevel@tonic-gate 		CWERASE,
56*0Sstevel@tonic-gate 		CLNEXT,
57*0Sstevel@tonic-gate 		0		/* nonexistent STATUS */
58*0Sstevel@tonic-gate 	}
59*0Sstevel@tonic-gate };
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate static int termioval(char **, uint_t *, char *);
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate void
ttycommon_close(tty_common_t * tc)65*0Sstevel@tonic-gate ttycommon_close(tty_common_t *tc)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	mutex_enter(&tc->t_excl);
68*0Sstevel@tonic-gate 	tc->t_flags &= ~TS_XCLUDE;
69*0Sstevel@tonic-gate 	tc->t_readq = NULL;
70*0Sstevel@tonic-gate 	tc->t_writeq = NULL;
71*0Sstevel@tonic-gate 	if (tc->t_iocpending != NULL) {
72*0Sstevel@tonic-gate 		mblk_t *mp;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 		mp = tc->t_iocpending;
75*0Sstevel@tonic-gate 		tc->t_iocpending = NULL;
76*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
77*0Sstevel@tonic-gate 		/*
78*0Sstevel@tonic-gate 		 * We were holding an "ioctl" response pending the
79*0Sstevel@tonic-gate 		 * availability of an "mblk" to hold data to be passed up;
80*0Sstevel@tonic-gate 		 * another "ioctl" came through, which means that "ioctl"
81*0Sstevel@tonic-gate 		 * must have timed out or been aborted.
82*0Sstevel@tonic-gate 		 */
83*0Sstevel@tonic-gate 		freemsg(mp);
84*0Sstevel@tonic-gate 	} else
85*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate /*
89*0Sstevel@tonic-gate  * A "line discipline" module's queue is full.
90*0Sstevel@tonic-gate  * Check whether IMAXBEL is set; if so, output a ^G, otherwise send an M_FLUSH
91*0Sstevel@tonic-gate  * upstream flushing all the read queues.
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate void
ttycommon_qfull(tty_common_t * tc,queue_t * q)94*0Sstevel@tonic-gate ttycommon_qfull(tty_common_t *tc, queue_t *q)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	mblk_t *mp;
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	if (tc->t_iflag & IMAXBEL) {
99*0Sstevel@tonic-gate 		if (canput(WR(q))) {
100*0Sstevel@tonic-gate 			if ((mp = allocb(1, BPRI_HI)) != NULL) {
101*0Sstevel@tonic-gate 				*mp->b_wptr++ = CTRL('g');
102*0Sstevel@tonic-gate 				(void) putq(WR(q), mp);
103*0Sstevel@tonic-gate 			}
104*0Sstevel@tonic-gate 		}
105*0Sstevel@tonic-gate 	} else {
106*0Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
107*0Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
108*0Sstevel@tonic-gate 	}
109*0Sstevel@tonic-gate }
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate /*
112*0Sstevel@tonic-gate  * Process an "ioctl" message sent down to us, and return a reply message,
113*0Sstevel@tonic-gate  * even if we don't understand the "ioctl".  Our client may want to use
114*0Sstevel@tonic-gate  * that reply message for its own purposes if we don't understand it but
115*0Sstevel@tonic-gate  * they do, and may want to modify it if we both understand it but they
116*0Sstevel@tonic-gate  * understand it better than we do.
117*0Sstevel@tonic-gate  * If the "ioctl" reply requires additional data to be passed up to the
118*0Sstevel@tonic-gate  * caller, and we cannot allocate an mblk to hold the data, we return the
119*0Sstevel@tonic-gate  * amount of data to be sent, so that our caller can do a "bufcall" and try
120*0Sstevel@tonic-gate  * again later; otherwise, we return 0.
121*0Sstevel@tonic-gate  */
122*0Sstevel@tonic-gate size_t
ttycommon_ioctl(tty_common_t * tc,queue_t * q,mblk_t * mp,int * errorp)123*0Sstevel@tonic-gate ttycommon_ioctl(tty_common_t *tc, queue_t *q, mblk_t *mp, int *errorp)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	struct iocblk *iocp;
126*0Sstevel@tonic-gate 	size_t ioctlrespsize;
127*0Sstevel@tonic-gate 	mblk_t *tmp;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	*errorp = 0;	/* no error detected yet */
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 	if (iocp->ioc_count == TRANSPARENT) {
134*0Sstevel@tonic-gate 		*errorp = -1;	/* we don't understand it, maybe they do */
135*0Sstevel@tonic-gate 		return (0);
136*0Sstevel@tonic-gate 	}
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	case TCSETSF:
141*0Sstevel@tonic-gate 		/*
142*0Sstevel@tonic-gate 		 * Flush the driver's queue, and send an M_FLUSH upstream
143*0Sstevel@tonic-gate 		 * to flush everybody above us.
144*0Sstevel@tonic-gate 		 */
145*0Sstevel@tonic-gate 		flushq(RD(q), FLUSHDATA);
146*0Sstevel@tonic-gate 		(void) putnextctl1(RD(q), M_FLUSH, FLUSHR);
147*0Sstevel@tonic-gate 		/* FALLTHROUGH */
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	case TCSETSW:
150*0Sstevel@tonic-gate 	case TCSETS: {
151*0Sstevel@tonic-gate 		struct termios *cb;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 		if (miocpullup(mp, sizeof (struct termios)) != 0) {
154*0Sstevel@tonic-gate 			*errorp = -1;
155*0Sstevel@tonic-gate 			break;
156*0Sstevel@tonic-gate 		}
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 		/*
159*0Sstevel@tonic-gate 		 * The only information we look at are the iflag word,
160*0Sstevel@tonic-gate 		 * the cflag word, and the start and stop characters.
161*0Sstevel@tonic-gate 		 */
162*0Sstevel@tonic-gate 		cb = (struct termios *)mp->b_cont->b_rptr;
163*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
164*0Sstevel@tonic-gate 		tc->t_iflag = cb->c_iflag;
165*0Sstevel@tonic-gate 		tc->t_cflag = cb->c_cflag;
166*0Sstevel@tonic-gate 		tc->t_stopc = cb->c_cc[VSTOP];
167*0Sstevel@tonic-gate 		tc->t_startc = cb->c_cc[VSTART];
168*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
169*0Sstevel@tonic-gate 		break;
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	case TCSETAF:
173*0Sstevel@tonic-gate 		/*
174*0Sstevel@tonic-gate 		 * Flush the driver's queue, and send an M_FLUSH upstream
175*0Sstevel@tonic-gate 		 * to flush everybody above us.
176*0Sstevel@tonic-gate 		 */
177*0Sstevel@tonic-gate 		flushq(RD(q), FLUSHDATA);
178*0Sstevel@tonic-gate 		(void) putnextctl1(RD(q), M_FLUSH, FLUSHR);
179*0Sstevel@tonic-gate 		/* FALLTHROUGH */
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	case TCSETAW:
182*0Sstevel@tonic-gate 	case TCSETA: {
183*0Sstevel@tonic-gate 		struct termio *cb;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 		if (miocpullup(mp, sizeof (struct termio)) != 0) {
186*0Sstevel@tonic-gate 			*errorp = -1;
187*0Sstevel@tonic-gate 			break;
188*0Sstevel@tonic-gate 		}
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 		/*
191*0Sstevel@tonic-gate 		 * The only information we look at are the iflag word
192*0Sstevel@tonic-gate 		 * and the cflag word.  Don't touch the unset portions.
193*0Sstevel@tonic-gate 		 */
194*0Sstevel@tonic-gate 		cb = (struct termio *)mp->b_cont->b_rptr;
195*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
196*0Sstevel@tonic-gate 		tc->t_iflag = (tc->t_iflag & 0xffff0000 | cb->c_iflag);
197*0Sstevel@tonic-gate 		tc->t_cflag = (tc->t_cflag & 0xffff0000 | cb->c_cflag);
198*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
199*0Sstevel@tonic-gate 		break;
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	case TIOCSWINSZ: {
203*0Sstevel@tonic-gate 		struct winsize *ws;
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 		if (miocpullup(mp, sizeof (struct winsize)) != 0) {
206*0Sstevel@tonic-gate 			*errorp = -1;
207*0Sstevel@tonic-gate 			break;
208*0Sstevel@tonic-gate 		}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 		/*
211*0Sstevel@tonic-gate 		 * If the window size changed, send a SIGWINCH.
212*0Sstevel@tonic-gate 		 */
213*0Sstevel@tonic-gate 		ws = (struct winsize *)mp->b_cont->b_rptr;
214*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
215*0Sstevel@tonic-gate 		if (bcmp(&tc->t_size, ws, sizeof (struct winsize)) != 0) {
216*0Sstevel@tonic-gate 			tc->t_size = *ws;
217*0Sstevel@tonic-gate 			mutex_exit(&tc->t_excl);
218*0Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_PCSIG, SIGWINCH);
219*0Sstevel@tonic-gate 		} else
220*0Sstevel@tonic-gate 			mutex_exit(&tc->t_excl);
221*0Sstevel@tonic-gate 		break;
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	/*
225*0Sstevel@tonic-gate 	 * Prevent more opens.
226*0Sstevel@tonic-gate 	 */
227*0Sstevel@tonic-gate 	case TIOCEXCL:
228*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
229*0Sstevel@tonic-gate 		tc->t_flags |= TS_XCLUDE;
230*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
231*0Sstevel@tonic-gate 		break;
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	/*
234*0Sstevel@tonic-gate 	 * Permit more opens.
235*0Sstevel@tonic-gate 	 */
236*0Sstevel@tonic-gate 	case TIOCNXCL:
237*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
238*0Sstevel@tonic-gate 		tc->t_flags &= ~TS_XCLUDE;
239*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
240*0Sstevel@tonic-gate 		break;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/*
243*0Sstevel@tonic-gate 	 * Set or clear the "soft carrier" flag.
244*0Sstevel@tonic-gate 	 */
245*0Sstevel@tonic-gate 	case TIOCSSOFTCAR:
246*0Sstevel@tonic-gate 		if (miocpullup(mp, sizeof (int)) != 0) {
247*0Sstevel@tonic-gate 			*errorp = -1;
248*0Sstevel@tonic-gate 			break;
249*0Sstevel@tonic-gate 		}
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
252*0Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr)
253*0Sstevel@tonic-gate 			tc->t_flags |= TS_SOFTCAR;
254*0Sstevel@tonic-gate 		else
255*0Sstevel@tonic-gate 			tc->t_flags &= ~TS_SOFTCAR;
256*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
257*0Sstevel@tonic-gate 		break;
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	/*
260*0Sstevel@tonic-gate 	 * The permission checking has already been done at the stream
261*0Sstevel@tonic-gate 	 * head, since it has to be done in the context of the process
262*0Sstevel@tonic-gate 	 * doing the call.
263*0Sstevel@tonic-gate 	 */
264*0Sstevel@tonic-gate 	case TIOCSTI: {
265*0Sstevel@tonic-gate 		mblk_t *bp;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 		if (miocpullup(mp, sizeof (char)) != 0) {
268*0Sstevel@tonic-gate 			*errorp = -1;
269*0Sstevel@tonic-gate 			break;
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 		/*
273*0Sstevel@tonic-gate 		 * Simulate typing of a character at the terminal.
274*0Sstevel@tonic-gate 		 */
275*0Sstevel@tonic-gate 		if ((bp = allocb(1, BPRI_MED)) != NULL) {
276*0Sstevel@tonic-gate 			if (!canput(tc->t_readq->q_next))
277*0Sstevel@tonic-gate 				freemsg(bp);
278*0Sstevel@tonic-gate 			else {
279*0Sstevel@tonic-gate 				*bp->b_wptr++ = *mp->b_cont->b_rptr;
280*0Sstevel@tonic-gate 				putnext(tc->t_readq, bp);
281*0Sstevel@tonic-gate 			}
282*0Sstevel@tonic-gate 		}
283*0Sstevel@tonic-gate 		break;
284*0Sstevel@tonic-gate 	}
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	/*
288*0Sstevel@tonic-gate 	 * Turn the ioctl message into an ioctl ACK message.
289*0Sstevel@tonic-gate 	 */
290*0Sstevel@tonic-gate 	iocp->ioc_count = 0;	/* no data returned unless we say so */
291*0Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	case TCSETSF:
296*0Sstevel@tonic-gate 	case TCSETSW:
297*0Sstevel@tonic-gate 	case TCSETS:
298*0Sstevel@tonic-gate 	case TCSETAF:
299*0Sstevel@tonic-gate 	case TCSETAW:
300*0Sstevel@tonic-gate 	case TCSETA:
301*0Sstevel@tonic-gate 	case TIOCSWINSZ:
302*0Sstevel@tonic-gate 	case TIOCEXCL:
303*0Sstevel@tonic-gate 	case TIOCNXCL:
304*0Sstevel@tonic-gate 	case TIOCSSOFTCAR:
305*0Sstevel@tonic-gate 	case TIOCSTI:
306*0Sstevel@tonic-gate 		/*
307*0Sstevel@tonic-gate 		 * We've done all the important work on these already;
308*0Sstevel@tonic-gate 		 * just reply with an ACK.
309*0Sstevel@tonic-gate 		 */
310*0Sstevel@tonic-gate 		break;
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	case TCGETS: {
313*0Sstevel@tonic-gate 		struct termios *cb;
314*0Sstevel@tonic-gate 		mblk_t *datap;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		if ((datap = allocb(sizeof (struct termios),
317*0Sstevel@tonic-gate 		    BPRI_HI)) == NULL) {
318*0Sstevel@tonic-gate 			ioctlrespsize = sizeof (struct termios);
319*0Sstevel@tonic-gate 			goto allocfailure;
320*0Sstevel@tonic-gate 		}
321*0Sstevel@tonic-gate 		cb = (struct termios *)datap->b_wptr;
322*0Sstevel@tonic-gate 		/*
323*0Sstevel@tonic-gate 		 * The only information we supply is the cflag word.
324*0Sstevel@tonic-gate 		 * Our copy of the iflag word is just that, a copy.
325*0Sstevel@tonic-gate 		 */
326*0Sstevel@tonic-gate 		bzero(cb, sizeof (struct termios));
327*0Sstevel@tonic-gate 		cb->c_cflag = tc->t_cflag;
328*0Sstevel@tonic-gate 		datap->b_wptr += sizeof (struct termios);
329*0Sstevel@tonic-gate 		iocp->ioc_count = sizeof (struct termios);
330*0Sstevel@tonic-gate 		if (mp->b_cont != NULL)
331*0Sstevel@tonic-gate 			freemsg(mp->b_cont);
332*0Sstevel@tonic-gate 		mp->b_cont = datap;
333*0Sstevel@tonic-gate 		break;
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	case TCGETA: {
337*0Sstevel@tonic-gate 		struct termio *cb;
338*0Sstevel@tonic-gate 		mblk_t *datap;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 		if ((datap = allocb(sizeof (struct termio), BPRI_HI)) == NULL) {
341*0Sstevel@tonic-gate 			ioctlrespsize = sizeof (struct termio);
342*0Sstevel@tonic-gate 			goto allocfailure;
343*0Sstevel@tonic-gate 		}
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 		cb = (struct termio *)datap->b_wptr;
346*0Sstevel@tonic-gate 		/*
347*0Sstevel@tonic-gate 		 * The only information we supply is the cflag word.
348*0Sstevel@tonic-gate 		 * Our copy of the iflag word is just that, a copy.
349*0Sstevel@tonic-gate 		 */
350*0Sstevel@tonic-gate 		bzero(cb, sizeof (struct termio));
351*0Sstevel@tonic-gate 		cb->c_cflag = tc->t_cflag;
352*0Sstevel@tonic-gate 		datap->b_wptr += sizeof (struct termio);
353*0Sstevel@tonic-gate 		iocp->ioc_count = sizeof (struct termio);
354*0Sstevel@tonic-gate 		if (mp->b_cont != NULL)
355*0Sstevel@tonic-gate 			freemsg(mp->b_cont);
356*0Sstevel@tonic-gate 		mp->b_cont = datap;
357*0Sstevel@tonic-gate 		break;
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/*
361*0Sstevel@tonic-gate 	 * Get the "soft carrier" flag.
362*0Sstevel@tonic-gate 	 */
363*0Sstevel@tonic-gate 	case TIOCGSOFTCAR: {
364*0Sstevel@tonic-gate 		mblk_t *datap;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
367*0Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
368*0Sstevel@tonic-gate 			goto allocfailure;
369*0Sstevel@tonic-gate 		}
370*0Sstevel@tonic-gate 		if (tc->t_flags & TS_SOFTCAR)
371*0Sstevel@tonic-gate 			*(int *)datap->b_wptr = 1;
372*0Sstevel@tonic-gate 		else
373*0Sstevel@tonic-gate 			*(int *)datap->b_wptr = 0;
374*0Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
375*0Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
376*0Sstevel@tonic-gate 		if (mp->b_cont != NULL)
377*0Sstevel@tonic-gate 			freemsg(mp->b_cont);
378*0Sstevel@tonic-gate 		mp->b_cont = datap;
379*0Sstevel@tonic-gate 		break;
380*0Sstevel@tonic-gate 	}
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	case TIOCGWINSZ: {
383*0Sstevel@tonic-gate 		mblk_t *datap;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 		if ((datap = allocb(sizeof (struct winsize),
386*0Sstevel@tonic-gate 		    BPRI_HI)) == NULL) {
387*0Sstevel@tonic-gate 			ioctlrespsize = sizeof (struct winsize);
388*0Sstevel@tonic-gate 			goto allocfailure;
389*0Sstevel@tonic-gate 		}
390*0Sstevel@tonic-gate 		/*
391*0Sstevel@tonic-gate 		 * Return the current size.
392*0Sstevel@tonic-gate 		 */
393*0Sstevel@tonic-gate 		*(struct winsize *)datap->b_wptr = tc->t_size;
394*0Sstevel@tonic-gate 		datap->b_wptr += sizeof (struct winsize);
395*0Sstevel@tonic-gate 		iocp->ioc_count = sizeof (struct winsize);
396*0Sstevel@tonic-gate 		if (mp->b_cont != NULL)
397*0Sstevel@tonic-gate 			freemsg(mp->b_cont);
398*0Sstevel@tonic-gate 		mp->b_cont = datap;
399*0Sstevel@tonic-gate 		break;
400*0Sstevel@tonic-gate 	}
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	default:
403*0Sstevel@tonic-gate 		*errorp = -1;	/* we don't understand it, maybe they do */
404*0Sstevel@tonic-gate 		break;
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 	return (0);
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate allocfailure:
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	mutex_enter(&tc->t_excl);
411*0Sstevel@tonic-gate 	tmp = tc->t_iocpending;
412*0Sstevel@tonic-gate 	tc->t_iocpending = mp;	/* hold this ioctl */
413*0Sstevel@tonic-gate 	mutex_exit(&tc->t_excl);
414*0Sstevel@tonic-gate 	/*
415*0Sstevel@tonic-gate 	 * We needed to allocate something to handle this "ioctl", but
416*0Sstevel@tonic-gate 	 * couldn't; save this "ioctl" and arrange to get called back when
417*0Sstevel@tonic-gate 	 * it's more likely that we can get what we need.
418*0Sstevel@tonic-gate 	 * If there's already one being saved, throw it out, since it
419*0Sstevel@tonic-gate 	 * must have timed out.
420*0Sstevel@tonic-gate 	 */
421*0Sstevel@tonic-gate 	if (tmp != NULL)
422*0Sstevel@tonic-gate 		freemsg(tmp);
423*0Sstevel@tonic-gate 	return (ioctlrespsize);
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate #define	NFIELDS	20	/* 16 control characters + 4 sets of modes */
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate /*
429*0Sstevel@tonic-gate  * Init routine run from main at boot time.
430*0Sstevel@tonic-gate  * Creates a property in the "options" node that is
431*0Sstevel@tonic-gate  * the default set of termios modes upon driver open.
432*0Sstevel@tonic-gate  * If the property already existed, then it was
433*0Sstevel@tonic-gate  * defined in the options.conf file.  In this case we
434*0Sstevel@tonic-gate  * need to convert this string (stty -g style) to an
435*0Sstevel@tonic-gate  * actual termios structure and store the new property
436*0Sstevel@tonic-gate  * value.
437*0Sstevel@tonic-gate  */
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate void
ttyinit()440*0Sstevel@tonic-gate ttyinit()
441*0Sstevel@tonic-gate {
442*0Sstevel@tonic-gate 	dev_info_t *dip;
443*0Sstevel@tonic-gate 	struct termios new_termios;
444*0Sstevel@tonic-gate 	struct termios *tp;
445*0Sstevel@tonic-gate 	char *property = "ttymodes";
446*0Sstevel@tonic-gate 	char **modesp, *cp;
447*0Sstevel@tonic-gate 	int i;
448*0Sstevel@tonic-gate 	uint_t val;
449*0Sstevel@tonic-gate 	uint_t len;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	/*
453*0Sstevel@tonic-gate 	 * If the termios defaults were NOT set up by the
454*0Sstevel@tonic-gate 	 * user via the options.conf file, create it using the
455*0Sstevel@tonic-gate 	 * "sane" set of termios modes.
456*0Sstevel@tonic-gate 	 * Note that if the property had been created via the
457*0Sstevel@tonic-gate 	 * options.conf file, it would have been created as
458*0Sstevel@tonic-gate 	 * a string property.  Since we would like to store
459*0Sstevel@tonic-gate 	 * a structure (termios) in this property, we need
460*0Sstevel@tonic-gate 	 * to change the property type to byte array.
461*0Sstevel@tonic-gate 	 */
462*0Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(), 0,
463*0Sstevel@tonic-gate 	    property, (char ***)&modesp, &len) != DDI_PROP_SUCCESS) {
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 		if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) {
466*0Sstevel@tonic-gate 			cmn_err(CE_PANIC,
467*0Sstevel@tonic-gate 			    "ttyinit: Can't find options node!\n");
468*0Sstevel@tonic-gate 		}
469*0Sstevel@tonic-gate 		/*
470*0Sstevel@tonic-gate 		 * Create the property.
471*0Sstevel@tonic-gate 		 */
472*0Sstevel@tonic-gate 		if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
473*0Sstevel@tonic-gate 		    property, (uchar_t *)&default_termios,
474*0Sstevel@tonic-gate 		    sizeof (struct termios)) != DDI_PROP_SUCCESS) {
475*0Sstevel@tonic-gate 			cmn_err(CE_PANIC, "ttyinit: can't create %s property\n",
476*0Sstevel@tonic-gate 			    property);
477*0Sstevel@tonic-gate 		}
478*0Sstevel@tonic-gate 		return;
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	/*
482*0Sstevel@tonic-gate 	 * This property was already set in the options.conf
483*0Sstevel@tonic-gate 	 * file.  We must convert it from a "stty -g" string
484*0Sstevel@tonic-gate 	 * to an actual termios structure.
485*0Sstevel@tonic-gate 	 */
486*0Sstevel@tonic-gate 	bzero(&new_termios, sizeof (struct termios));
487*0Sstevel@tonic-gate 	tp = &new_termios;
488*0Sstevel@tonic-gate 	cp = *modesp;
489*0Sstevel@tonic-gate 	for (i = 0; i < NFIELDS; i++) {
490*0Sstevel@tonic-gate 		/*
491*0Sstevel@tonic-gate 		 * Check for bad field/string.
492*0Sstevel@tonic-gate 		 */
493*0Sstevel@tonic-gate 		if (termioval(&cp, &val, *modesp+strlen(*modesp)) == -1) {
494*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
495*0Sstevel@tonic-gate 			    "ttyinit: property '%s' %s\n", property,
496*0Sstevel@tonic-gate 			    "set incorrectly, using sane value");
497*0Sstevel@tonic-gate 			tp = &default_termios;
498*0Sstevel@tonic-gate 			break;
499*0Sstevel@tonic-gate 		}
500*0Sstevel@tonic-gate 		switch (i) {
501*0Sstevel@tonic-gate 		case 0:
502*0Sstevel@tonic-gate 			new_termios.c_iflag = (tcflag_t)val;
503*0Sstevel@tonic-gate 			break;
504*0Sstevel@tonic-gate 		case 1:
505*0Sstevel@tonic-gate 			new_termios.c_oflag = (tcflag_t)val;
506*0Sstevel@tonic-gate 			break;
507*0Sstevel@tonic-gate 		case 2:
508*0Sstevel@tonic-gate 			new_termios.c_cflag = (tcflag_t)val;
509*0Sstevel@tonic-gate 			break;
510*0Sstevel@tonic-gate 		case 3:
511*0Sstevel@tonic-gate 			new_termios.c_lflag = (tcflag_t)val;
512*0Sstevel@tonic-gate 			break;
513*0Sstevel@tonic-gate 		default:
514*0Sstevel@tonic-gate 			new_termios.c_cc[i - 4] = (cc_t)val;
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 	if ((dip = ddi_find_devinfo("options", -1, 0)) == NULL) {
518*0Sstevel@tonic-gate 		cmn_err(CE_PANIC, "ttyinit: Can't find options node!\n");
519*0Sstevel@tonic-gate 	}
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	/*
522*0Sstevel@tonic-gate 	 * We need to create ttymode property as a byte array
523*0Sstevel@tonic-gate 	 * since it will be interpreted as a termios struct.
524*0Sstevel@tonic-gate 	 * The property was created as a string by default.
525*0Sstevel@tonic-gate 	 * So remove the old property and add the new one -
526*0Sstevel@tonic-gate 	 * otherwise we end up with two ttymodes properties.
527*0Sstevel@tonic-gate 	 */
528*0Sstevel@tonic-gate 	if (e_ddi_prop_remove(DDI_DEV_T_NONE, dip, property)
529*0Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
530*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "ttyinit: cannot remove '%s' property\n",
531*0Sstevel@tonic-gate 		    property);
532*0Sstevel@tonic-gate 	}
533*0Sstevel@tonic-gate 	/*
534*0Sstevel@tonic-gate 	 * Store the new defaults.  Since, this property was
535*0Sstevel@tonic-gate 	 * autoconfig'ed, we must use e_ddi_prop_update_byte_array().
536*0Sstevel@tonic-gate 	 */
537*0Sstevel@tonic-gate 	if (e_ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip, property,
538*0Sstevel@tonic-gate 	    (uchar_t *)tp, sizeof (struct termios)) != DDI_PROP_SUCCESS) {
539*0Sstevel@tonic-gate 		cmn_err(CE_PANIC, "ttyinit: cannot modify '%s' property\n",
540*0Sstevel@tonic-gate 		    property);
541*0Sstevel@tonic-gate 	}
542*0Sstevel@tonic-gate 	ddi_prop_free(modesp);
543*0Sstevel@tonic-gate }
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate /*
546*0Sstevel@tonic-gate  * Convert hex string representation of termios field
547*0Sstevel@tonic-gate  * to a uint_t.  Increments string pointer to the next
548*0Sstevel@tonic-gate  * field, and assigns value. Returns -1 if no more fields
549*0Sstevel@tonic-gate  * or an error.
550*0Sstevel@tonic-gate  */
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate static int
termioval(char ** sp,uint_t * valp,char * ep)553*0Sstevel@tonic-gate termioval(char **sp, uint_t *valp, char *ep)
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate 	char *s = *sp;
556*0Sstevel@tonic-gate 	uint_t digit;
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	if (s == 0)
559*0Sstevel@tonic-gate 		return (-1);
560*0Sstevel@tonic-gate 	*valp = 0;
561*0Sstevel@tonic-gate 	while (s < ep) {
562*0Sstevel@tonic-gate 		if (*s >= '0' && *s <= '9')
563*0Sstevel@tonic-gate 			digit = *s++ - '0';
564*0Sstevel@tonic-gate 		else if (*s >= 'a' && *s <= 'f')
565*0Sstevel@tonic-gate 			digit = *s++ - 'a' + 10;
566*0Sstevel@tonic-gate 		else if (*s >= 'A' && *s <= 'F')
567*0Sstevel@tonic-gate 			digit = *s++ - 'A' + 10;
568*0Sstevel@tonic-gate 		else if (*s == ':' || *s == '\0')
569*0Sstevel@tonic-gate 			break;
570*0Sstevel@tonic-gate 		else
571*0Sstevel@tonic-gate 			return (-1);
572*0Sstevel@tonic-gate 		*valp = (*valp * 16) + digit;
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 	/*
575*0Sstevel@tonic-gate 	 * Null string or empty field.
576*0Sstevel@tonic-gate 	 */
577*0Sstevel@tonic-gate 	if (s == *sp)
578*0Sstevel@tonic-gate 		return (-1);
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	if (s < ep && *s == ':')
581*0Sstevel@tonic-gate 		s++;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	*sp = s;
584*0Sstevel@tonic-gate 	return (0);
585*0Sstevel@tonic-gate }
586