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 /*
13*0Sstevel@tonic-gate  * PTY - Stream "pseudo-tty" device.
14*0Sstevel@tonic-gate  * This is the "slave" side.
15*0Sstevel@tonic-gate  */
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
18*0Sstevel@tonic-gate 
19*0Sstevel@tonic-gate #include <sys/param.h>
20*0Sstevel@tonic-gate #include <sys/systm.h>
21*0Sstevel@tonic-gate #include <sys/filio.h>
22*0Sstevel@tonic-gate #include <sys/ioccom.h>
23*0Sstevel@tonic-gate #include <sys/termios.h>
24*0Sstevel@tonic-gate #include <sys/termio.h>
25*0Sstevel@tonic-gate #include <sys/ttold.h>
26*0Sstevel@tonic-gate #include <sys/stropts.h>
27*0Sstevel@tonic-gate #include <sys/stream.h>
28*0Sstevel@tonic-gate #include <sys/strsun.h>
29*0Sstevel@tonic-gate #include <sys/tty.h>
30*0Sstevel@tonic-gate #include <sys/user.h>
31*0Sstevel@tonic-gate #include <sys/conf.h>
32*0Sstevel@tonic-gate #include <sys/file.h>
33*0Sstevel@tonic-gate #include <sys/vnode.h>	/* 1/0 on the vomit meter */
34*0Sstevel@tonic-gate #include <sys/proc.h>
35*0Sstevel@tonic-gate #include <sys/uio.h>
36*0Sstevel@tonic-gate #include <sys/errno.h>
37*0Sstevel@tonic-gate #include <sys/strsubr.h>
38*0Sstevel@tonic-gate #include <sys/poll.h>
39*0Sstevel@tonic-gate #include <sys/sysmacros.h>
40*0Sstevel@tonic-gate #include <sys/debug.h>
41*0Sstevel@tonic-gate #include <sys/procset.h>
42*0Sstevel@tonic-gate #include <sys/cred.h>
43*0Sstevel@tonic-gate #include <sys/ptyvar.h>
44*0Sstevel@tonic-gate #include <sys/suntty.h>
45*0Sstevel@tonic-gate #include <sys/stat.h>
46*0Sstevel@tonic-gate #include <sys/policy.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include <sys/conf.h>
49*0Sstevel@tonic-gate #include <sys/ddi.h>
50*0Sstevel@tonic-gate #include <sys/sunddi.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate extern void gsignal(int pid, int sig);
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate extern	int npty;	/* number of pseudo-ttys configured in */
55*0Sstevel@tonic-gate extern struct pty *pty_softc;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate extern struct pollhead	ptcph;	/* poll head for ptcpoll() use */
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #define	IFLAGS	(CS7|CREAD|PARENB)
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate /*
63*0Sstevel@tonic-gate  * Most of these should be "void", but the people who defined the "streams"
64*0Sstevel@tonic-gate  * data structure for S5 didn't understand data types.
65*0Sstevel@tonic-gate  */
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate /*
68*0Sstevel@tonic-gate  * Slave side.  This is a streams device.
69*0Sstevel@tonic-gate  */
70*0Sstevel@tonic-gate static int ptslopen(queue_t *, dev_t *, int flag, int, cred_t *);
71*0Sstevel@tonic-gate static int ptslclose(queue_t *, int, cred_t *);
72*0Sstevel@tonic-gate static int ptslrserv(queue_t *);
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * To save instructions, since STREAMS ignores the return value
76*0Sstevel@tonic-gate  * from this function, it is defined as void here. Kind of icky, but...
77*0Sstevel@tonic-gate  */
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate static void ptslwput(queue_t *q, mblk_t *mp);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static struct module_info ptslm_info = {
82*0Sstevel@tonic-gate 	0,
83*0Sstevel@tonic-gate 	"ptys",
84*0Sstevel@tonic-gate 	0,
85*0Sstevel@tonic-gate 	INFPSZ,
86*0Sstevel@tonic-gate 	2048,
87*0Sstevel@tonic-gate 	200
88*0Sstevel@tonic-gate };
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate static struct qinit ptslrinit = {
91*0Sstevel@tonic-gate 	putq,
92*0Sstevel@tonic-gate 	ptslrserv,
93*0Sstevel@tonic-gate 	ptslopen,
94*0Sstevel@tonic-gate 	ptslclose,
95*0Sstevel@tonic-gate 	NULL,
96*0Sstevel@tonic-gate 	&ptslm_info,
97*0Sstevel@tonic-gate 	NULL
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate static struct qinit ptslwinit = {
101*0Sstevel@tonic-gate 	(int (*)())ptslwput,
102*0Sstevel@tonic-gate 	NULL,
103*0Sstevel@tonic-gate 	NULL,
104*0Sstevel@tonic-gate 	NULL,
105*0Sstevel@tonic-gate 	NULL,
106*0Sstevel@tonic-gate 	&ptslm_info,
107*0Sstevel@tonic-gate 	NULL
108*0Sstevel@tonic-gate };
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate struct	streamtab ptysinfo = {
111*0Sstevel@tonic-gate 	&ptslrinit,
112*0Sstevel@tonic-gate 	&ptslwinit,
113*0Sstevel@tonic-gate 	NULL,
114*0Sstevel@tonic-gate 	NULL
115*0Sstevel@tonic-gate };
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate static void	ptslreioctl(void *);
118*0Sstevel@tonic-gate static void	ptslioctl(struct pty *, queue_t *, mblk_t *);
119*0Sstevel@tonic-gate static void	pt_sendstop(struct pty *);
120*0Sstevel@tonic-gate static void	ptcpollwakeup(struct pty *, int);
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate static int ptsl_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
124*0Sstevel@tonic-gate static int ptsl_attach(dev_info_t *, ddi_attach_cmd_t);
125*0Sstevel@tonic-gate static dev_info_t *ptsl_dip;	/* for dev-to-dip conversions */
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(ptsl_ops, nulldev, nulldev,
128*0Sstevel@tonic-gate     ptsl_attach, nodev, nodev, ptsl_info, D_MP, &ptysinfo);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate #include <sys/types.h>
131*0Sstevel@tonic-gate #include <sys/conf.h>
132*0Sstevel@tonic-gate #include <sys/param.h>
133*0Sstevel@tonic-gate #include <sys/systm.h>
134*0Sstevel@tonic-gate #include <sys/errno.h>
135*0Sstevel@tonic-gate #include <sys/modctl.h>
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate char _depends_on[] = "drv/ptc";
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate /*
140*0Sstevel@tonic-gate  * Module linkage information for the kernel.
141*0Sstevel@tonic-gate  */
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate static struct modldrv modldrv = {
144*0Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
145*0Sstevel@tonic-gate 	"tty pseudo driver slave 'ptsl' %I%",
146*0Sstevel@tonic-gate 	&ptsl_ops,	/* driver ops */
147*0Sstevel@tonic-gate };
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
150*0Sstevel@tonic-gate 	MODREV_1,
151*0Sstevel@tonic-gate 	&modldrv,
152*0Sstevel@tonic-gate 	NULL
153*0Sstevel@tonic-gate };
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate int
156*0Sstevel@tonic-gate _init(void)
157*0Sstevel@tonic-gate {
158*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
159*0Sstevel@tonic-gate }
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate int
162*0Sstevel@tonic-gate _fini(void)
163*0Sstevel@tonic-gate {
164*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate int
168*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
169*0Sstevel@tonic-gate {
170*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate static char	*tty_banks = PTY_BANKS;
174*0Sstevel@tonic-gate static char	*tty_digits = PTY_DIGITS;
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate /* ARGSUSED */
177*0Sstevel@tonic-gate static int
178*0Sstevel@tonic-gate ptsl_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
179*0Sstevel@tonic-gate {
180*0Sstevel@tonic-gate 	char	name[8];
181*0Sstevel@tonic-gate 	int	tty_num;
182*0Sstevel@tonic-gate 	char	*tty_digit = tty_digits;
183*0Sstevel@tonic-gate 	char	*tty_bank = tty_banks;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	for (tty_num = 0; tty_num < npty; tty_num++) {
186*0Sstevel@tonic-gate 		(void) sprintf(name, "tty%c%c", *tty_bank, *tty_digit);
187*0Sstevel@tonic-gate 		if (ddi_create_minor_node(devi, name, S_IFCHR,
188*0Sstevel@tonic-gate 			tty_num, DDI_PSEUDO, NULL) == DDI_FAILURE) {
189*0Sstevel@tonic-gate 			ddi_remove_minor_node(devi, NULL);
190*0Sstevel@tonic-gate 			return (-1);
191*0Sstevel@tonic-gate 		}
192*0Sstevel@tonic-gate 		if (*(++tty_digit) == '\0') {
193*0Sstevel@tonic-gate 			tty_digit = tty_digits;
194*0Sstevel@tonic-gate 			if (*(++tty_bank) == '\0')
195*0Sstevel@tonic-gate 				break;
196*0Sstevel@tonic-gate 		}
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 	ptsl_dip = devi;
199*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
200*0Sstevel@tonic-gate }
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate /* ARGSUSED */
203*0Sstevel@tonic-gate static int
204*0Sstevel@tonic-gate ptsl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
205*0Sstevel@tonic-gate     void **result)
206*0Sstevel@tonic-gate {
207*0Sstevel@tonic-gate 	int error;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	switch (infocmd) {
210*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
211*0Sstevel@tonic-gate 		if (ptsl_dip == NULL) {
212*0Sstevel@tonic-gate 			error = DDI_FAILURE;
213*0Sstevel@tonic-gate 		} else {
214*0Sstevel@tonic-gate 			*result = (void *)ptsl_dip;
215*0Sstevel@tonic-gate 			error = DDI_SUCCESS;
216*0Sstevel@tonic-gate 		}
217*0Sstevel@tonic-gate 		break;
218*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
219*0Sstevel@tonic-gate 		*result = (void *)0;
220*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
221*0Sstevel@tonic-gate 		break;
222*0Sstevel@tonic-gate 	default:
223*0Sstevel@tonic-gate 		error = DDI_FAILURE;
224*0Sstevel@tonic-gate 	}
225*0Sstevel@tonic-gate 	return (error);
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate  * Open the slave side of a pty.
231*0Sstevel@tonic-gate  */
232*0Sstevel@tonic-gate /*ARGSUSED*/
233*0Sstevel@tonic-gate static int
234*0Sstevel@tonic-gate ptslopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *cred)
235*0Sstevel@tonic-gate {
236*0Sstevel@tonic-gate 	minor_t unit;
237*0Sstevel@tonic-gate 	dev_t dev = *devp;
238*0Sstevel@tonic-gate 	struct pty *pty;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	unit = getminor(dev);
241*0Sstevel@tonic-gate 	if (unit >= npty)
242*0Sstevel@tonic-gate 		return (ENXIO);
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	pty = &pty_softc[unit];
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
247*0Sstevel@tonic-gate 	/*
248*0Sstevel@tonic-gate 	 * Block waiting for controller to open, unless this is a no-delay
249*0Sstevel@tonic-gate 	 * open.
250*0Sstevel@tonic-gate 	 */
251*0Sstevel@tonic-gate again:
252*0Sstevel@tonic-gate 	if (pty->pt_ttycommon.t_writeq == NULL) {
253*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_iflag = 0;
254*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_cflag = (B38400 << IBSHIFT)|B38400|IFLAGS;
255*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_iocpending = NULL;
256*0Sstevel@tonic-gate 		pty->pt_wbufcid = 0;
257*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_row = 0;
258*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_col = 0;
259*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_xpixel = 0;
260*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_size.ws_ypixel = 0;
261*0Sstevel@tonic-gate 	} else if ((pty->pt_ttycommon.t_flags & TS_XCLUDE) &&
262*0Sstevel@tonic-gate 	    secpolicy_excl_open(cred) != 0) {
263*0Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
264*0Sstevel@tonic-gate 		return (EBUSY);
265*0Sstevel@tonic-gate 	}
266*0Sstevel@tonic-gate 	if (!(flag & (FNONBLOCK|FNDELAY)) &&
267*0Sstevel@tonic-gate 	    !(pty->pt_ttycommon.t_cflag & CLOCAL)) {
268*0Sstevel@tonic-gate 		if (!(pty->pt_flags & PF_CARR_ON)) {
269*0Sstevel@tonic-gate 			pty->pt_flags |= PF_WOPEN;
270*0Sstevel@tonic-gate 			if (!cv_wait_sig(&pty->pt_cv_flags, &pty->ptc_lock)) {
271*0Sstevel@tonic-gate 				pty->pt_flags &= ~PF_WOPEN;
272*0Sstevel@tonic-gate 				mutex_exit(&pty->ptc_lock);
273*0Sstevel@tonic-gate 				return (EINTR);
274*0Sstevel@tonic-gate 			}
275*0Sstevel@tonic-gate 			goto again;
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	/*
280*0Sstevel@tonic-gate 	 * queue has already been setup with a pointer to
281*0Sstevel@tonic-gate 	 * the stream head that is being referenced
282*0Sstevel@tonic-gate 	 */
283*0Sstevel@tonic-gate 	pty->pt_vnode = strq2vp(q);
284*0Sstevel@tonic-gate 	VN_RELE(pty->pt_vnode);
285*0Sstevel@tonic-gate 	pty->pt_sdev = dev;
286*0Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = pty;
287*0Sstevel@tonic-gate 	pty->pt_flags &= ~PF_SLAVEGONE;
288*0Sstevel@tonic-gate 	pty->pt_ttycommon.t_readq = pty->pt_ttycommon.t_writeq = NULL;
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	/*
291*0Sstevel@tonic-gate 	 * Slave is ready to accept messages but master still can't send
292*0Sstevel@tonic-gate 	 * messages to the slave queue since it is not plumbed
293*0Sstevel@tonic-gate 	 * yet. So do qprocson() and finish slave initialization.
294*0Sstevel@tonic-gate 	 */
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	qprocson(q);
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	/*
301*0Sstevel@tonic-gate 	 * Now it is safe to send messages to q, so wakeup master possibly
302*0Sstevel@tonic-gate 	 * waiting for slave queue to finish open.
303*0Sstevel@tonic-gate 	 */
304*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
305*0Sstevel@tonic-gate 	pty->pt_ttycommon.t_readq = q;
306*0Sstevel@tonic-gate 	pty->pt_ttycommon.t_writeq = WR(q);
307*0Sstevel@tonic-gate 	/* tell master device that slave is ready for writing */
308*0Sstevel@tonic-gate 	if (pty->pt_flags & PF_CARR_ON)
309*0Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_readq);
310*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	return (0);
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate static int
316*0Sstevel@tonic-gate ptslclose(queue_t *q, int flag, cred_t *cred)
317*0Sstevel@tonic-gate {
318*0Sstevel@tonic-gate 	struct pty *pty;
319*0Sstevel@tonic-gate 	bufcall_id_t pt_wbufcid = 0;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate #ifdef lint
322*0Sstevel@tonic-gate 	flag = flag;
323*0Sstevel@tonic-gate 	cred = cred;
324*0Sstevel@tonic-gate #endif
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if ((pty = (struct pty *)q->q_ptr) == NULL)
327*0Sstevel@tonic-gate 		return (ENODEV);	/* already been closed once */
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	/*
330*0Sstevel@tonic-gate 	 * Prevent the queues from being uses by master device.
331*0Sstevel@tonic-gate 	 * This should be done before qprocsoff or writer may attempt
332*0Sstevel@tonic-gate 	 * to use the slave queue after qprocsoff removed it from the stream and
333*0Sstevel@tonic-gate 	 * before entering mutex_enter().
334*0Sstevel@tonic-gate 	 */
335*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
336*0Sstevel@tonic-gate 	pty->pt_ttycommon.t_readq = NULL;
337*0Sstevel@tonic-gate 	pty->pt_ttycommon.t_writeq = NULL;
338*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	qprocsoff(q);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	while (pty->pt_flags & PF_IOCTL) {
345*0Sstevel@tonic-gate 		pty->pt_flags |= PF_WAIT;
346*0Sstevel@tonic-gate 		cv_wait(&pty->pt_cv_flags, &pty->ptc_lock);
347*0Sstevel@tonic-gate 	}
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/*
350*0Sstevel@tonic-gate 	 * ptc_lock mutex is not dropped across
351*0Sstevel@tonic-gate 	 * the call to the routine ttycommon_close
352*0Sstevel@tonic-gate 	 */
353*0Sstevel@tonic-gate 	ttycommon_close(&pty->pt_ttycommon);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/*
356*0Sstevel@tonic-gate 	 * Cancel outstanding "bufcall" request.
357*0Sstevel@tonic-gate 	 */
358*0Sstevel@tonic-gate 	if (pty->pt_wbufcid) {
359*0Sstevel@tonic-gate 		pt_wbufcid = pty->pt_wbufcid;
360*0Sstevel@tonic-gate 		pty->pt_wbufcid = 0;
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/*
364*0Sstevel@tonic-gate 	 * Clear out all the slave-side state.
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 	pty->pt_flags &= ~(PF_WOPEN|PF_STOPPED|PF_NOSTOP);
367*0Sstevel@tonic-gate 	if (pty->pt_flags & PF_CARR_ON) {
368*0Sstevel@tonic-gate 		pty->pt_flags |= PF_SLAVEGONE;	/* let the controller know */
369*0Sstevel@tonic-gate 		ptcpollwakeup(pty, 0);	/* wake up readers/selectors */
370*0Sstevel@tonic-gate 		ptcpollwakeup(pty, FWRITE);	/* wake up writers/selectors */
371*0Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_flags);
372*0Sstevel@tonic-gate 	}
373*0Sstevel@tonic-gate 	pty->pt_vnode = NULL;
374*0Sstevel@tonic-gate 	pty->pt_sdev = 0;
375*0Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
376*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (pt_wbufcid)
379*0Sstevel@tonic-gate 		unbufcall(pt_wbufcid);
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	return (0);
382*0Sstevel@tonic-gate }
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate /*
385*0Sstevel@tonic-gate  * Put procedure for write queue.
386*0Sstevel@tonic-gate  * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;
387*0Sstevel@tonic-gate  * queue up M_DATA messages for processing by the controller "read"
388*0Sstevel@tonic-gate  * routine; discard everything else.
389*0Sstevel@tonic-gate  */
390*0Sstevel@tonic-gate static void
391*0Sstevel@tonic-gate ptslwput(queue_t *q, mblk_t *mp)
392*0Sstevel@tonic-gate {
393*0Sstevel@tonic-gate 	struct pty *pty;
394*0Sstevel@tonic-gate 	mblk_t *bp;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	pty = (struct pty *)q->q_ptr;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	case M_STOP:
403*0Sstevel@tonic-gate 		if (!(pty->pt_flags & PF_STOPPED)) {
404*0Sstevel@tonic-gate 			pty->pt_flags |= PF_STOPPED;
405*0Sstevel@tonic-gate 			pty->pt_send |= TIOCPKT_STOP;
406*0Sstevel@tonic-gate 			ptcpollwakeup(pty, 0);
407*0Sstevel@tonic-gate 		}
408*0Sstevel@tonic-gate 		freemsg(mp);
409*0Sstevel@tonic-gate 		break;
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	case M_START:
412*0Sstevel@tonic-gate 		if (pty->pt_flags & PF_STOPPED) {
413*0Sstevel@tonic-gate 			pty->pt_flags &= ~PF_STOPPED;
414*0Sstevel@tonic-gate 			pty->pt_send = TIOCPKT_START;
415*0Sstevel@tonic-gate 			ptcpollwakeup(pty, 0);
416*0Sstevel@tonic-gate 		}
417*0Sstevel@tonic-gate 		ptcpollwakeup(pty, FREAD);	/* permit controller to read */
418*0Sstevel@tonic-gate 		freemsg(mp);
419*0Sstevel@tonic-gate 		break;
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	case M_IOCTL:
422*0Sstevel@tonic-gate 		ptslioctl(pty, q, mp);
423*0Sstevel@tonic-gate 		break;
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	case M_FLUSH:
426*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
427*0Sstevel@tonic-gate 			/*
428*0Sstevel@tonic-gate 			 * Set the "flush write" flag, so that we
429*0Sstevel@tonic-gate 			 * notify the controller if they're in packet
430*0Sstevel@tonic-gate 			 * or user control mode.
431*0Sstevel@tonic-gate 			 */
432*0Sstevel@tonic-gate 			if (!(pty->pt_send & TIOCPKT_FLUSHWRITE)) {
433*0Sstevel@tonic-gate 				pty->pt_send |= TIOCPKT_FLUSHWRITE;
434*0Sstevel@tonic-gate 				ptcpollwakeup(pty, 0);
435*0Sstevel@tonic-gate 			}
436*0Sstevel@tonic-gate 			/*
437*0Sstevel@tonic-gate 			 * Flush our write queue.
438*0Sstevel@tonic-gate 			 */
439*0Sstevel@tonic-gate 			flushq(q, FLUSHDATA);	/* XXX doesn't flush M_DELAY */
440*0Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;	/* it has been flushed */
441*0Sstevel@tonic-gate 		}
442*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
443*0Sstevel@tonic-gate 			/*
444*0Sstevel@tonic-gate 			 * Set the "flush read" flag, so that we
445*0Sstevel@tonic-gate 			 * notify the controller if they're in packet
446*0Sstevel@tonic-gate 			 * mode.
447*0Sstevel@tonic-gate 			 */
448*0Sstevel@tonic-gate 			if (!(pty->pt_send & TIOCPKT_FLUSHREAD)) {
449*0Sstevel@tonic-gate 				pty->pt_send |= TIOCPKT_FLUSHREAD;
450*0Sstevel@tonic-gate 				ptcpollwakeup(pty, 0);
451*0Sstevel@tonic-gate 			}
452*0Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
453*0Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
454*0Sstevel@tonic-gate 			qreply(q, mp);	/* give the read queues a crack at it */
455*0Sstevel@tonic-gate 			return;
456*0Sstevel@tonic-gate 		} else
457*0Sstevel@tonic-gate 			freemsg(mp);
458*0Sstevel@tonic-gate 		break;
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	case M_DATA:
461*0Sstevel@tonic-gate 		/*
462*0Sstevel@tonic-gate 		 * Throw away any leading zero-length blocks, and queue it up
463*0Sstevel@tonic-gate 		 * for the controller to read.
464*0Sstevel@tonic-gate 		 */
465*0Sstevel@tonic-gate 		if (pty->pt_flags & PF_CARR_ON) {
466*0Sstevel@tonic-gate 			bp = mp;
467*0Sstevel@tonic-gate 			while ((bp->b_wptr - bp->b_rptr) == 0) {
468*0Sstevel@tonic-gate 				mp = bp->b_cont;
469*0Sstevel@tonic-gate 				freeb(bp);
470*0Sstevel@tonic-gate 				if (mp == NULL) {
471*0Sstevel@tonic-gate 					mutex_exit(&pty->ptc_lock);
472*0Sstevel@tonic-gate 					return;	/* damp squib of a message */
473*0Sstevel@tonic-gate 				}
474*0Sstevel@tonic-gate 				bp = mp;
475*0Sstevel@tonic-gate 			}
476*0Sstevel@tonic-gate 			(void) putq(q, mp);
477*0Sstevel@tonic-gate 			ptcpollwakeup(pty, FREAD);	/* soup's on! */
478*0Sstevel@tonic-gate 		} else
479*0Sstevel@tonic-gate 			freemsg(mp);	/* nobody listening */
480*0Sstevel@tonic-gate 		break;
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	case M_CTL:
483*0Sstevel@tonic-gate 		if ((*(int *)mp->b_rptr) == MC_CANONQUERY) {
484*0Sstevel@tonic-gate 			/*
485*0Sstevel@tonic-gate 			 * We're being asked whether we do canonicalization
486*0Sstevel@tonic-gate 			 * or not.  Send a reply back up indicating whether
487*0Sstevel@tonic-gate 			 * we do or not.
488*0Sstevel@tonic-gate 			 */
489*0Sstevel@tonic-gate 			(void) putctl1(RD(q), M_CTL,
490*0Sstevel@tonic-gate 			    (pty->pt_flags & PF_REMOTE) ?
491*0Sstevel@tonic-gate 				MC_NOCANON : MC_DOCANON);
492*0Sstevel@tonic-gate 		}
493*0Sstevel@tonic-gate 		freemsg(mp);
494*0Sstevel@tonic-gate 		break;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	default:
497*0Sstevel@tonic-gate 		/*
498*0Sstevel@tonic-gate 		 * "No, I don't want a subscription to Chain Store Age,
499*0Sstevel@tonic-gate 		 * thank you anyway."
500*0Sstevel@tonic-gate 		 */
501*0Sstevel@tonic-gate 		freemsg(mp);
502*0Sstevel@tonic-gate 		break;
503*0Sstevel@tonic-gate 	}
504*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
505*0Sstevel@tonic-gate }
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate /*
508*0Sstevel@tonic-gate  * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
509*0Sstevel@tonic-gate  * the buffer we need.
510*0Sstevel@tonic-gate  */
511*0Sstevel@tonic-gate static void
512*0Sstevel@tonic-gate ptslreioctl(void *arg)
513*0Sstevel@tonic-gate {
514*0Sstevel@tonic-gate 	struct pty *pty = arg;
515*0Sstevel@tonic-gate 	queue_t *q;
516*0Sstevel@tonic-gate 	mblk_t *mp;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
519*0Sstevel@tonic-gate 	/*
520*0Sstevel@tonic-gate 	 * The bufcall is no longer pending.
521*0Sstevel@tonic-gate 	 */
522*0Sstevel@tonic-gate 	if (pty->pt_wbufcid == 0) {
523*0Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
524*0Sstevel@tonic-gate 		return;
525*0Sstevel@tonic-gate 	}
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	pty->pt_wbufcid = 0;
528*0Sstevel@tonic-gate 	if ((q = pty->pt_ttycommon.t_writeq) == NULL) {
529*0Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
530*0Sstevel@tonic-gate 		return;
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 	if ((mp = pty->pt_ttycommon.t_iocpending) != NULL) {
533*0Sstevel@tonic-gate 		/* It's not pending any more. */
534*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_iocpending = NULL;
535*0Sstevel@tonic-gate 		ptslioctl(pty, q, mp);
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
538*0Sstevel@tonic-gate }
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate /*
541*0Sstevel@tonic-gate  * Process an "ioctl" message sent down to us.
542*0Sstevel@tonic-gate  * Drops pty's ptc_lock mutex and then reacquire
543*0Sstevel@tonic-gate  */
544*0Sstevel@tonic-gate static void
545*0Sstevel@tonic-gate ptslioctl(struct pty *pty, queue_t *q, mblk_t *mp)
546*0Sstevel@tonic-gate {
547*0Sstevel@tonic-gate 	struct iocblk *iocp;
548*0Sstevel@tonic-gate 	int cmd;
549*0Sstevel@tonic-gate 	size_t datasize;
550*0Sstevel@tonic-gate 	int error = 0;
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pty->ptc_lock));
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
555*0Sstevel@tonic-gate 	cmd = iocp->ioc_cmd;
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	switch (cmd) {
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	case TIOCSTI: {
560*0Sstevel@tonic-gate 		/*
561*0Sstevel@tonic-gate 		 * The permission checking has already been done at the stream
562*0Sstevel@tonic-gate 		 * head, since it has to be done in the context of the process
563*0Sstevel@tonic-gate 		 * doing the call.
564*0Sstevel@tonic-gate 		 */
565*0Sstevel@tonic-gate 		mblk_t *bp;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (char));
568*0Sstevel@tonic-gate 		if (error != 0)
569*0Sstevel@tonic-gate 			goto out;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 		/*
572*0Sstevel@tonic-gate 		 * Simulate typing of a character at the terminal.
573*0Sstevel@tonic-gate 		 */
574*0Sstevel@tonic-gate 		if ((bp = allocb(1, BPRI_MED)) != NULL) {
575*0Sstevel@tonic-gate 			*bp->b_wptr++ = *mp->b_cont->b_rptr;
576*0Sstevel@tonic-gate 			if (!(pty->pt_flags & PF_REMOTE)) {
577*0Sstevel@tonic-gate 				if (!canput(pty->pt_ttycommon.t_readq)) {
578*0Sstevel@tonic-gate 					mutex_exit(&pty->ptc_lock);
579*0Sstevel@tonic-gate 					ttycommon_qfull(&pty->pt_ttycommon, q);
580*0Sstevel@tonic-gate 					mutex_enter(&pty->ptc_lock);
581*0Sstevel@tonic-gate 					freemsg(bp);
582*0Sstevel@tonic-gate 					error = EAGAIN;
583*0Sstevel@tonic-gate 					goto out;
584*0Sstevel@tonic-gate 				} else
585*0Sstevel@tonic-gate 					(void) putq(
586*0Sstevel@tonic-gate 					    pty->pt_ttycommon.t_readq, bp);
587*0Sstevel@tonic-gate 			} else {
588*0Sstevel@tonic-gate 				if (pty->pt_flags & PF_UCNTL) {
589*0Sstevel@tonic-gate 					/*
590*0Sstevel@tonic-gate 					 * XXX - flow control; don't overflow
591*0Sstevel@tonic-gate 					 * this "queue".
592*0Sstevel@tonic-gate 					 */
593*0Sstevel@tonic-gate 					if (pty->pt_stuffqfirst != NULL) {
594*0Sstevel@tonic-gate 						pty->pt_stuffqlast->b_next = bp;
595*0Sstevel@tonic-gate 						bp->b_prev = pty->pt_stuffqlast;
596*0Sstevel@tonic-gate 					} else {
597*0Sstevel@tonic-gate 						pty->pt_stuffqfirst = bp;
598*0Sstevel@tonic-gate 						bp->b_prev = NULL;
599*0Sstevel@tonic-gate 					}
600*0Sstevel@tonic-gate 					bp->b_next = NULL;
601*0Sstevel@tonic-gate 					pty->pt_stuffqlast = bp;
602*0Sstevel@tonic-gate 					pty->pt_stuffqlen++;
603*0Sstevel@tonic-gate 					ptcpollwakeup(pty, 0);
604*0Sstevel@tonic-gate 				}
605*0Sstevel@tonic-gate 			}
606*0Sstevel@tonic-gate 		} else {
607*0Sstevel@tonic-gate 			error = EAGAIN;
608*0Sstevel@tonic-gate 			goto out;
609*0Sstevel@tonic-gate 		}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 		/*
612*0Sstevel@tonic-gate 		 * Turn the ioctl message into an ioctl ACK message.
613*0Sstevel@tonic-gate 		 */
614*0Sstevel@tonic-gate 		iocp->ioc_count = 0;	/* no data returned */
615*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
616*0Sstevel@tonic-gate 		goto out;
617*0Sstevel@tonic-gate 	}
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	case TIOCSSIZE: {
620*0Sstevel@tonic-gate 		tty_common_t *tc = &pty->pt_ttycommon;
621*0Sstevel@tonic-gate 		struct ttysize *tp;
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct ttysize));
624*0Sstevel@tonic-gate 		if (error != 0)
625*0Sstevel@tonic-gate 			goto out;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		/*
628*0Sstevel@tonic-gate 		 * Set the window size, but don't send a SIGWINCH.
629*0Sstevel@tonic-gate 		 */
630*0Sstevel@tonic-gate 		tp = (struct ttysize *)mp->b_cont->b_rptr;
631*0Sstevel@tonic-gate 		tc->t_size.ws_row = tp->ts_lines;
632*0Sstevel@tonic-gate 		tc->t_size.ws_col = tp->ts_cols;
633*0Sstevel@tonic-gate 		tc->t_size.ws_xpixel = 0;
634*0Sstevel@tonic-gate 		tc->t_size.ws_ypixel = 0;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 		/*
637*0Sstevel@tonic-gate 		 * Send an ACK back.
638*0Sstevel@tonic-gate 		 */
639*0Sstevel@tonic-gate 		iocp->ioc_count = 0;	/* no data returned */
640*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
641*0Sstevel@tonic-gate 		goto out;
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	case TIOCGSIZE: {
645*0Sstevel@tonic-gate 		tty_common_t *tc = &pty->pt_ttycommon;
646*0Sstevel@tonic-gate 		mblk_t *datap;
647*0Sstevel@tonic-gate 		struct ttysize *tp;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 		if ((datap = allocb(sizeof (struct ttysize),
650*0Sstevel@tonic-gate 		    BPRI_HI)) == NULL) {
651*0Sstevel@tonic-gate 			if (pty->pt_wbufcid) {
652*0Sstevel@tonic-gate 				if (pty->pt_ttycommon.t_iocpending)
653*0Sstevel@tonic-gate 					freemsg(pty->pt_ttycommon.t_iocpending);
654*0Sstevel@tonic-gate 				pty->pt_ttycommon.t_iocpending = mp;
655*0Sstevel@tonic-gate 				return;
656*0Sstevel@tonic-gate 			}
657*0Sstevel@tonic-gate 			pty->pt_wbufcid = bufcall(sizeof (struct ttysize),
658*0Sstevel@tonic-gate 			    BPRI_HI, ptslreioctl, pty);
659*0Sstevel@tonic-gate 			if (pty->pt_wbufcid == 0) {
660*0Sstevel@tonic-gate 				error = ENOMEM;
661*0Sstevel@tonic-gate 				goto out;
662*0Sstevel@tonic-gate 			}
663*0Sstevel@tonic-gate 			pty->pt_ttycommon.t_iocpending = mp;
664*0Sstevel@tonic-gate 			return;
665*0Sstevel@tonic-gate 		}
666*0Sstevel@tonic-gate 		/*
667*0Sstevel@tonic-gate 		 * Return the current size.
668*0Sstevel@tonic-gate 		 */
669*0Sstevel@tonic-gate 		tp = (struct ttysize *)datap->b_wptr;
670*0Sstevel@tonic-gate 		tp->ts_lines = tc->t_size.ws_row;
671*0Sstevel@tonic-gate 		tp->ts_cols = tc->t_size.ws_col;
672*0Sstevel@tonic-gate 		datap->b_wptr += sizeof (struct ttysize);
673*0Sstevel@tonic-gate 		iocp->ioc_count = sizeof (struct ttysize);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		if (mp->b_cont != NULL)
676*0Sstevel@tonic-gate 			freemsg(mp->b_cont);
677*0Sstevel@tonic-gate 		mp->b_cont = datap;
678*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
679*0Sstevel@tonic-gate 		goto out;
680*0Sstevel@tonic-gate 	}
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	/*
683*0Sstevel@tonic-gate 	 * Imported from ttycommon_ioctl routine
684*0Sstevel@tonic-gate 	 */
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	case TCSETSF: {
687*0Sstevel@tonic-gate 		tty_common_t *tc = &pty->pt_ttycommon;
688*0Sstevel@tonic-gate 		struct termios *cb;
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct termios));
691*0Sstevel@tonic-gate 		if (error != 0)
692*0Sstevel@tonic-gate 			goto out;
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 		cb = (struct termios *)mp->b_cont->b_rptr;
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 		flushq(RD(q), FLUSHDATA);
697*0Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
698*0Sstevel@tonic-gate 		(void) putnextctl1(RD(q), M_FLUSH, FLUSHR);
699*0Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
700*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
701*0Sstevel@tonic-gate 		tc->t_iflag = cb->c_iflag;
702*0Sstevel@tonic-gate 		tc->t_cflag = cb->c_cflag;
703*0Sstevel@tonic-gate 		tc->t_stopc = cb->c_cc[VSTOP];
704*0Sstevel@tonic-gate 		tc->t_startc = cb->c_cc[VSTART];
705*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 		/*
708*0Sstevel@tonic-gate 		 * Turn the ioctl message into an ioctl ACK message.
709*0Sstevel@tonic-gate 		 */
710*0Sstevel@tonic-gate 		iocp->ioc_count = 0;	/* no data returned */
711*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
712*0Sstevel@tonic-gate 		goto ioctldone;
713*0Sstevel@tonic-gate 	}
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	case TCSETAF: {
716*0Sstevel@tonic-gate 		tty_common_t *tc = &pty->pt_ttycommon;
717*0Sstevel@tonic-gate 		struct termios *cb;
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct termios));
720*0Sstevel@tonic-gate 		if (error != 0)
721*0Sstevel@tonic-gate 			goto out;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 		cb = (struct termios *)mp->b_cont->b_rptr;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		flushq(RD(q), FLUSHDATA);
726*0Sstevel@tonic-gate 		mutex_exit(&pty->ptc_lock);
727*0Sstevel@tonic-gate 		(void) putnextctl1(RD(q), M_FLUSH, FLUSHR);
728*0Sstevel@tonic-gate 		mutex_enter(&pty->ptc_lock);
729*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
730*0Sstevel@tonic-gate 		tc->t_iflag = (tc->t_iflag & 0xffff0000 | cb->c_iflag);
731*0Sstevel@tonic-gate 		tc->t_cflag = (tc->t_cflag & 0xffff0000 | cb->c_cflag);
732*0Sstevel@tonic-gate 		mutex_exit(&tc->t_excl);
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 		/*
735*0Sstevel@tonic-gate 		 * Turn the ioctl message into an ioctl ACK message.
736*0Sstevel@tonic-gate 		 */
737*0Sstevel@tonic-gate 		iocp->ioc_count = 0;	/* no data returned */
738*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
739*0Sstevel@tonic-gate 		goto ioctldone;
740*0Sstevel@tonic-gate 	}
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 	case TIOCSWINSZ: {
743*0Sstevel@tonic-gate 		tty_common_t *tc = &pty->pt_ttycommon;
744*0Sstevel@tonic-gate 		struct winsize *ws;
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct winsize));
747*0Sstevel@tonic-gate 		if (error != 0)
748*0Sstevel@tonic-gate 			goto out;
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 		ws = (struct winsize *)mp->b_cont->b_rptr;
751*0Sstevel@tonic-gate 		/*
752*0Sstevel@tonic-gate 		 * If the window size changed, send a SIGWINCH.
753*0Sstevel@tonic-gate 		 */
754*0Sstevel@tonic-gate 		mutex_enter(&tc->t_excl);
755*0Sstevel@tonic-gate 		if (bcmp(&tc->t_size, ws, sizeof (struct winsize))) {
756*0Sstevel@tonic-gate 			tc->t_size = *ws;
757*0Sstevel@tonic-gate 			mutex_exit(&tc->t_excl);
758*0Sstevel@tonic-gate 			mutex_exit(&pty->ptc_lock);
759*0Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_PCSIG, SIGWINCH);
760*0Sstevel@tonic-gate 			mutex_enter(&pty->ptc_lock);
761*0Sstevel@tonic-gate 		} else
762*0Sstevel@tonic-gate 			mutex_exit(&tc->t_excl);
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 		/*
765*0Sstevel@tonic-gate 		 * Turn the ioctl message into an ioctl ACK message.
766*0Sstevel@tonic-gate 		 */
767*0Sstevel@tonic-gate 		iocp->ioc_count = 0;	/* no data returned */
768*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
769*0Sstevel@tonic-gate 		goto ioctldone;
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	/*
773*0Sstevel@tonic-gate 	 * If they were just trying to drain output, that's OK.
774*0Sstevel@tonic-gate 	 * If they are actually trying to send a break it's an error.
775*0Sstevel@tonic-gate 	 */
776*0Sstevel@tonic-gate 	case TCSBRK:
777*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
778*0Sstevel@tonic-gate 		if (error != 0)
779*0Sstevel@tonic-gate 			goto out;
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr != 0) {
782*0Sstevel@tonic-gate 			/*
783*0Sstevel@tonic-gate 			 * Turn the ioctl message into an ioctl ACK message.
784*0Sstevel@tonic-gate 			 */
785*0Sstevel@tonic-gate 			iocp->ioc_count = 0;	/* no data returned */
786*0Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
787*0Sstevel@tonic-gate 		} else {
788*0Sstevel@tonic-gate 			error = ENOTTY;
789*0Sstevel@tonic-gate 		}
790*0Sstevel@tonic-gate 		goto out;
791*0Sstevel@tonic-gate 	}
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	/*
794*0Sstevel@tonic-gate 	 * The only way in which "ttycommon_ioctl" can fail is if the "ioctl"
795*0Sstevel@tonic-gate 	 * requires a response containing data to be returned to the user,
796*0Sstevel@tonic-gate 	 * and no mblk could be allocated for the data.
797*0Sstevel@tonic-gate 	 * No such "ioctl" alters our state.  Thus, we always go ahead and
798*0Sstevel@tonic-gate 	 * do any state-changes the "ioctl" calls for.  If we couldn't allocate
799*0Sstevel@tonic-gate 	 * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so
800*0Sstevel@tonic-gate 	 * we just call "bufcall" to request that we be called back when we
801*0Sstevel@tonic-gate 	 * stand a better chance of allocating the data.
802*0Sstevel@tonic-gate 	 */
803*0Sstevel@tonic-gate 	if ((datasize =
804*0Sstevel@tonic-gate 	    ttycommon_ioctl(&pty->pt_ttycommon, q, mp, &error)) != 0) {
805*0Sstevel@tonic-gate 		if (pty->pt_wbufcid) {
806*0Sstevel@tonic-gate 			if (pty->pt_ttycommon.t_iocpending)
807*0Sstevel@tonic-gate 				freemsg(pty->pt_ttycommon.t_iocpending);
808*0Sstevel@tonic-gate 			pty->pt_ttycommon.t_iocpending = mp;
809*0Sstevel@tonic-gate 			return;
810*0Sstevel@tonic-gate 		}
811*0Sstevel@tonic-gate 		pty->pt_wbufcid = bufcall(datasize, BPRI_HI, ptslreioctl, pty);
812*0Sstevel@tonic-gate 		if (pty->pt_wbufcid == 0) {
813*0Sstevel@tonic-gate 			error = ENOMEM;
814*0Sstevel@tonic-gate 			goto out;
815*0Sstevel@tonic-gate 		}
816*0Sstevel@tonic-gate 		pty->pt_ttycommon.t_iocpending = mp;
817*0Sstevel@tonic-gate 		return;
818*0Sstevel@tonic-gate 	}
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate ioctldone:
821*0Sstevel@tonic-gate 	if (error == 0) {
822*0Sstevel@tonic-gate 		/*
823*0Sstevel@tonic-gate 		 * "ttycommon_ioctl" did most of the work; we just use the
824*0Sstevel@tonic-gate 		 * data it set up.
825*0Sstevel@tonic-gate 		 */
826*0Sstevel@tonic-gate 		switch (cmd) {
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 		case TCSETSF:
829*0Sstevel@tonic-gate 		case TCSETAF:
830*0Sstevel@tonic-gate 			/*
831*0Sstevel@tonic-gate 			 * Set the "flush read" flag, so that we
832*0Sstevel@tonic-gate 			 * notify the controller if they're in packet
833*0Sstevel@tonic-gate 			 * mode.
834*0Sstevel@tonic-gate 			 */
835*0Sstevel@tonic-gate 			if (!(pty->pt_send & TIOCPKT_FLUSHREAD)) {
836*0Sstevel@tonic-gate 				pty->pt_send |= TIOCPKT_FLUSHREAD;
837*0Sstevel@tonic-gate 				ptcpollwakeup(pty, 0);
838*0Sstevel@tonic-gate 			}
839*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 		case TCSETSW:
842*0Sstevel@tonic-gate 		case TCSETAW:
843*0Sstevel@tonic-gate 			cmd = TIOCSETP;	/* map backwards to old codes */
844*0Sstevel@tonic-gate 			pt_sendstop(pty);
845*0Sstevel@tonic-gate 			break;
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 		case TCSETS:
848*0Sstevel@tonic-gate 		case TCSETA:
849*0Sstevel@tonic-gate 			cmd = TIOCSETN;	/* map backwards to old codes */
850*0Sstevel@tonic-gate 			pt_sendstop(pty);
851*0Sstevel@tonic-gate 			break;
852*0Sstevel@tonic-gate 		}
853*0Sstevel@tonic-gate 	}
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	if (pty->pt_flags & PF_43UCNTL) {
856*0Sstevel@tonic-gate 		if (error < 0) {
857*0Sstevel@tonic-gate 			if ((cmd & ~0xff) == _IO('u', 0)) {
858*0Sstevel@tonic-gate 				if (cmd & 0xff) {
859*0Sstevel@tonic-gate 					pty->pt_ucntl = (uchar_t)cmd & 0xff;
860*0Sstevel@tonic-gate 					ptcpollwakeup(pty, FREAD);
861*0Sstevel@tonic-gate 				}
862*0Sstevel@tonic-gate 				error = 0; /* XXX */
863*0Sstevel@tonic-gate 				goto out;
864*0Sstevel@tonic-gate 			}
865*0Sstevel@tonic-gate 			error = ENOTTY;
866*0Sstevel@tonic-gate 		}
867*0Sstevel@tonic-gate 	} else {
868*0Sstevel@tonic-gate 		if ((pty->pt_flags & PF_UCNTL) &&
869*0Sstevel@tonic-gate 		    (cmd & (IOC_INOUT | 0xff00)) == (IOC_IN|('t'<<8)) &&
870*0Sstevel@tonic-gate 		    (cmd & 0xff)) {
871*0Sstevel@tonic-gate 			pty->pt_ucntl = (uchar_t)cmd & 0xff;
872*0Sstevel@tonic-gate 			ptcpollwakeup(pty, FREAD);
873*0Sstevel@tonic-gate 			goto out;
874*0Sstevel@tonic-gate 		}
875*0Sstevel@tonic-gate 		if (error < 0)
876*0Sstevel@tonic-gate 			error = ENOTTY;
877*0Sstevel@tonic-gate 	}
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate out:
880*0Sstevel@tonic-gate 	if (error != 0) {
881*0Sstevel@tonic-gate 		((struct iocblk *)mp->b_rptr)->ioc_error = error;
882*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
883*0Sstevel@tonic-gate 	}
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
886*0Sstevel@tonic-gate 	qreply(q, mp);
887*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
888*0Sstevel@tonic-gate }
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate /*
891*0Sstevel@tonic-gate  * Service routine for read queue.
892*0Sstevel@tonic-gate  * Just wakes the controller side up so it can write some more data
893*0Sstevel@tonic-gate  * to that queue.
894*0Sstevel@tonic-gate  */
895*0Sstevel@tonic-gate static int
896*0Sstevel@tonic-gate ptslrserv(queue_t *q)
897*0Sstevel@tonic-gate {
898*0Sstevel@tonic-gate 	struct pty *pty = (struct pty *)q->q_ptr;
899*0Sstevel@tonic-gate 	mblk_t *mp;
900*0Sstevel@tonic-gate 	mblk_t *head = NULL, *tail = NULL;
901*0Sstevel@tonic-gate 	/*
902*0Sstevel@tonic-gate 	 * Build up the link list of messages, then drop
903*0Sstevel@tonic-gate 	 * drop the lock and do putnext()
904*0Sstevel@tonic-gate 	 */
905*0Sstevel@tonic-gate 	mutex_enter(&pty->ptc_lock);
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
908*0Sstevel@tonic-gate 		if ((mp->b_datap->db_type < QPCTL) && !canputnext(q)) {
909*0Sstevel@tonic-gate 			(void) putbq(q, mp);
910*0Sstevel@tonic-gate 			break;
911*0Sstevel@tonic-gate 		}
912*0Sstevel@tonic-gate 		if (!head) {
913*0Sstevel@tonic-gate 			head = mp;
914*0Sstevel@tonic-gate 			tail = mp;
915*0Sstevel@tonic-gate 		} else {
916*0Sstevel@tonic-gate 			tail->b_next = mp;
917*0Sstevel@tonic-gate 			tail = mp;
918*0Sstevel@tonic-gate 		}
919*0Sstevel@tonic-gate 	}
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	if (q->q_count <= q->q_lowat)
922*0Sstevel@tonic-gate 		ptcpollwakeup((struct pty *)q->q_ptr, FWRITE);
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	mutex_exit(&pty->ptc_lock);
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	while (head) {
927*0Sstevel@tonic-gate 		mp = head;
928*0Sstevel@tonic-gate 		head = mp->b_next;
929*0Sstevel@tonic-gate 		mp->b_next = NULL;
930*0Sstevel@tonic-gate 		putnext(q, mp);
931*0Sstevel@tonic-gate 	}
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 	return (0);
934*0Sstevel@tonic-gate }
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate static void
937*0Sstevel@tonic-gate pt_sendstop(struct pty *pty)
938*0Sstevel@tonic-gate {
939*0Sstevel@tonic-gate 	int stop;
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pty->ptc_lock));
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 	if ((pty->pt_ttycommon.t_cflag&CBAUD) == 0) {
944*0Sstevel@tonic-gate 		if (pty->pt_flags & PF_CARR_ON) {
945*0Sstevel@tonic-gate 			/*
946*0Sstevel@tonic-gate 			 * Let the controller know, then wake up
947*0Sstevel@tonic-gate 			 * readers/selectors and writers/selectors.
948*0Sstevel@tonic-gate 			 */
949*0Sstevel@tonic-gate 			pty->pt_flags |= PF_SLAVEGONE;
950*0Sstevel@tonic-gate 			ptcpollwakeup(pty, 0);
951*0Sstevel@tonic-gate 			ptcpollwakeup(pty, FWRITE);
952*0Sstevel@tonic-gate 		}
953*0Sstevel@tonic-gate 	}
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 	stop = (pty->pt_ttycommon.t_iflag & IXON) &&
956*0Sstevel@tonic-gate 	    pty->pt_ttycommon.t_stopc == CTRL('s') &&
957*0Sstevel@tonic-gate 	    pty->pt_ttycommon.t_startc == CTRL('q');
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	if (pty->pt_flags & PF_NOSTOP) {
960*0Sstevel@tonic-gate 		if (stop) {
961*0Sstevel@tonic-gate 			pty->pt_send &= ~TIOCPKT_NOSTOP;
962*0Sstevel@tonic-gate 			pty->pt_send |= TIOCPKT_DOSTOP;
963*0Sstevel@tonic-gate 			pty->pt_flags &= ~PF_NOSTOP;
964*0Sstevel@tonic-gate 			ptcpollwakeup(pty, 0);
965*0Sstevel@tonic-gate 		}
966*0Sstevel@tonic-gate 	} else {
967*0Sstevel@tonic-gate 		if (!stop) {
968*0Sstevel@tonic-gate 			pty->pt_send &= ~TIOCPKT_DOSTOP;
969*0Sstevel@tonic-gate 			pty->pt_send |= TIOCPKT_NOSTOP;
970*0Sstevel@tonic-gate 			pty->pt_flags |= PF_NOSTOP;
971*0Sstevel@tonic-gate 			ptcpollwakeup(pty, 0);
972*0Sstevel@tonic-gate 		}
973*0Sstevel@tonic-gate 	}
974*0Sstevel@tonic-gate }
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate /*
977*0Sstevel@tonic-gate  * Wake up controller side.  "flag" is 0 if a special packet or
978*0Sstevel@tonic-gate  * user control mode message has been queued up (this data is readable,
979*0Sstevel@tonic-gate  * so we also treat it as a regular data event; should we send SIGIO,
980*0Sstevel@tonic-gate  * though?), FREAD if regular data has been queued up, or FWRITE if
981*0Sstevel@tonic-gate  * the slave's read queue has drained sufficiently to allow writing.
982*0Sstevel@tonic-gate  */
983*0Sstevel@tonic-gate static void
984*0Sstevel@tonic-gate ptcpollwakeup(struct pty *pty, int flag)
985*0Sstevel@tonic-gate {
986*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pty->ptc_lock));
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 	if (flag == 0) {
989*0Sstevel@tonic-gate 		/*
990*0Sstevel@tonic-gate 		 * "Exceptional condition" occurred.  This means that
991*0Sstevel@tonic-gate 		 * a "read" is now possible, so do a "read" wakeup.
992*0Sstevel@tonic-gate 		 */
993*0Sstevel@tonic-gate 		flag = FREAD;
994*0Sstevel@tonic-gate 		pollwakeup(&ptcph, POLLIN | POLLRDBAND);
995*0Sstevel@tonic-gate 		if (pty->pt_flags & PF_ASYNC)
996*0Sstevel@tonic-gate 			gsignal(pty->pt_pgrp, SIGURG);
997*0Sstevel@tonic-gate 	}
998*0Sstevel@tonic-gate 	if (flag & FREAD) {
999*0Sstevel@tonic-gate 		/*
1000*0Sstevel@tonic-gate 		 * Wake up the parent process as there is regular
1001*0Sstevel@tonic-gate 		 * data to read from slave's write queue
1002*0Sstevel@tonic-gate 		 */
1003*0Sstevel@tonic-gate 		pollwakeup(&ptcph, POLLIN | POLLRDNORM);
1004*0Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_writeq);
1005*0Sstevel@tonic-gate 		if (pty->pt_flags & PF_ASYNC)
1006*0Sstevel@tonic-gate 			gsignal(pty->pt_pgrp, SIGIO);
1007*0Sstevel@tonic-gate 	}
1008*0Sstevel@tonic-gate 	if (flag & FWRITE) {
1009*0Sstevel@tonic-gate 		/*
1010*0Sstevel@tonic-gate 		 * Wake up the parent process to write
1011*0Sstevel@tonic-gate 		 * data into slave's read queue as the
1012*0Sstevel@tonic-gate 		 * read queue has drained enough
1013*0Sstevel@tonic-gate 		 */
1014*0Sstevel@tonic-gate 		pollwakeup(&ptcph, POLLOUT | POLLWRNORM);
1015*0Sstevel@tonic-gate 		cv_broadcast(&pty->pt_cv_readq);
1016*0Sstevel@tonic-gate 		if (pty->pt_flags & PF_ASYNC)
1017*0Sstevel@tonic-gate 			gsignal(pty->pt_pgrp, SIGIO);
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate }
1020