1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  *	Asynchronous protocol handler for Z8530 chips
31*0Sstevel@tonic-gate  *	Handles normal UNIX support for terminals & modems
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <sys/types.h>
35*0Sstevel@tonic-gate #include <sys/param.h>
36*0Sstevel@tonic-gate #include <sys/systm.h>
37*0Sstevel@tonic-gate #include <sys/sysmacros.h>
38*0Sstevel@tonic-gate #include <sys/signal.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <sys/termios.h>
41*0Sstevel@tonic-gate #include <sys/stropts.h>
42*0Sstevel@tonic-gate #include <sys/stream.h>
43*0Sstevel@tonic-gate #include <sys/strsun.h>
44*0Sstevel@tonic-gate #include <sys/tty.h>
45*0Sstevel@tonic-gate #include <sys/ptyvar.h>
46*0Sstevel@tonic-gate #include <sys/cred.h>
47*0Sstevel@tonic-gate #include <sys/user.h>
48*0Sstevel@tonic-gate #include <sys/proc.h>
49*0Sstevel@tonic-gate #include <sys/file.h>
50*0Sstevel@tonic-gate #include <sys/uio.h>
51*0Sstevel@tonic-gate #include <sys/buf.h>
52*0Sstevel@tonic-gate #include <sys/mkdev.h>
53*0Sstevel@tonic-gate #include <sys/cmn_err.h>
54*0Sstevel@tonic-gate #include <sys/strtty.h>
55*0Sstevel@tonic-gate #include <sys/consdev.h>
56*0Sstevel@tonic-gate #include <sys/zsdev.h>
57*0Sstevel@tonic-gate #include <sys/ser_async.h>
58*0Sstevel@tonic-gate #include <sys/debug.h>
59*0Sstevel@tonic-gate #include <sys/kbio.h>
60*0Sstevel@tonic-gate #include <sys/conf.h>
61*0Sstevel@tonic-gate #include <sys/ddi.h>
62*0Sstevel@tonic-gate #include <sys/sunddi.h>
63*0Sstevel@tonic-gate #include <sys/promif.h>
64*0Sstevel@tonic-gate #include <sys/policy.h>
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate /*
67*0Sstevel@tonic-gate  * PPS (Pulse Per Second) support.
68*0Sstevel@tonic-gate  */
69*0Sstevel@tonic-gate extern void ddi_hardpps(struct timeval *, int);
70*0Sstevel@tonic-gate static struct ppsclockev ppsclockev;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #ifdef PPSCLOCKLED
73*0Sstevel@tonic-gate /* XXX Use these to observe PPS latencies and jitter on a scope */
74*0Sstevel@tonic-gate #define	LED_ON
75*0Sstevel@tonic-gate #define	LED_OFF
76*0Sstevel@tonic-gate #else
77*0Sstevel@tonic-gate #define	LED_ON
78*0Sstevel@tonic-gate #define	LED_OFF
79*0Sstevel@tonic-gate #endif
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate #define	ZSA_RCV_SIZE	64
82*0Sstevel@tonic-gate #define	ZA_KICK_RCV_COUNT	3
83*0Sstevel@tonic-gate #define	ZSA_GRACE_MIN_FLOW_CONTROL	5
84*0Sstevel@tonic-gate #define	ZSA_GRACE_MAX_FLOW_CONTROL	20
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate int zsasoftdtr = 0;	/* if nonzero, softcarrier raises dtr at attach */
87*0Sstevel@tonic-gate int zsb134_weird = 0;	/* if set, old weird B134 behavior */
88*0Sstevel@tonic-gate int g_zsticks = 0;	/* if set, becomes the global zsticks value */
89*0Sstevel@tonic-gate int g_nocluster = 0;	/* if set, disables clustering of received data */
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate unsigned int zsa_rstandby = ZSA_MIN_RSTANDBY;
92*0Sstevel@tonic-gate unsigned int zsa_rdone = ZSA_RDONE_MIN;
93*0Sstevel@tonic-gate unsigned int zsa_grace_flow_control = ZSA_GRACE_MIN_FLOW_CONTROL;
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate #define	NSPEED	18	/* max # of speeds */
97*0Sstevel@tonic-gate ushort_t zs_speeds[NSPEED] = {
98*0Sstevel@tonic-gate 	0,
99*0Sstevel@tonic-gate 	ZSPEED(50),	/* 1 */
100*0Sstevel@tonic-gate 	ZSPEED(75),	/* 2 */
101*0Sstevel@tonic-gate 	ZSPEED(110),	/* 3 */
102*0Sstevel@tonic-gate #ifdef lint
103*0Sstevel@tonic-gate 	ZSPEED(134),	/* 4 */
104*0Sstevel@tonic-gate #else
105*0Sstevel@tonic-gate 	ZSPEED(269/2),			/* XXX - This is sleazy */
106*0Sstevel@tonic-gate #endif
107*0Sstevel@tonic-gate 	ZSPEED(150),	/* 5 */
108*0Sstevel@tonic-gate 	ZSPEED(200),	/* 6 */
109*0Sstevel@tonic-gate 	ZSPEED(300),	/* 7 */
110*0Sstevel@tonic-gate 	ZSPEED(600),	/* 8 */
111*0Sstevel@tonic-gate 	ZSPEED(1200),	/* 9 */
112*0Sstevel@tonic-gate 	ZSPEED(1800),	/* 10 */
113*0Sstevel@tonic-gate 	ZSPEED(2400),	/* 11 */
114*0Sstevel@tonic-gate 	ZSPEED(4800),	/* 12 */
115*0Sstevel@tonic-gate 	ZSPEED(9600),	/* 13 */
116*0Sstevel@tonic-gate 	ZSPEED(19200),	/* 14 */
117*0Sstevel@tonic-gate 	ZSPEED(38400),	/* 15 */
118*0Sstevel@tonic-gate 	ZSPEED(57680),	/* 16 */
119*0Sstevel@tonic-gate 	ZSPEED(76800)	/* 17 */
120*0Sstevel@tonic-gate };
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate ushort_t zsticks[NSPEED] = {
123*0Sstevel@tonic-gate 	3,		/* 0 */
124*0Sstevel@tonic-gate 	3,		/* 1 */
125*0Sstevel@tonic-gate 	3,		/* 2 */
126*0Sstevel@tonic-gate 	3,		/* 3 */
127*0Sstevel@tonic-gate 	3,		/* 4 */
128*0Sstevel@tonic-gate 	3,		/* 5 */
129*0Sstevel@tonic-gate 	3,		/* 6 */
130*0Sstevel@tonic-gate 	3,		/* 7 */
131*0Sstevel@tonic-gate 	3,		/* 8 */
132*0Sstevel@tonic-gate 	3,		/* 9 */
133*0Sstevel@tonic-gate 	3,		/* 10 */
134*0Sstevel@tonic-gate 	3,		/* 11 */
135*0Sstevel@tonic-gate 	3,		/* 12 */
136*0Sstevel@tonic-gate 	3,		/* 13 */
137*0Sstevel@tonic-gate 	2,		/* 14 */
138*0Sstevel@tonic-gate 	1,		/* 15 */
139*0Sstevel@tonic-gate 	1,		/* 16 */
140*0Sstevel@tonic-gate 	1		/* 17 */
141*0Sstevel@tonic-gate };
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate #define	ztdelay(nsp)	(zsdelay[(nsp)]*(hz/100))
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate ushort_t zsdelay[NSPEED] = {
146*0Sstevel@tonic-gate 	0,
147*0Sstevel@tonic-gate 	ZDELAY(50),	/* 1 */
148*0Sstevel@tonic-gate 	ZDELAY(75),	/* 2 */
149*0Sstevel@tonic-gate 	ZDELAY(110),    /* 3 */
150*0Sstevel@tonic-gate #ifdef lint
151*0Sstevel@tonic-gate 	ZDELAY(134),    /* 4 */
152*0Sstevel@tonic-gate #else
153*0Sstevel@tonic-gate 	ZDELAY(269/2),
154*0Sstevel@tonic-gate #endif
155*0Sstevel@tonic-gate 	ZDELAY(150),    /* 5 */
156*0Sstevel@tonic-gate 	ZDELAY(200),    /* 6 */
157*0Sstevel@tonic-gate 	ZDELAY(300),    /* 7 */
158*0Sstevel@tonic-gate 	ZDELAY(600),    /* 8 */
159*0Sstevel@tonic-gate 	ZDELAY(1200),   /* 9 */
160*0Sstevel@tonic-gate 	ZDELAY(1800),   /* 10 */
161*0Sstevel@tonic-gate 	ZDELAY(2400),   /* 11 */
162*0Sstevel@tonic-gate 	ZDELAY(4800),   /* 12 */
163*0Sstevel@tonic-gate 	ZDELAY(9600),   /* 13 */
164*0Sstevel@tonic-gate 	ZDELAY(19200),  /* 14 */
165*0Sstevel@tonic-gate 	ZDELAY(38400),  /* 15 */
166*0Sstevel@tonic-gate 	ZDELAY(57600),  /* 16 */
167*0Sstevel@tonic-gate 	ZDELAY(76800)	/* 17 */
168*0Sstevel@tonic-gate };
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate ushort_t zslowat[NSPEED] = {
171*0Sstevel@tonic-gate 	3,		/* 0 */
172*0Sstevel@tonic-gate 	3,		/* 1 */
173*0Sstevel@tonic-gate 	3,		/* 2 */
174*0Sstevel@tonic-gate 	3,		/* 3 */
175*0Sstevel@tonic-gate 	3,		/* 4 */
176*0Sstevel@tonic-gate 	3,		/* 5 */
177*0Sstevel@tonic-gate 	3,		/* 6 */
178*0Sstevel@tonic-gate 	2,		/* 7 */
179*0Sstevel@tonic-gate 	2,		/* 8 */
180*0Sstevel@tonic-gate 	2,		/* 9 */
181*0Sstevel@tonic-gate 	2,		/* 10 */
182*0Sstevel@tonic-gate 	1,		/* 11 */
183*0Sstevel@tonic-gate 	1,		/* 12 */
184*0Sstevel@tonic-gate 	1,		/* 13 */
185*0Sstevel@tonic-gate 	1,		/* 14 */
186*0Sstevel@tonic-gate 	1,		/* 15 */
187*0Sstevel@tonic-gate 	1,		/* 16 */
188*0Sstevel@tonic-gate 	1		/* 17 */
189*0Sstevel@tonic-gate };
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate ushort_t zshiwat[NSPEED] = {
192*0Sstevel@tonic-gate 	0,		/* 0 */
193*0Sstevel@tonic-gate 	1,		/* 1 */
194*0Sstevel@tonic-gate 	1,		/* 2 */
195*0Sstevel@tonic-gate 	1,		/* 3 */
196*0Sstevel@tonic-gate 	1,		/* 4 */
197*0Sstevel@tonic-gate 	1,		/* 5 */
198*0Sstevel@tonic-gate 	1,		/* 6 */
199*0Sstevel@tonic-gate 	1,		/* 7 */
200*0Sstevel@tonic-gate 	1,		/* 8 */
201*0Sstevel@tonic-gate 	1,		/* 9 */
202*0Sstevel@tonic-gate 	1,		/* 10 */
203*0Sstevel@tonic-gate 	1,		/* 11 */
204*0Sstevel@tonic-gate 	1,		/* 12 */
205*0Sstevel@tonic-gate 	3,		/* 13 */
206*0Sstevel@tonic-gate 	3,		/* 14 */
207*0Sstevel@tonic-gate 	4,		/* 15 */
208*0Sstevel@tonic-gate 	4,		/* 16 */
209*0Sstevel@tonic-gate 	4		/* 17 */
210*0Sstevel@tonic-gate };
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate #define	SLAVIO_BUG	/* this workaround required to fix bug 1102778 */
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate #define	SPEED(cflag) \
215*0Sstevel@tonic-gate 	((cflag) & CBAUDEXT) ? \
216*0Sstevel@tonic-gate 		(((cflag) & 0x1) + CBAUD + 1) : ((cflag) & CBAUD)
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate  * Special macros to handle STREAMS operations.
220*0Sstevel@tonic-gate  * These are required to address memory leakage problems.
221*0Sstevel@tonic-gate  * WARNING : the macro do NOT call ZSSETSOFT
222*0Sstevel@tonic-gate  */
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate /*
225*0Sstevel@tonic-gate  * Should be called holding only the adaptive (zs_excl) mutex.
226*0Sstevel@tonic-gate  */
227*0Sstevel@tonic-gate #define	ZSA_GETBLOCK(zs, allocbcount) \
228*0Sstevel@tonic-gate { \
229*0Sstevel@tonic-gate 	register int n = zsa_rstandby; \
230*0Sstevel@tonic-gate 	while (--n >= 0 && allocbcount > 0) { \
231*0Sstevel@tonic-gate 		if (!za->za_rstandby[n]) { \
232*0Sstevel@tonic-gate 			if ((za->za_rstandby[n] = allocb(ZSA_RCV_SIZE, \
233*0Sstevel@tonic-gate 			    BPRI_MED)) == NULL) { \
234*0Sstevel@tonic-gate 				if (za->za_bufcid == 0) { \
235*0Sstevel@tonic-gate 					za->za_bufcid = bufcall(ZSA_RCV_SIZE, \
236*0Sstevel@tonic-gate 					    BPRI_MED, \
237*0Sstevel@tonic-gate 					    zsa_callback, zs); \
238*0Sstevel@tonic-gate 					break; \
239*0Sstevel@tonic-gate 				} \
240*0Sstevel@tonic-gate 			} \
241*0Sstevel@tonic-gate 			allocbcount--; \
242*0Sstevel@tonic-gate 		} \
243*0Sstevel@tonic-gate 	} \
244*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSXOFF) { \
245*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi); \
246*0Sstevel@tonic-gate 		if (!(zs->zs_wreg[5] & ZSWR5_RTS)) { \
247*0Sstevel@tonic-gate 			register int usedcnt = 0; \
248*0Sstevel@tonic-gate 			for (n = 0; n < zsa_rstandby; n++) \
249*0Sstevel@tonic-gate 				if (!za->za_rstandby[n]) \
250*0Sstevel@tonic-gate 					usedcnt++; \
251*0Sstevel@tonic-gate 			if ((ushort_t)usedcnt <= \
252*0Sstevel@tonic-gate 			    zslowat[SPEED(za->za_ttycommon.t_cflag)]) \
253*0Sstevel@tonic-gate 				SCC_BIS(5, ZSWR5_RTS); \
254*0Sstevel@tonic-gate 		} \
255*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi); \
256*0Sstevel@tonic-gate 	} \
257*0Sstevel@tonic-gate }
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate /*
260*0Sstevel@tonic-gate  * Should be called holding the spin (zs_excl_hi) mutex.
261*0Sstevel@tonic-gate  */
262*0Sstevel@tonic-gate #define	ZSA_ALLOCB(mp) \
263*0Sstevel@tonic-gate { \
264*0Sstevel@tonic-gate 	register int n = zsa_rstandby; \
265*0Sstevel@tonic-gate 	while (--n >= 0) { \
266*0Sstevel@tonic-gate 		if ((mp = za->za_rstandby[n]) != NULL) { \
267*0Sstevel@tonic-gate 			za->za_rstandby[n] = NULL; \
268*0Sstevel@tonic-gate 			break; \
269*0Sstevel@tonic-gate 		} \
270*0Sstevel@tonic-gate 	} \
271*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSXOFF) { \
272*0Sstevel@tonic-gate 		if (!mp) { \
273*0Sstevel@tonic-gate 			if (zs->zs_wreg[5] & ZSWR5_RTS) \
274*0Sstevel@tonic-gate 				SCC_BIC(5, ZSWR5_RTS); \
275*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "zs%d: message lost\n", \
276*0Sstevel@tonic-gate 				UNIT(za->za_dev)); \
277*0Sstevel@tonic-gate 		} else if (zs->zs_wreg[5] & ZSWR5_RTS) { \
278*0Sstevel@tonic-gate 			register int usedcnt = 0; \
279*0Sstevel@tonic-gate 			for (n = 0; n < zsa_rstandby; n++) \
280*0Sstevel@tonic-gate 				if (!za->za_rstandby[n]) \
281*0Sstevel@tonic-gate 					usedcnt++; \
282*0Sstevel@tonic-gate 			if ((ushort_t)usedcnt >= (zsa_rstandby - \
283*0Sstevel@tonic-gate 			    zshiwat[SPEED(za->za_ttycommon.t_cflag)])) \
284*0Sstevel@tonic-gate 				SCC_BIC(5, ZSWR5_RTS); \
285*0Sstevel@tonic-gate 		} \
286*0Sstevel@tonic-gate 	} \
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate /*
290*0Sstevel@tonic-gate  * Should get the spin (zs_excl_hi) mutex.
291*0Sstevel@tonic-gate  */
292*0Sstevel@tonic-gate #define	ZSA_QREPLY(q, mp) \
293*0Sstevel@tonic-gate { \
294*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi); \
295*0Sstevel@tonic-gate 	ZSA_PUTQ(mp); \
296*0Sstevel@tonic-gate 	ZSSETSOFT(zs); \
297*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi); \
298*0Sstevel@tonic-gate }
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate /*
301*0Sstevel@tonic-gate  * Should be called holding the spin (zs_excl_hi) mutex.
302*0Sstevel@tonic-gate  */
303*0Sstevel@tonic-gate #define	ZSA_PUTQ(mp) \
304*0Sstevel@tonic-gate { \
305*0Sstevel@tonic-gate 	register int wptr, rptr; \
306*0Sstevel@tonic-gate 	wptr = za->za_rdone_wptr; \
307*0Sstevel@tonic-gate 	rptr = za->za_rdone_rptr; \
308*0Sstevel@tonic-gate 	za->za_rdone[wptr] = mp; \
309*0Sstevel@tonic-gate 	if ((wptr)+1 == zsa_rdone) { \
310*0Sstevel@tonic-gate 		za->za_rdone_wptr = wptr = 0; \
311*0Sstevel@tonic-gate 	} else \
312*0Sstevel@tonic-gate 		za->za_rdone_wptr = ++wptr; \
313*0Sstevel@tonic-gate 	if (wptr == rptr) { \
314*0Sstevel@tonic-gate 		SCC_BIC(1, ZSWR1_INIT); \
315*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "zs%d disabled: input buffer overflow", \
316*0Sstevel@tonic-gate 			UNIT(za->za_dev)); \
317*0Sstevel@tonic-gate 	} \
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate /*
321*0Sstevel@tonic-gate  * Should be called holding the spin (zs_excl_hi) mutex.
322*0Sstevel@tonic-gate  */
323*0Sstevel@tonic-gate #define	ZSA_KICK_RCV \
324*0Sstevel@tonic-gate { \
325*0Sstevel@tonic-gate 	register mblk_t *mp = za->za_rcvblk; \
326*0Sstevel@tonic-gate 	if (mp) { \
327*0Sstevel@tonic-gate 		if (zs->zs_rd_cur) {	/* M_DATA */ \
328*0Sstevel@tonic-gate 			mp->b_wptr = zs->zs_rd_cur; \
329*0Sstevel@tonic-gate 			zs->zs_rd_cur = NULL; \
330*0Sstevel@tonic-gate 			zs->zs_rd_lim = NULL; \
331*0Sstevel@tonic-gate 		} \
332*0Sstevel@tonic-gate 		za->za_rcvblk = NULL; \
333*0Sstevel@tonic-gate 		ZSA_PUTQ(mp); \
334*0Sstevel@tonic-gate 		ZSSETSOFT(zs); \
335*0Sstevel@tonic-gate 	} \
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate #define	ZSA_SEEQ(mp) \
339*0Sstevel@tonic-gate { \
340*0Sstevel@tonic-gate 		if (za->za_rdone_rptr != za->za_rdone_wptr) { \
341*0Sstevel@tonic-gate 			mp = za->za_rdone[za->za_rdone_rptr]; \
342*0Sstevel@tonic-gate 		} else { \
343*0Sstevel@tonic-gate 			mp = NULL; \
344*0Sstevel@tonic-gate 		} \
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate /*
349*0Sstevel@tonic-gate  * Should be called holding only the adaptive (zs_excl) mutex.
350*0Sstevel@tonic-gate  */
351*0Sstevel@tonic-gate #define	ZSA_GETQ(mp) \
352*0Sstevel@tonic-gate { \
353*0Sstevel@tonic-gate 	if (za->za_rdone_rptr != za->za_rdone_wptr) { \
354*0Sstevel@tonic-gate 		mp = za->za_rdone[za->za_rdone_rptr]; \
355*0Sstevel@tonic-gate 		za->za_rdone[za->za_rdone_rptr++] = NULL; \
356*0Sstevel@tonic-gate 		if (za->za_rdone_rptr == zsa_rdone) \
357*0Sstevel@tonic-gate 			za->za_rdone_rptr = 0; \
358*0Sstevel@tonic-gate 	} else { \
359*0Sstevel@tonic-gate 		mp = NULL; \
360*0Sstevel@tonic-gate 	} \
361*0Sstevel@tonic-gate }
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate /*
364*0Sstevel@tonic-gate  * Should be called holding only the adaptive (zs_excl) mutex.
365*0Sstevel@tonic-gate  */
366*0Sstevel@tonic-gate #define	ZSA_FLUSHQ \
367*0Sstevel@tonic-gate { \
368*0Sstevel@tonic-gate 	register mblk_t *tmp; \
369*0Sstevel@tonic-gate 	for (;;) { \
370*0Sstevel@tonic-gate 		ZSA_GETQ(tmp); \
371*0Sstevel@tonic-gate 		if (!(tmp)) \
372*0Sstevel@tonic-gate 			break; \
373*0Sstevel@tonic-gate 		freemsg(tmp); \
374*0Sstevel@tonic-gate 	} \
375*0Sstevel@tonic-gate }
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate /*
379*0Sstevel@tonic-gate  * Logging definitions
380*0Sstevel@tonic-gate  */
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate #ifdef ZSA_DEBUG
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate #ifdef ZS_DEBUG_ALL
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate extern	char	zs_h_log[];
387*0Sstevel@tonic-gate extern	int	zs_h_log_n;
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate #define	zsa_h_log_clear
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate #define	zsa_h_log_add(c) \
392*0Sstevel@tonic-gate { \
393*0Sstevel@tonic-gate 	if (zs_h_log_n >= ZS_H_LOG_MAX) \
394*0Sstevel@tonic-gate 		zs_h_log_n = 0; \
395*0Sstevel@tonic-gate 	zs_h_log[zs_h_log_n++] = 'A' + zs->zs_unit; \
396*0Sstevel@tonic-gate 	zs_h_log[zs_h_log_n++] = c; \
397*0Sstevel@tonic-gate 	zs_h_log[zs_h_log_n] = '\0'; \
398*0Sstevel@tonic-gate }
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate #else /* ZS_DEBUG_ALL */
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate #define	ZSA_H_LOG_MAX	0x4000
403*0Sstevel@tonic-gate char zsa_h_log[40][ZSA_H_LOG_MAX +10];
404*0Sstevel@tonic-gate int zsa_h_log_n[40];
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate #define	zsa_h_log_add(c) \
407*0Sstevel@tonic-gate { \
408*0Sstevel@tonic-gate 	if (zsa_h_log_n[zs->zs_unit] >= ZSA_H_LOG_MAX) \
409*0Sstevel@tonic-gate 		zsa_h_log_n[zs->zs_unit] = 0; \
410*0Sstevel@tonic-gate 	zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]++] = c; \
411*0Sstevel@tonic-gate 	zsa_h_log[zs->zs_unit][zsa_h_log_n[zs->zs_unit]] = '\0'; \
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate #define	zsa_h_log_clear \
415*0Sstevel@tonic-gate { \
416*0Sstevel@tonic-gate 	register char *p; \
417*0Sstevel@tonic-gate 	for (p = &zsa_h_log[zs->zs_unit][ZSA_H_LOG_MAX]; \
418*0Sstevel@tonic-gate 		p >= &zsa_h_log[zs->zs_unit][0]; /* null */) \
419*0Sstevel@tonic-gate 		*p-- = '\0'; \
420*0Sstevel@tonic-gate 	zsa_h_log_n[zs->zs_unit] = 0; \
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate #endif /* ZS_DEBUG_ALL */
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate #define	ZSA_R0_LOG(r0) \
426*0Sstevel@tonic-gate { \
427*0Sstevel@tonic-gate 	if (r0 & ZSRR0_RX_READY) zsa_h_log_add('R'); \
428*0Sstevel@tonic-gate 	if (r0 & ZSRR0_TIMER) zsa_h_log_add('Z'); \
429*0Sstevel@tonic-gate 	if (r0 & ZSRR0_TX_READY) zsa_h_log_add('T'); \
430*0Sstevel@tonic-gate 	if (r0 & ZSRR0_CD) zsa_h_log_add('D'); \
431*0Sstevel@tonic-gate 	if (r0 & ZSRR0_SYNC) zsa_h_log_add('S'); \
432*0Sstevel@tonic-gate 	if (r0 & ZSRR0_CTS) zsa_h_log_add('C'); \
433*0Sstevel@tonic-gate 	if (r0 & ZSRR0_TXUNDER) zsa_h_log_add('U'); \
434*0Sstevel@tonic-gate 	if (r0 & ZSRR0_BREAK) zsa_h_log_add('B'); \
435*0Sstevel@tonic-gate }
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate #else /* ZSA_DEBUG */
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate #define	zsa_h_log_clear
440*0Sstevel@tonic-gate #define	zsa_h_log_add(c)
441*0Sstevel@tonic-gate #define	 ZSA_R0_LOG(r0)
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate #endif /* ZSA_DEBUG */
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate static int zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
448*0Sstevel@tonic-gate static int zsa_close(queue_t *q, int flag);
449*0Sstevel@tonic-gate static void zsa_wput(queue_t *q, mblk_t *mp);
450*0Sstevel@tonic-gate static void zsa_rsrv(queue_t *q);
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate static struct module_info asyncm_info = {
453*0Sstevel@tonic-gate 	0,
454*0Sstevel@tonic-gate 	"zs",
455*0Sstevel@tonic-gate 	0,
456*0Sstevel@tonic-gate 	INFPSZ,
457*0Sstevel@tonic-gate 	2048,
458*0Sstevel@tonic-gate 	128
459*0Sstevel@tonic-gate };
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate static struct qinit async_rinit = {
462*0Sstevel@tonic-gate 	putq,
463*0Sstevel@tonic-gate 	(int (*)())zsa_rsrv,
464*0Sstevel@tonic-gate 	zsa_open,
465*0Sstevel@tonic-gate 	zsa_close,
466*0Sstevel@tonic-gate 	NULL,
467*0Sstevel@tonic-gate 	&asyncm_info,
468*0Sstevel@tonic-gate 	NULL
469*0Sstevel@tonic-gate };
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate static struct qinit async_winit = {
472*0Sstevel@tonic-gate 	(int (*)())zsa_wput,
473*0Sstevel@tonic-gate 	NULL,
474*0Sstevel@tonic-gate 	NULL,
475*0Sstevel@tonic-gate 	NULL,
476*0Sstevel@tonic-gate 	NULL,
477*0Sstevel@tonic-gate 	&asyncm_info,
478*0Sstevel@tonic-gate 	NULL
479*0Sstevel@tonic-gate };
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate struct streamtab asynctab = {
482*0Sstevel@tonic-gate 	&async_rinit,
483*0Sstevel@tonic-gate 	&async_winit,
484*0Sstevel@tonic-gate 	NULL,
485*0Sstevel@tonic-gate 	NULL,
486*0Sstevel@tonic-gate };
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate /*
489*0Sstevel@tonic-gate  * The async interrupt entry points.
490*0Sstevel@tonic-gate  */
491*0Sstevel@tonic-gate static void	zsa_txint(struct zscom *zs);
492*0Sstevel@tonic-gate static void	zsa_xsint(struct zscom *zs);
493*0Sstevel@tonic-gate static void	zsa_rxint(struct zscom *zs);
494*0Sstevel@tonic-gate static void	zsa_srint(struct zscom *zs);
495*0Sstevel@tonic-gate static int	zsa_softint(struct zscom *zs);
496*0Sstevel@tonic-gate static int	zsa_suspend(struct zscom *zs);
497*0Sstevel@tonic-gate static int	zsa_resume(struct zscom *zs);
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate static void
500*0Sstevel@tonic-gate zsa_null(struct zscom *zs)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	/* LINTED */
503*0Sstevel@tonic-gate 	register short	c;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_TXINT);
506*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
507*0Sstevel@tonic-gate 	c = SCC_READDATA();
508*0Sstevel@tonic-gate 	ZSDELAY();
509*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_ERRORS);
510*0Sstevel@tonic-gate }
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate /*ARGSUSED*/
513*0Sstevel@tonic-gate static int
514*0Sstevel@tonic-gate zsa_null_int(struct zscom *zs)
515*0Sstevel@tonic-gate {
516*0Sstevel@tonic-gate 	return (0);
517*0Sstevel@tonic-gate }
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate struct zsops zsops_null_async = {
520*0Sstevel@tonic-gate 	zsa_null,
521*0Sstevel@tonic-gate 	zsa_null,
522*0Sstevel@tonic-gate 	zsa_null,
523*0Sstevel@tonic-gate 	zsa_null,
524*0Sstevel@tonic-gate 	zsa_null_int,
525*0Sstevel@tonic-gate 	zsa_null_int,
526*0Sstevel@tonic-gate 	zsa_null_int
527*0Sstevel@tonic-gate };
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate struct zsops zsops_async = {
530*0Sstevel@tonic-gate 	zsa_txint,
531*0Sstevel@tonic-gate 	zsa_xsint,
532*0Sstevel@tonic-gate 	zsa_rxint,
533*0Sstevel@tonic-gate 	zsa_srint,
534*0Sstevel@tonic-gate 	zsa_softint,
535*0Sstevel@tonic-gate 	zsa_suspend,
536*0Sstevel@tonic-gate 	zsa_resume
537*0Sstevel@tonic-gate };
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate static int	dmtozs(int bits);
540*0Sstevel@tonic-gate static int	zstodm(int bits);
541*0Sstevel@tonic-gate static void	zsa_restart(void *);
542*0Sstevel@tonic-gate static void	zsa_reioctl(void *);
543*0Sstevel@tonic-gate static void	zsa_ioctl(struct asyncline *za, queue_t *q, mblk_t *mp);
544*0Sstevel@tonic-gate static void	zsa_program(struct asyncline *za, int setibaud);
545*0Sstevel@tonic-gate static void	zsa_start(struct zscom *zs);
546*0Sstevel@tonic-gate static void 	zsa_kick_rcv(void *);
547*0Sstevel@tonic-gate static void 	zsa_callback(void *);
548*0Sstevel@tonic-gate static void	zsa_set_za_rcv_flags_mask(struct asyncline *za);
549*0Sstevel@tonic-gate int		zsgetspeed(dev_t dev);
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate static boolean_t abort_charseq_recognize(uchar_t ch);
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate /* ARGSUSED */
554*0Sstevel@tonic-gate int
555*0Sstevel@tonic-gate zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
556*0Sstevel@tonic-gate     void **result)
557*0Sstevel@tonic-gate {
558*0Sstevel@tonic-gate 	register dev_t dev = (dev_t)arg;
559*0Sstevel@tonic-gate 	register int unit, error;
560*0Sstevel@tonic-gate 	register struct zscom *zs;
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	if ((unit = UNIT(dev)) >= nzs)
563*0Sstevel@tonic-gate 		return (DDI_FAILURE);
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	switch (infocmd) {
566*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
567*0Sstevel@tonic-gate 		zs = &zscom[unit];
568*0Sstevel@tonic-gate 		*result = zs->zs_dip;
569*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
570*0Sstevel@tonic-gate 		break;
571*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
572*0Sstevel@tonic-gate 		*result = (void *)(unit / 2);
573*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
574*0Sstevel@tonic-gate 		break;
575*0Sstevel@tonic-gate 	default:
576*0Sstevel@tonic-gate 		error = DDI_FAILURE;
577*0Sstevel@tonic-gate 	}
578*0Sstevel@tonic-gate 	return (error);
579*0Sstevel@tonic-gate }
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate /*
582*0Sstevel@tonic-gate  * The Asynchronous Driver.
583*0Sstevel@tonic-gate  */
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate /*
586*0Sstevel@tonic-gate  * Determine if the zsminor device is in use as either a stdin or stdout
587*0Sstevel@tonic-gate  * device, so we can be careful about how we initialize the DUART, if
588*0Sstevel@tonic-gate  * it is, in fact, in use.
589*0Sstevel@tonic-gate  *
590*0Sstevel@tonic-gate  * Since this is expensive, we do it once and store away the answers,
591*0Sstevel@tonic-gate  * since this gets called a number of times per phyical zs device.
592*0Sstevel@tonic-gate  * Perhaps, this should be in a loadable module, so it can get thrown
593*0Sstevel@tonic-gate  * away after all the zs devices are attached?
594*0Sstevel@tonic-gate  */
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate /*
597*0Sstevel@tonic-gate  * To determine if a given unit is being used by the PROM,
598*0Sstevel@tonic-gate  * we need to map stdin/stdout devices as known to the PROM
599*0Sstevel@tonic-gate  * to zs internal minor device numbers:
600*0Sstevel@tonic-gate  *
601*0Sstevel@tonic-gate  * PROM (real device)	zs minor	device
602*0Sstevel@tonic-gate  *
603*0Sstevel@tonic-gate  * "zs", 0, "a"		 0		ttya
604*0Sstevel@tonic-gate  * "zs", 0, "b"		 1		ttyb
605*0Sstevel@tonic-gate  * "zs", 1, "a"		 2		keyboard
606*0Sstevel@tonic-gate  * "zs", 1, "b"		 3		mouse
607*0Sstevel@tonic-gate  * "zs", 2, "a"		 4		ttyc
608*0Sstevel@tonic-gate  * "zs", 2, "b"		 5		ttyd
609*0Sstevel@tonic-gate  *
610*0Sstevel@tonic-gate  * The following value mapping lines assume that insource
611*0Sstevel@tonic-gate  * and outsink map as "screen, a, b, c, d, ...", and that
612*0Sstevel@tonic-gate  * zs minors are "a, b, kbd, mouse, c, d, ...".
613*0Sstevel@tonic-gate  */
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate static int zsa_inuse;		/* Strictly for debugging */
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate int
618*0Sstevel@tonic-gate zsa_channel_is_active_in_rom(dev_info_t *dev, int zsminor)
619*0Sstevel@tonic-gate {
620*0Sstevel@tonic-gate 	char pathname[OBP_MAXPATHLEN];
621*0Sstevel@tonic-gate 	char default_pathname[OBP_MAXPATHLEN];
622*0Sstevel@tonic-gate 	char *stdioname;
623*0Sstevel@tonic-gate 	char minordata[3];
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	/*
626*0Sstevel@tonic-gate 	 * Basically, get my name and compare it to stdio devnames
627*0Sstevel@tonic-gate 	 * and if we get a match, then the device is in use as either
628*0Sstevel@tonic-gate 	 * stdin or stdout device (console tip line or keyboard device).
629*0Sstevel@tonic-gate 	 *
630*0Sstevel@tonic-gate 	 * We get two forms of the pathname, one complete with the
631*0Sstevel@tonic-gate 	 * the channel number, and if the channel is 'a', then
632*0Sstevel@tonic-gate 	 * we also deal with the user's ability to default to
633*0Sstevel@tonic-gate 	 * channel 'a', by omitting the channel number option.
634*0Sstevel@tonic-gate 	 * We then compare these pathnames to both the stdin and
635*0Sstevel@tonic-gate 	 * stdout pathnames. If any of these match, then the channel
636*0Sstevel@tonic-gate 	 * is in use.
637*0Sstevel@tonic-gate 	 */
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	(void) ddi_pathname(dev, pathname);	/* device pathname */
640*0Sstevel@tonic-gate 	default_pathname[0] = (char)0;	/* default pathname if channel 'a' */
641*0Sstevel@tonic-gate 	if ((zsminor & 1) == 0)
642*0Sstevel@tonic-gate 		(void) strcpy(default_pathname, pathname);
643*0Sstevel@tonic-gate 	minordata[0] = ':';
644*0Sstevel@tonic-gate 	minordata[1] = (char)('a' + (zsminor & 1));
645*0Sstevel@tonic-gate 	minordata[2] = (char)0;
646*0Sstevel@tonic-gate 	(void) strcat(pathname, minordata);
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	stdioname = prom_stdinpath();
649*0Sstevel@tonic-gate 	if (strcmp(pathname, stdioname) == 0) {
650*0Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
651*0Sstevel@tonic-gate 		return (1);
652*0Sstevel@tonic-gate 	}
653*0Sstevel@tonic-gate 	if (strcmp(default_pathname, stdioname) == 0) {
654*0Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
655*0Sstevel@tonic-gate 		return (1);
656*0Sstevel@tonic-gate 	}
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	stdioname = prom_stdoutpath();
659*0Sstevel@tonic-gate 	if (strcmp(pathname, stdioname) == 0) {
660*0Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
661*0Sstevel@tonic-gate 		return (1);
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate 	if (strcmp(default_pathname, stdioname) == 0) {
664*0Sstevel@tonic-gate 		zsa_inuse |= (1 << zsminor);
665*0Sstevel@tonic-gate 		return (1);
666*0Sstevel@tonic-gate 	}
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	return (0);
669*0Sstevel@tonic-gate }
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate /*
672*0Sstevel@tonic-gate  * Initialize zs
673*0Sstevel@tonic-gate  */
674*0Sstevel@tonic-gate void
675*0Sstevel@tonic-gate zsa_init(struct zscom *zs)
676*0Sstevel@tonic-gate {
677*0Sstevel@tonic-gate 	/*
678*0Sstevel@tonic-gate 	 * This routine is called near the end of the zs module's attach
679*0Sstevel@tonic-gate 	 * process. It initializes the TTY protocol-private data for this
680*0Sstevel@tonic-gate 	 * channel that needs to be in place before interrupts are enabled.
681*0Sstevel@tonic-gate 	 */
682*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
683*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	/*
686*0Sstevel@tonic-gate 	 * Raise modem control lines on serial ports associated
687*0Sstevel@tonic-gate 	 * with the console and (optionally) softcarrier lines.
688*0Sstevel@tonic-gate 	 * Drop modem control lines on all others so that modems
689*0Sstevel@tonic-gate 	 * will not answer and portselectors will skip these
690*0Sstevel@tonic-gate 	 * lines until they are opened by a getty.
691*0Sstevel@tonic-gate 	 */
692*0Sstevel@tonic-gate 	if (zsa_channel_is_active_in_rom(zs->zs_dip, zs->zs_unit))
693*0Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_ON, DMSET);	/* raise dtr */
694*0Sstevel@tonic-gate 	else if (zsasoftdtr && (zssoftCAR[zs->zs_unit]))
695*0Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_ON, DMSET);	/* raise dtr */
696*0Sstevel@tonic-gate 	else
697*0Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_OFF, DMSET);	/* drop dtr */
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	if (zsa_rstandby > ZSA_MAX_RSTANDBY)
700*0Sstevel@tonic-gate 		zsa_rstandby = ZSA_MAX_RSTANDBY;
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	if (zsa_rdone > ZSA_RDONE_MAX)
703*0Sstevel@tonic-gate 		zsa_rdone = ZSA_RDONE_MAX;
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	if (zsa_grace_flow_control > ZSA_GRACE_MAX_FLOW_CONTROL)
706*0Sstevel@tonic-gate 		zsa_grace_flow_control = ZSA_GRACE_MAX_FLOW_CONTROL;
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
709*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
710*0Sstevel@tonic-gate }
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate /*
714*0Sstevel@tonic-gate  * Open routine.
715*0Sstevel@tonic-gate  */
716*0Sstevel@tonic-gate /*ARGSUSED*/
717*0Sstevel@tonic-gate static int
718*0Sstevel@tonic-gate zsa_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
719*0Sstevel@tonic-gate {
720*0Sstevel@tonic-gate 	register struct zscom *zs;
721*0Sstevel@tonic-gate 	register struct asyncline *za;
722*0Sstevel@tonic-gate 	register int	speed, unit;
723*0Sstevel@tonic-gate 	struct termios *termiosp;
724*0Sstevel@tonic-gate 	int len;
725*0Sstevel@tonic-gate 	register int allocbcount = zsa_rstandby;
726*0Sstevel@tonic-gate 	boolean_t set_zsoptinit = B_FALSE;
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	unit = UNIT(*dev);
729*0Sstevel@tonic-gate 	if (unit >= nzs)
730*0Sstevel@tonic-gate 		return (ENXIO);		/* unit not configured */
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	/* zscom is allocated by zsattach, and thus cannot be NULL here */
733*0Sstevel@tonic-gate 	zs = &zscom[unit];
734*0Sstevel@tonic-gate 	if (zs->zs_ops == NULL) {
735*0Sstevel@tonic-gate 		return (ENXIO);	 /* device not found by autoconfig */
736*0Sstevel@tonic-gate 	}
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	mutex_enter(zs->zs_ocexcl);
739*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
740*0Sstevel@tonic-gate again:
741*0Sstevel@tonic-gate 	if ((zs->zs_ops != &zsops_null) &&
742*0Sstevel@tonic-gate 	    (zs->zs_ops != &zsops_async)) {
743*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
744*0Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
745*0Sstevel@tonic-gate 		return (EBUSY);	 /* another protocol got here first */
746*0Sstevel@tonic-gate 	}
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	za = (struct asyncline *)&zs->zs_priv_str;
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	if (zs->zs_suspended) {
751*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
752*0Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
753*0Sstevel@tonic-gate 		(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
754*0Sstevel@tonic-gate 		mutex_enter(zs->zs_ocexcl);
755*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
756*0Sstevel@tonic-gate 	}
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	/* Mark device as busy (for power management) */
759*0Sstevel@tonic-gate 	(void) pm_busy_component(zs->zs_dip, unit%2+1);
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	if (zs->zs_ops == &zsops_null) {
762*0Sstevel@tonic-gate 		bzero(za, sizeof (zs->zs_priv_str));
763*0Sstevel@tonic-gate 		za->za_common = zs;
764*0Sstevel@tonic-gate 		if (zssoftCAR[zs->zs_unit])
765*0Sstevel@tonic-gate 			za->za_ttycommon.t_flags |= TS_SOFTCAR;
766*0Sstevel@tonic-gate 		zsopinit(zs, &zsops_async);
767*0Sstevel@tonic-gate 		set_zsoptinit = B_TRUE;
768*0Sstevel@tonic-gate 		za->za_rdone_wptr = 0;
769*0Sstevel@tonic-gate 		za->za_rdone_rptr = 0;
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	zs->zs_priv = (caddr_t)za;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	/*
775*0Sstevel@tonic-gate 	 * Block waiting for carrier to come up,
776*0Sstevel@tonic-gate 	 * unless this is a no-delay open.
777*0Sstevel@tonic-gate 	 */
778*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
779*0Sstevel@tonic-gate 	if (!(za->za_flags & ZAS_ISOPEN)) {
780*0Sstevel@tonic-gate 		/*
781*0Sstevel@tonic-gate 		 * Get the default termios settings (cflag).
782*0Sstevel@tonic-gate 		 * These are stored as a property in the
783*0Sstevel@tonic-gate 		 * "options" node.
784*0Sstevel@tonic-gate 		 */
785*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
786*0Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY,
787*0Sstevel@tonic-gate 		    ddi_root_node(), 0, "ttymodes",
788*0Sstevel@tonic-gate 		    (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
789*0Sstevel@tonic-gate 		    len == sizeof (struct termios)) {
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 			za->za_ttycommon.t_cflag = termiosp->c_cflag;
792*0Sstevel@tonic-gate 			kmem_free(termiosp, len);
793*0Sstevel@tonic-gate 		} else {
794*0Sstevel@tonic-gate 			/*
795*0Sstevel@tonic-gate 			 * Gack! Whine about it.
796*0Sstevel@tonic-gate 			 */
797*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
798*0Sstevel@tonic-gate 			    "zs: Couldn't get ttymodes property!");
799*0Sstevel@tonic-gate 		}
800*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
801*0Sstevel@tonic-gate 		if ((*dev == rconsdev) || (*dev == kbddev) ||
802*0Sstevel@tonic-gate 		    (*dev == stdindev)) {
803*0Sstevel@tonic-gate 			speed = zsgetspeed(*dev);
804*0Sstevel@tonic-gate 			za->za_ttycommon.t_cflag &= ~(CBAUD);
805*0Sstevel@tonic-gate 			if (speed > CBAUD) {
806*0Sstevel@tonic-gate 				za->za_ttycommon.t_cflag |= CBAUDEXT;
807*0Sstevel@tonic-gate 				za->za_ttycommon.t_cflag |=
808*0Sstevel@tonic-gate 					((speed - CBAUD - 1) & CBAUD);
809*0Sstevel@tonic-gate 			} else {
810*0Sstevel@tonic-gate 				za->za_ttycommon.t_cflag &= ~CBAUDEXT;
811*0Sstevel@tonic-gate 				za->za_ttycommon.t_cflag |= (speed & CBAUD);
812*0Sstevel@tonic-gate 			}
813*0Sstevel@tonic-gate 		}
814*0Sstevel@tonic-gate 		za->za_overrun = 0;
815*0Sstevel@tonic-gate 		za->za_ttycommon.t_iflag = 0;
816*0Sstevel@tonic-gate 		za->za_ttycommon.t_iocpending = NULL;
817*0Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_row = 0;
818*0Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_col = 0;
819*0Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_xpixel = 0;
820*0Sstevel@tonic-gate 		za->za_ttycommon.t_size.ws_ypixel = 0;
821*0Sstevel@tonic-gate 		za->za_dev = *dev;
822*0Sstevel@tonic-gate 		za->za_wbufcid = 0;
823*0Sstevel@tonic-gate 		zsa_program(za, za->za_ttycommon.t_cflag & (CIBAUDEXT|CIBAUD));
824*0Sstevel@tonic-gate 		zsa_set_za_rcv_flags_mask(za);
825*0Sstevel@tonic-gate 	} else if ((za->za_ttycommon.t_flags & TS_XCLUDE) &&
826*0Sstevel@tonic-gate 						secpolicy_excl_open(cr) != 0) {
827*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
828*0Sstevel@tonic-gate 		if (set_zsoptinit && !(za->za_flags & ISOPEN))
829*0Sstevel@tonic-gate 			zsopinit(zs, &zsops_null);
830*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
831*0Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
832*0Sstevel@tonic-gate 		return (EBUSY);
833*0Sstevel@tonic-gate 	} else if ((*dev & OUTLINE) && !(za->za_flags & ZAS_OUT)) {
834*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
835*0Sstevel@tonic-gate 		if (set_zsoptinit && !(za->za_flags & ISOPEN))
836*0Sstevel@tonic-gate 			zsopinit(zs, &zsops_null);
837*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
838*0Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
839*0Sstevel@tonic-gate 		return (EBUSY);
840*0Sstevel@tonic-gate 	}
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	if (*dev & OUTLINE)
843*0Sstevel@tonic-gate 		za->za_flags |= ZAS_OUT;
844*0Sstevel@tonic-gate 	(void) zsmctl(zs, ZS_ON, DMSET);
845*0Sstevel@tonic-gate 
846*0Sstevel@tonic-gate 	/*
847*0Sstevel@tonic-gate 	 * Check carrier.
848*0Sstevel@tonic-gate 	 */
849*0Sstevel@tonic-gate 	if ((za->za_ttycommon.t_flags & TS_SOFTCAR) ||
850*0Sstevel@tonic-gate 	    (zsmctl(zs, 0, DMGET) & ZSRR0_CD))
851*0Sstevel@tonic-gate 		za->za_flags |= ZAS_CARR_ON;
852*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate 	/*
855*0Sstevel@tonic-gate 	 * If FNDELAY and FNONBLOCK are clear, block until carrier up.
856*0Sstevel@tonic-gate 	 * Quit on interrupt.
857*0Sstevel@tonic-gate 	 */
858*0Sstevel@tonic-gate 	if (!(flag & (FNDELAY|FNONBLOCK)) &&
859*0Sstevel@tonic-gate 	    !(za->za_ttycommon.t_cflag & CLOCAL)) {
860*0Sstevel@tonic-gate 		if (!(za->za_flags & (ZAS_CARR_ON|ZAS_OUT)) ||
861*0Sstevel@tonic-gate 		    ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE))) {
862*0Sstevel@tonic-gate 			za->za_flags |= ZAS_WOPEN;
863*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
864*0Sstevel@tonic-gate 			if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_ocexcl) == 0) {
865*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl);
866*0Sstevel@tonic-gate 				if (zs->zs_suspended) {
867*0Sstevel@tonic-gate 					mutex_exit(zs->zs_excl);
868*0Sstevel@tonic-gate 					mutex_exit(zs->zs_ocexcl);
869*0Sstevel@tonic-gate 					(void) ddi_dev_is_needed(zs->zs_dip,
870*0Sstevel@tonic-gate 									0, 1);
871*0Sstevel@tonic-gate 					mutex_enter(zs->zs_ocexcl);
872*0Sstevel@tonic-gate 					mutex_enter(zs->zs_excl);
873*0Sstevel@tonic-gate 				}
874*0Sstevel@tonic-gate 				za->za_flags &= ~ZAS_WOPEN;
875*0Sstevel@tonic-gate 				if (set_zsoptinit && !(za->za_flags & ISOPEN))
876*0Sstevel@tonic-gate 					zsopinit(zs, &zsops_null);
877*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
878*0Sstevel@tonic-gate 				mutex_exit(zs->zs_ocexcl);
879*0Sstevel@tonic-gate 				return (EINTR);
880*0Sstevel@tonic-gate 			}
881*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl);
882*0Sstevel@tonic-gate 			za->za_flags &= ~ZAS_WOPEN;
883*0Sstevel@tonic-gate 			if ((zs->zs_ops == &zsops_null) ||
884*0Sstevel@tonic-gate 			    (zs->zs_ops == &zsops_async))
885*0Sstevel@tonic-gate 				goto again;
886*0Sstevel@tonic-gate 			else {
887*0Sstevel@tonic-gate 				if (set_zsoptinit && !(za->za_flags & ISOPEN))
888*0Sstevel@tonic-gate 					zsopinit(zs, &zsops_null);
889*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
890*0Sstevel@tonic-gate 				mutex_exit(zs->zs_ocexcl);
891*0Sstevel@tonic-gate 				return (EBUSY);
892*0Sstevel@tonic-gate 			}
893*0Sstevel@tonic-gate 		}
894*0Sstevel@tonic-gate 	} else if ((za->za_flags & ZAS_OUT) && !(*dev & OUTLINE)) {
895*0Sstevel@tonic-gate 		if (set_zsoptinit && !(za->za_flags & ISOPEN))
896*0Sstevel@tonic-gate 			zsopinit(zs, &zsops_null);
897*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
898*0Sstevel@tonic-gate 		mutex_exit(zs->zs_ocexcl);
899*0Sstevel@tonic-gate 		return (EBUSY);
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	za->za_ttycommon.t_readq = rq;
903*0Sstevel@tonic-gate 	za->za_ttycommon.t_writeq = WR(rq);
904*0Sstevel@tonic-gate 	rq->q_ptr = WR(rq)->q_ptr = (caddr_t)za;
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	za->za_flags |= ZAS_ISOPEN;
907*0Sstevel@tonic-gate 	ZSA_GETBLOCK(zs, allocbcount);
908*0Sstevel@tonic-gate 	qprocson(rq);
909*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
910*0Sstevel@tonic-gate 	mutex_exit(zs->zs_ocexcl);
911*0Sstevel@tonic-gate 	return (0);
912*0Sstevel@tonic-gate }
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate static void
915*0Sstevel@tonic-gate zs_progress_check(void *arg)
916*0Sstevel@tonic-gate {
917*0Sstevel@tonic-gate 	struct asyncline *za = arg;
918*0Sstevel@tonic-gate 	struct zscom *zs = za->za_common;
919*0Sstevel@tonic-gate 	mblk_t *bp;
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	/*
922*0Sstevel@tonic-gate 	 * We define "progress" as either waiting on a timed break or delay, or
923*0Sstevel@tonic-gate 	 * having had at least one transmitter interrupt.  If none of these are
924*0Sstevel@tonic-gate 	 * true, then just terminate the output and wake up that close thread.
925*0Sstevel@tonic-gate 	 */
926*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
927*0Sstevel@tonic-gate 	if (!(zs->zs_flags & ZS_PROGRESS) &&
928*0Sstevel@tonic-gate 	    !(za->za_flags & (ZAS_BREAK|ZAS_DELAY))) {
929*0Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BUSY;
930*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
931*0Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
932*0Sstevel@tonic-gate 		zs->zs_wr_cur = NULL;
933*0Sstevel@tonic-gate 		zs->zs_wr_lim = NULL;
934*0Sstevel@tonic-gate 		bp = za->za_xmitblk;
935*0Sstevel@tonic-gate 		za->za_xmitblk = NULL;
936*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
937*0Sstevel@tonic-gate 		zs->zs_timer = 0;
938*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
939*0Sstevel@tonic-gate 		if (bp != NULL)
940*0Sstevel@tonic-gate 			freeb(bp);
941*0Sstevel@tonic-gate 		/*
942*0Sstevel@tonic-gate 		 * Since this timer is running, we know that we're in exit(2).
943*0Sstevel@tonic-gate 		 * That means that the user can't possibly be waiting on any
944*0Sstevel@tonic-gate 		 * valid ioctl(2) completion anymore, and we should just flush
945*0Sstevel@tonic-gate 		 * everything.
946*0Sstevel@tonic-gate 		 */
947*0Sstevel@tonic-gate 		flushq(za->za_ttycommon.t_writeq, FLUSHALL);
948*0Sstevel@tonic-gate 		cv_broadcast(&zs->zs_flags_cv);
949*0Sstevel@tonic-gate 	} else {
950*0Sstevel@tonic-gate 		zs->zs_flags &= ~ZS_PROGRESS;
951*0Sstevel@tonic-gate 		zs->zs_timer = timeout(zs_progress_check, za,
952*0Sstevel@tonic-gate 		    drv_usectohz(zs_drain_check));
953*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
954*0Sstevel@tonic-gate 	}
955*0Sstevel@tonic-gate }
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate /*
958*0Sstevel@tonic-gate  * Close routine.
959*0Sstevel@tonic-gate  *
960*0Sstevel@tonic-gate  * Important locking note: the zs_ocexcl lock is not held at all in this
961*0Sstevel@tonic-gate  * routine.  This is intentional.  That lock is used to coordinate multiple
962*0Sstevel@tonic-gate  * simultaneous opens on a stream, and there's no such thing as multiple
963*0Sstevel@tonic-gate  * simultaneous closes on a stream.
964*0Sstevel@tonic-gate  */
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate /*ARGSUSED*/
967*0Sstevel@tonic-gate static int
968*0Sstevel@tonic-gate zsa_close(queue_t *q, int flag)
969*0Sstevel@tonic-gate {
970*0Sstevel@tonic-gate 	struct asyncline *za;
971*0Sstevel@tonic-gate 	struct zscom *zs;
972*0Sstevel@tonic-gate 	int i;
973*0Sstevel@tonic-gate 	mblk_t *bp;
974*0Sstevel@tonic-gate 	timeout_id_t za_zsa_restart_id, za_kick_rcv_id;
975*0Sstevel@tonic-gate 	bufcall_id_t za_bufcid, za_wbufcid;
976*0Sstevel@tonic-gate 	int	 tmp;
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	za = q->q_ptr;
979*0Sstevel@tonic-gate 	ASSERT(za != NULL);
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate 	zs = za->za_common;
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
984*0Sstevel@tonic-gate 	zs->zs_flags |= ZS_CLOSING;
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 	/*
987*0Sstevel@tonic-gate 	 * There are two flavors of break -- timed (M_BREAK or TCSBRK) and
988*0Sstevel@tonic-gate 	 * untimed (TIOCSBRK).  For the timed case, these are enqueued on our
989*0Sstevel@tonic-gate 	 * write queue and there's a timer running, so we don't have to worry
990*0Sstevel@tonic-gate 	 * about them.  For the untimed case, though, the user obviously made a
991*0Sstevel@tonic-gate 	 * mistake, because these are handled immediately.  We'll terminate the
992*0Sstevel@tonic-gate 	 * break now and honor his implicit request by discarding the rest of
993*0Sstevel@tonic-gate 	 * the data.
994*0Sstevel@tonic-gate 	 */
995*0Sstevel@tonic-gate 	if (!(za->za_flags & ZAS_BREAK) && (zs->zs_wreg[5] & ZSWR5_BREAK))
996*0Sstevel@tonic-gate 		goto nodrain;
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	/*
999*0Sstevel@tonic-gate 	 * If the user told us not to delay the close ("non-blocking"), then
1000*0Sstevel@tonic-gate 	 * don't bother trying to drain.
1001*0Sstevel@tonic-gate 	 *
1002*0Sstevel@tonic-gate 	 * If the user did M_STOP (ASYNC_STOPPED), there's no hope of ever
1003*0Sstevel@tonic-gate 	 * getting an M_START (since these messages aren't enqueued), and the
1004*0Sstevel@tonic-gate 	 * only other way to clear the stop condition is by loss of DCD, which
1005*0Sstevel@tonic-gate 	 * would discard the queue data.  Thus, we drop the output data if
1006*0Sstevel@tonic-gate 	 * ASYNC_STOPPED is set.
1007*0Sstevel@tonic-gate 	 */
1008*0Sstevel@tonic-gate 	if ((flag & (FNDELAY|FNONBLOCK)) || (za->za_flags & ZAS_STOPPED))
1009*0Sstevel@tonic-gate 		goto nodrain;
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 	/*
1012*0Sstevel@tonic-gate 	 * If there's any pending output, then we have to try to drain it.
1013*0Sstevel@tonic-gate 	 * There are two main cases to be handled:
1014*0Sstevel@tonic-gate 	 *	- called by close(2): need to drain until done or until
1015*0Sstevel@tonic-gate 	 *	  a signal is received.  No timeout.
1016*0Sstevel@tonic-gate 	 *	- called by exit(2): need to drain while making progress
1017*0Sstevel@tonic-gate 	 *	  or until a timeout occurs.  No signals.
1018*0Sstevel@tonic-gate 	 *
1019*0Sstevel@tonic-gate 	 * If we can't rely on receiving a signal to get us out of a hung
1020*0Sstevel@tonic-gate 	 * session, then we have to use a timer.  In this case, we set a timer
1021*0Sstevel@tonic-gate 	 * to check for progress in sending the output data -- all that we ask
1022*0Sstevel@tonic-gate 	 * (at each interval) is that there's been some progress made.  Since
1023*0Sstevel@tonic-gate 	 * the interrupt routine grabs buffers from the write queue, we can't
1024*0Sstevel@tonic-gate 	 * trust changes in zs_wr_cur.  Instead, we use a progress flag.
1025*0Sstevel@tonic-gate 	 *
1026*0Sstevel@tonic-gate 	 * Note that loss of carrier will cause the output queue to be flushed,
1027*0Sstevel@tonic-gate 	 * and we'll wake up again and finish normally.
1028*0Sstevel@tonic-gate 	 */
1029*0Sstevel@tonic-gate 	if (!ddi_can_receive_sig() && zs_drain_check != 0) {
1030*0Sstevel@tonic-gate 		zs->zs_flags &= ~ZS_PROGRESS;
1031*0Sstevel@tonic-gate 		zs->zs_timer = timeout(zs_progress_check, za,
1032*0Sstevel@tonic-gate 		    drv_usectohz(zs_drain_check));
1033*0Sstevel@tonic-gate 	}
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	while (zs->zs_wr_cur != NULL ||
1036*0Sstevel@tonic-gate 	    za->za_ttycommon.t_writeq->q_first != NULL ||
1037*0Sstevel@tonic-gate 	    (za->za_flags & (ZAS_BUSY|ZAS_DELAY|ZAS_BREAK))) {
1038*0Sstevel@tonic-gate 		if (cv_wait_sig(&zs->zs_flags_cv, zs->zs_excl) == 0)
1039*0Sstevel@tonic-gate 			break;
1040*0Sstevel@tonic-gate 	}
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	if (zs->zs_timer != 0) {
1043*0Sstevel@tonic-gate 		(void) untimeout(zs->zs_timer);
1044*0Sstevel@tonic-gate 		zs->zs_timer = 0;
1045*0Sstevel@tonic-gate 	}
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate nodrain:
1048*0Sstevel@tonic-gate 	/*
1049*0Sstevel@tonic-gate 	 * If break is in progress, stop it.
1050*0Sstevel@tonic-gate 	 */
1051*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
1052*0Sstevel@tonic-gate 	if (zs->zs_wreg[5] & ZSWR5_BREAK) {
1053*0Sstevel@tonic-gate 		SCC_BIC(5, ZSWR5_BREAK);
1054*0Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BREAK;
1055*0Sstevel@tonic-gate 	}
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	za_wbufcid = za->za_wbufcid;
1058*0Sstevel@tonic-gate 	za_bufcid = za->za_bufcid;
1059*0Sstevel@tonic-gate 	za_zsa_restart_id = za->za_zsa_restart_id;
1060*0Sstevel@tonic-gate 	za_kick_rcv_id = za->za_kick_rcv_id;
1061*0Sstevel@tonic-gate 
1062*0Sstevel@tonic-gate 	za->za_wbufcid = za->za_bufcid = 0;
1063*0Sstevel@tonic-gate 	za->za_zsa_restart_id = za->za_kick_rcv_id = 0;
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate 	/*
1066*0Sstevel@tonic-gate 	 * If line has HUPCL set or is incompletely opened,
1067*0Sstevel@tonic-gate 	 * and it is not the console or the keyboard,
1068*0Sstevel@tonic-gate 	 * fix up the modem lines.
1069*0Sstevel@tonic-gate 	 */
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	zsopinit(zs, &zsops_null_async);
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	/*
1074*0Sstevel@tonic-gate 	 * Nobody, zsh or zs can now open this port until
1075*0Sstevel@tonic-gate 	 * zsopinit(zs, &zsops_null);
1076*0Sstevel@tonic-gate 	 *
1077*0Sstevel@tonic-gate 	 */
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 	if ((za->za_dev != rconsdev) && (za->za_dev != kbddev) &&
1080*0Sstevel@tonic-gate 	    (za->za_dev != stdindev) &&
1081*0Sstevel@tonic-gate 	    (((za->za_flags & (ZAS_WOPEN|ZAS_ISOPEN)) != ZAS_ISOPEN) ||
1082*0Sstevel@tonic-gate 	    (za->za_ttycommon.t_cflag & HUPCL))) {
1083*0Sstevel@tonic-gate 		/*
1084*0Sstevel@tonic-gate 		 * If DTR is being held high by softcarrier,
1085*0Sstevel@tonic-gate 		 * set up the ZS_ON set; if not, hang up.
1086*0Sstevel@tonic-gate 		 */
1087*0Sstevel@tonic-gate 		if (zsasoftdtr && (za->za_ttycommon.t_flags & TS_SOFTCAR))
1088*0Sstevel@tonic-gate 			(void) zsmctl(zs, ZS_ON, DMSET);
1089*0Sstevel@tonic-gate 		else
1090*0Sstevel@tonic-gate 			(void) zsmctl(zs, ZS_OFF, DMSET);
1091*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
1092*0Sstevel@tonic-gate 		/*
1093*0Sstevel@tonic-gate 		 * Don't let an interrupt in the middle of close
1094*0Sstevel@tonic-gate 		 * bounce us back to the top; just continue
1095*0Sstevel@tonic-gate 		 * closing as if nothing had happened.
1096*0Sstevel@tonic-gate 		 */
1097*0Sstevel@tonic-gate 		tmp = cv_timedwait_sig(&zs->zs_flags_cv, zs->zs_excl,
1098*0Sstevel@tonic-gate 		    ddi_get_lbolt() + drv_usectohz(10000));
1099*0Sstevel@tonic-gate 		if (zs->zs_suspended) {
1100*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
1101*0Sstevel@tonic-gate 			(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
1102*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl);
1103*0Sstevel@tonic-gate 		}
1104*0Sstevel@tonic-gate 		if (tmp == 0)
1105*0Sstevel@tonic-gate 			goto out;
1106*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
1107*0Sstevel@tonic-gate 	}
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	/*
1110*0Sstevel@tonic-gate 	 * If nobody's now using it, turn off receiver interrupts.
1111*0Sstevel@tonic-gate 	 */
1112*0Sstevel@tonic-gate 	if ((za->za_flags & (ZAS_ISOPEN|ZAS_WOPEN)) == 0)
1113*0Sstevel@tonic-gate 		SCC_BIC(1, ZSWR1_RIE);
1114*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate out:
1117*0Sstevel@tonic-gate 	/*
1118*0Sstevel@tonic-gate 	 * Clear out device state.
1119*0Sstevel@tonic-gate 	 */
1120*0Sstevel@tonic-gate 	ttycommon_close(&za->za_ttycommon);
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	za->za_ttycommon.t_readq = NULL;
1123*0Sstevel@tonic-gate 	za->za_ttycommon.t_writeq = NULL;
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
1126*0Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
1127*0Sstevel@tonic-gate 	zs->zs_wr_cur = NULL;
1128*0Sstevel@tonic-gate 	zs->zs_wr_lim = NULL;
1129*0Sstevel@tonic-gate 	bp = za->za_xmitblk;
1130*0Sstevel@tonic-gate 	za->za_xmitblk = NULL;
1131*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
1132*0Sstevel@tonic-gate 	if (bp)
1133*0Sstevel@tonic-gate 		freemsg(bp);
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
1136*0Sstevel@tonic-gate 	zs->zs_rd_cur = NULL;
1137*0Sstevel@tonic-gate 	zs->zs_rd_lim = NULL;
1138*0Sstevel@tonic-gate 	bp = za->za_rcvblk;
1139*0Sstevel@tonic-gate 	za->za_rcvblk = NULL;
1140*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
1141*0Sstevel@tonic-gate 	if (bp)
1142*0Sstevel@tonic-gate 		freemsg(bp);
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	for (i = 0; i < zsa_rstandby; i++) {
1145*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
1146*0Sstevel@tonic-gate 		bp = za->za_rstandby[i];
1147*0Sstevel@tonic-gate 		za->za_rstandby[i] = NULL;
1148*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
1149*0Sstevel@tonic-gate 		if (bp)
1150*0Sstevel@tonic-gate 			freemsg(bp);
1151*0Sstevel@tonic-gate 	}
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 	if (za->za_soft_active || za->za_kick_active) {
1154*0Sstevel@tonic-gate 		zs->zs_flags |= ZS_CLOSED;
1155*0Sstevel@tonic-gate 		while (za->za_soft_active || za->za_kick_active)
1156*0Sstevel@tonic-gate 			cv_wait(&zs->zs_flags_cv, zs->zs_excl);
1157*0Sstevel@tonic-gate 	}
1158*0Sstevel@tonic-gate 	if (zs->zs_suspended) {
1159*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1160*0Sstevel@tonic-gate 		(void) ddi_dev_is_needed(zs->zs_dip, 0, 1);
1161*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1162*0Sstevel@tonic-gate 	}
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate 	ZSA_FLUSHQ;
1165*0Sstevel@tonic-gate 	bzero(za, sizeof (struct asyncline));
1166*0Sstevel@tonic-gate 	qprocsoff(q);
1167*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
1168*0Sstevel@tonic-gate 
1169*0Sstevel@tonic-gate 	/*
1170*0Sstevel@tonic-gate 	 * Cancel outstanding "bufcall" request.
1171*0Sstevel@tonic-gate 	 */
1172*0Sstevel@tonic-gate 	if (za_wbufcid)
1173*0Sstevel@tonic-gate 		unbufcall(za_wbufcid);
1174*0Sstevel@tonic-gate 	if (za_bufcid)
1175*0Sstevel@tonic-gate 		unbufcall(za_bufcid);
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	/*
1178*0Sstevel@tonic-gate 	 * Cancel outstanding timeout.
1179*0Sstevel@tonic-gate 	 */
1180*0Sstevel@tonic-gate 	if (za_zsa_restart_id)
1181*0Sstevel@tonic-gate 		(void) untimeout(za_zsa_restart_id);
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	if (za_kick_rcv_id)
1184*0Sstevel@tonic-gate 		(void) untimeout(za_kick_rcv_id);
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
1187*0Sstevel@tonic-gate 	zsopinit(zs, &zsops_null);
1188*0Sstevel@tonic-gate 	cv_broadcast(&zs->zs_flags_cv);
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 	/* Mark device as available for power management */
1191*0Sstevel@tonic-gate 	(void) pm_idle_component(zs->zs_dip, zs->zs_unit%2+1);
1192*0Sstevel@tonic-gate 	return (0);
1193*0Sstevel@tonic-gate }
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate /*
1196*0Sstevel@tonic-gate  * Put procedure for write queue.
1197*0Sstevel@tonic-gate  * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;
1198*0Sstevel@tonic-gate  * set the flow control character for M_STOPI and M_STARTI messages;
1199*0Sstevel@tonic-gate  * queue up M_BREAK, M_DELAY, and M_DATA messages for processing
1200*0Sstevel@tonic-gate  * by the start routine, and then call the start routine; discard
1201*0Sstevel@tonic-gate  * everything else. Note that this driver does not incorporate any
1202*0Sstevel@tonic-gate  * mechanism to negotiate to handle the canonicalization process.
1203*0Sstevel@tonic-gate  * It expects that these functions are handled in upper module(s),
1204*0Sstevel@tonic-gate  * as we do in ldterm.
1205*0Sstevel@tonic-gate  */
1206*0Sstevel@tonic-gate static void
1207*0Sstevel@tonic-gate zsa_wput(queue_t *q, mblk_t *mp)
1208*0Sstevel@tonic-gate {
1209*0Sstevel@tonic-gate 	register struct asyncline	*za;
1210*0Sstevel@tonic-gate 	register struct zscom		*zs;
1211*0Sstevel@tonic-gate 	register struct copyresp	*resp;
1212*0Sstevel@tonic-gate 	register mblk_t			*bp = NULL;
1213*0Sstevel@tonic-gate 	int				error;
1214*0Sstevel@tonic-gate 	struct iocblk			*iocp;
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate 	za = (struct asyncline *)q->q_ptr;
1217*0Sstevel@tonic-gate 	zs = za->za_common;
1218*0Sstevel@tonic-gate 	if (zs->zs_flags & ZS_NEEDSOFT) {
1219*0Sstevel@tonic-gate 		zs->zs_flags &= ~ZS_NEEDSOFT;
1220*0Sstevel@tonic-gate 		(void) zsa_softint(zs);
1221*0Sstevel@tonic-gate 	}
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 	case M_STOP:
1226*0Sstevel@tonic-gate 		/*
1227*0Sstevel@tonic-gate 		 * Since we don't do real DMA, we can just let the
1228*0Sstevel@tonic-gate 		 * chip coast to a stop after applying the brakes.
1229*0Sstevel@tonic-gate 		 */
1230*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1231*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
1232*0Sstevel@tonic-gate 		za->za_flags |= ZAS_STOPPED;
1233*0Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
1234*0Sstevel@tonic-gate 			za->za_flags &= ~ZAS_BUSY;
1235*0Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
1236*0Sstevel@tonic-gate 			bp = za->za_xmitblk;
1237*0Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
1238*0Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
1239*0Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
1240*0Sstevel@tonic-gate 			za->za_xmitblk = NULL;
1241*0Sstevel@tonic-gate 		}
1242*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
1243*0Sstevel@tonic-gate 		if (bp)
1244*0Sstevel@tonic-gate 			(void) putbq(q, bp);
1245*0Sstevel@tonic-gate 		freemsg(mp);
1246*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1247*0Sstevel@tonic-gate 		break;
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate 	case M_START:
1250*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1251*0Sstevel@tonic-gate 		if (za->za_flags & ZAS_STOPPED) {
1252*0Sstevel@tonic-gate 			za->za_flags &= ~ZAS_STOPPED;
1253*0Sstevel@tonic-gate 			/*
1254*0Sstevel@tonic-gate 			 * If an output operation is in progress,
1255*0Sstevel@tonic-gate 			 * resume it. Otherwise, prod the start
1256*0Sstevel@tonic-gate 			 * routine.
1257*0Sstevel@tonic-gate 			 */
1258*0Sstevel@tonic-gate 			zsa_start(zs);
1259*0Sstevel@tonic-gate 		}
1260*0Sstevel@tonic-gate 		freemsg(mp);
1261*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1262*0Sstevel@tonic-gate 		break;
1263*0Sstevel@tonic-gate 
1264*0Sstevel@tonic-gate 	case M_IOCTL:
1265*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1266*0Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
1267*0Sstevel@tonic-gate 
1268*0Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
1269*0Sstevel@tonic-gate 
1270*0Sstevel@tonic-gate 		case TIOCGPPS:
1271*0Sstevel@tonic-gate 			/*
1272*0Sstevel@tonic-gate 			 * Get PPS state.
1273*0Sstevel@tonic-gate 			 */
1274*0Sstevel@tonic-gate 			if (mp->b_cont != NULL)
1275*0Sstevel@tonic-gate 				freemsg(mp->b_cont);
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 			mp->b_cont = allocb(sizeof (int), BPRI_HI);
1278*0Sstevel@tonic-gate 			if (mp->b_cont == NULL) {
1279*0Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
1280*0Sstevel@tonic-gate 				iocp->ioc_error = ENOMEM;
1281*0Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
1282*0Sstevel@tonic-gate 				break;
1283*0Sstevel@tonic-gate 			}
1284*0Sstevel@tonic-gate 			if (za->za_pps)
1285*0Sstevel@tonic-gate 				*(int *)mp->b_cont->b_wptr = 1;
1286*0Sstevel@tonic-gate 			else
1287*0Sstevel@tonic-gate 				*(int *)mp->b_cont->b_wptr = 0;
1288*0Sstevel@tonic-gate 			mp->b_cont->b_wptr += sizeof (int);
1289*0Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
1290*0Sstevel@tonic-gate 			iocp->ioc_count = sizeof (int);
1291*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1292*0Sstevel@tonic-gate 			break;
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate 		case TIOCSPPS:
1295*0Sstevel@tonic-gate 			/*
1296*0Sstevel@tonic-gate 			 * Set PPS state.
1297*0Sstevel@tonic-gate 			 */
1298*0Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (int));
1299*0Sstevel@tonic-gate 			if (error != 0) {
1300*0Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
1301*0Sstevel@tonic-gate 				iocp->ioc_error = error;
1302*0Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
1303*0Sstevel@tonic-gate 				break;
1304*0Sstevel@tonic-gate 			}
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 			za->za_pps = (*(int *)mp->b_cont->b_rptr != 0);
1307*0Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
1308*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1309*0Sstevel@tonic-gate 			break;
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 		case TIOCGPPSEV:
1312*0Sstevel@tonic-gate 		{
1313*0Sstevel@tonic-gate 			/*
1314*0Sstevel@tonic-gate 			 * Get PPS event data.
1315*0Sstevel@tonic-gate 			 */
1316*0Sstevel@tonic-gate 			void *buf;
1317*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1318*0Sstevel@tonic-gate 			struct ppsclockev32 p32;
1319*0Sstevel@tonic-gate #endif
1320*0Sstevel@tonic-gate 
1321*0Sstevel@tonic-gate 			if (mp->b_cont != NULL) {
1322*0Sstevel@tonic-gate 				freemsg(mp->b_cont);
1323*0Sstevel@tonic-gate 				mp->b_cont = NULL;
1324*0Sstevel@tonic-gate 			}
1325*0Sstevel@tonic-gate 			if (za->za_pps == NULL) {
1326*0Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
1327*0Sstevel@tonic-gate 				iocp->ioc_error = ENXIO;
1328*0Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
1329*0Sstevel@tonic-gate 				break;
1330*0Sstevel@tonic-gate 			}
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1333*0Sstevel@tonic-gate 			if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
1334*0Sstevel@tonic-gate 				TIMEVAL_TO_TIMEVAL32(&p32.tv, &ppsclockev.tv);
1335*0Sstevel@tonic-gate 				p32.serial = ppsclockev.serial;
1336*0Sstevel@tonic-gate 				buf = &p32;
1337*0Sstevel@tonic-gate 				iocp->ioc_count = sizeof (struct ppsclockev32);
1338*0Sstevel@tonic-gate 			} else
1339*0Sstevel@tonic-gate #endif
1340*0Sstevel@tonic-gate 			{
1341*0Sstevel@tonic-gate 				buf = &ppsclockev;
1342*0Sstevel@tonic-gate 				iocp->ioc_count = sizeof (struct ppsclockev);
1343*0Sstevel@tonic-gate 			}
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 			if ((bp = allocb(iocp->ioc_count, BPRI_HI)) == NULL) {
1346*0Sstevel@tonic-gate 				mp->b_datap->db_type = M_IOCNAK;
1347*0Sstevel@tonic-gate 				iocp->ioc_error = ENOMEM;
1348*0Sstevel@tonic-gate 				ZSA_QREPLY(q, mp);
1349*0Sstevel@tonic-gate 				break;
1350*0Sstevel@tonic-gate 			}
1351*0Sstevel@tonic-gate 			mp->b_cont = bp;
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 			bcopy(buf, bp->b_wptr, iocp->ioc_count);
1354*0Sstevel@tonic-gate 			bp->b_wptr += iocp->ioc_count;
1355*0Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
1356*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1357*0Sstevel@tonic-gate 			break;
1358*0Sstevel@tonic-gate 		}
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate 		case TCSETSW:
1361*0Sstevel@tonic-gate 		case TCSETSF:
1362*0Sstevel@tonic-gate 		case TCSETAW:
1363*0Sstevel@tonic-gate 		case TCSETAF:
1364*0Sstevel@tonic-gate 		case TCSBRK:
1365*0Sstevel@tonic-gate 			/*
1366*0Sstevel@tonic-gate 			 * The changes do not take effect until all
1367*0Sstevel@tonic-gate 			 * output queued before them is drained.
1368*0Sstevel@tonic-gate 			 * Put this message on the queue, so that
1369*0Sstevel@tonic-gate 			 * "zsa_start" will see it when it's done
1370*0Sstevel@tonic-gate 			 * with the output before it. Poke the
1371*0Sstevel@tonic-gate 			 * start routine, just in case.
1372*0Sstevel@tonic-gate 			 */
1373*0Sstevel@tonic-gate 			(void) putq(q, mp);
1374*0Sstevel@tonic-gate 			zsa_start(zs);
1375*0Sstevel@tonic-gate 			break;
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 		default:
1378*0Sstevel@tonic-gate 			/*
1379*0Sstevel@tonic-gate 			 * Do it now.
1380*0Sstevel@tonic-gate 			 */
1381*0Sstevel@tonic-gate 			zsa_ioctl(za, q, mp);
1382*0Sstevel@tonic-gate 			break;
1383*0Sstevel@tonic-gate 		}
1384*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1385*0Sstevel@tonic-gate 		break;
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate 
1388*0Sstevel@tonic-gate 	case M_IOCDATA:
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1391*0Sstevel@tonic-gate 		resp = (struct copyresp *)mp->b_rptr;
1392*0Sstevel@tonic-gate 		if (resp->cp_rval) {
1393*0Sstevel@tonic-gate 			/*
1394*0Sstevel@tonic-gate 			 * Just free message on failure.
1395*0Sstevel@tonic-gate 			 */
1396*0Sstevel@tonic-gate 			freemsg(mp);
1397*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
1398*0Sstevel@tonic-gate 			break;
1399*0Sstevel@tonic-gate 		}
1400*0Sstevel@tonic-gate 		switch (resp->cp_cmd) {
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate 		case TIOCMSET:
1403*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
1404*0Sstevel@tonic-gate 			(void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
1405*0Sstevel@tonic-gate 			    DMSET);
1406*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
1407*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
1408*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1409*0Sstevel@tonic-gate 			break;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 		case TIOCMBIS:
1412*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
1413*0Sstevel@tonic-gate 			(void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
1414*0Sstevel@tonic-gate 			    DMBIS);
1415*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
1416*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
1417*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1418*0Sstevel@tonic-gate 			break;
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 		case TIOCMBIC:
1421*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
1422*0Sstevel@tonic-gate 			(void) zsmctl(zs, dmtozs(*(int *)mp->b_cont->b_rptr),
1423*0Sstevel@tonic-gate 			    DMBIC);
1424*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
1425*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
1426*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1427*0Sstevel@tonic-gate 			break;
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 		case TIOCMGET:
1430*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
1431*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1432*0Sstevel@tonic-gate 			break;
1433*0Sstevel@tonic-gate 
1434*0Sstevel@tonic-gate 		default:
1435*0Sstevel@tonic-gate 			freemsg(mp);
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 		}
1438*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1439*0Sstevel@tonic-gate 		break;
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 
1442*0Sstevel@tonic-gate 	case M_FLUSH:
1443*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1444*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 			/*
1447*0Sstevel@tonic-gate 			 * Abort any output in progress.
1448*0Sstevel@tonic-gate 			 */
1449*0Sstevel@tonic-gate 			if (za->za_flags & ZAS_BUSY) {
1450*0Sstevel@tonic-gate 				za->za_flags &= ~ZAS_BUSY;
1451*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
1452*0Sstevel@tonic-gate 				za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
1453*0Sstevel@tonic-gate 				zs->zs_wr_cur = NULL;
1454*0Sstevel@tonic-gate 				zs->zs_wr_lim = NULL;
1455*0Sstevel@tonic-gate 				bp = za->za_xmitblk;
1456*0Sstevel@tonic-gate 				za->za_xmitblk = NULL;
1457*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
1458*0Sstevel@tonic-gate 				if (bp)
1459*0Sstevel@tonic-gate 					freemsg(bp);
1460*0Sstevel@tonic-gate 			}
1461*0Sstevel@tonic-gate 			/*
1462*0Sstevel@tonic-gate 			 * Flush our write queue.
1463*0Sstevel@tonic-gate 			 */
1464*0Sstevel@tonic-gate 			flushq(q, FLUSHDATA);	/* XXX doesn't flush M_DELAY */
1465*0Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;	/* it has been flushed */
1466*0Sstevel@tonic-gate 		}
1467*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
1468*0Sstevel@tonic-gate 			/*
1469*0Sstevel@tonic-gate 			 * Flush any data in the temporary receive buffer
1470*0Sstevel@tonic-gate 			 */
1471*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
1472*0Sstevel@tonic-gate 			if ((za->za_ttycommon.t_flags & TS_SOFTCAR) ||
1473*0Sstevel@tonic-gate 			    (SCC_READ0() & ZSRR0_CD)) {
1474*0Sstevel@tonic-gate 				ZSA_KICK_RCV;
1475*0Sstevel@tonic-gate 			} else {
1476*0Sstevel@tonic-gate 			    ZSA_KICK_RCV;
1477*0Sstevel@tonic-gate 			    if (!(SCC_READ0() & ZSRR0_RX_READY)) {
1478*0Sstevel@tonic-gate 				/*
1479*0Sstevel@tonic-gate 				 * settle time for 1 character shift
1480*0Sstevel@tonic-gate 				 */
1481*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
1482*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
1483*0Sstevel@tonic-gate 				delay(ztdelay(
1484*0Sstevel@tonic-gate 				    SPEED(za->za_ttycommon.t_cflag))/3 + 1);
1485*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl);
1486*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
1487*0Sstevel@tonic-gate 				if (!(SCC_READ0() & ZSRR0_CD))
1488*0Sstevel@tonic-gate 					ZSA_KICK_RCV;
1489*0Sstevel@tonic-gate 			    }
1490*0Sstevel@tonic-gate 			    while ((SCC_READ0() &
1491*0Sstevel@tonic-gate 				(ZSRR0_CD|ZSRR0_RX_READY)) == ZSRR0_RX_READY) {
1492*0Sstevel@tonic-gate 				/*
1493*0Sstevel@tonic-gate 				 * Empty Receiver
1494*0Sstevel@tonic-gate 				 */
1495*0Sstevel@tonic-gate 				(void) SCC_READDATA();
1496*0Sstevel@tonic-gate 			    }
1497*0Sstevel@tonic-gate 			}
1498*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
1499*0Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
1500*0Sstevel@tonic-gate 			ZSA_QREPLY(q, mp);
1501*0Sstevel@tonic-gate 			/*
1502*0Sstevel@tonic-gate 			 * give the read queues a crack at it
1503*0Sstevel@tonic-gate 			 */
1504*0Sstevel@tonic-gate 		} else
1505*0Sstevel@tonic-gate 			freemsg(mp);
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 		/*
1508*0Sstevel@tonic-gate 		 * We must make sure we process messages that survive the
1509*0Sstevel@tonic-gate 		 * write-side flush. Without this call, the close protocol
1510*0Sstevel@tonic-gate 		 * with ldterm can hang forever.  (ldterm will have sent us a
1511*0Sstevel@tonic-gate 		 * TCSBRK ioctl that it expects a response to.)
1512*0Sstevel@tonic-gate 		 */
1513*0Sstevel@tonic-gate 		zsa_start(zs);
1514*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1515*0Sstevel@tonic-gate 		break;
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 	case M_BREAK:
1518*0Sstevel@tonic-gate 	case M_DELAY:
1519*0Sstevel@tonic-gate 	case M_DATA:
1520*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1521*0Sstevel@tonic-gate 		/*
1522*0Sstevel@tonic-gate 		 * Queue the message up to be transmitted,
1523*0Sstevel@tonic-gate 		 * and poke the start routine.
1524*0Sstevel@tonic-gate 		 */
1525*0Sstevel@tonic-gate 		(void) putq(q, mp);
1526*0Sstevel@tonic-gate 		zsa_start(zs);
1527*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1528*0Sstevel@tonic-gate 		break;
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 	case M_STOPI:
1531*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1532*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
1533*0Sstevel@tonic-gate 		za->za_flowc = za->za_ttycommon.t_stopc;
1534*0Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
1535*0Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
1536*0Sstevel@tonic-gate 			bp = za->za_xmitblk;
1537*0Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
1538*0Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
1539*0Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
1540*0Sstevel@tonic-gate 			za->za_xmitblk = NULL;
1541*0Sstevel@tonic-gate 		}
1542*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
1543*0Sstevel@tonic-gate 		if (bp)
1544*0Sstevel@tonic-gate 			(void) putbq(q, bp);
1545*0Sstevel@tonic-gate 		else
1546*0Sstevel@tonic-gate 			zsa_start(zs);		/* poke the start routine */
1547*0Sstevel@tonic-gate 		freemsg(mp);
1548*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1549*0Sstevel@tonic-gate 		break;
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 	case M_STARTI:
1552*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
1553*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
1554*0Sstevel@tonic-gate 		za->za_flowc = za->za_ttycommon.t_startc;
1555*0Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
1556*0Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
1557*0Sstevel@tonic-gate 			bp = za->za_xmitblk;
1558*0Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
1559*0Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
1560*0Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
1561*0Sstevel@tonic-gate 			za->za_xmitblk = NULL;
1562*0Sstevel@tonic-gate 		}
1563*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
1564*0Sstevel@tonic-gate 		if (bp)
1565*0Sstevel@tonic-gate 			(void) putbq(q, bp);
1566*0Sstevel@tonic-gate 		else
1567*0Sstevel@tonic-gate 			zsa_start(zs);		/* poke the start routine */
1568*0Sstevel@tonic-gate 		freemsg(mp);
1569*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
1570*0Sstevel@tonic-gate 		break;
1571*0Sstevel@tonic-gate 
1572*0Sstevel@tonic-gate 	case M_CTL:
1573*0Sstevel@tonic-gate 		if (MBLKL(mp) >= sizeof (struct iocblk) &&
1574*0Sstevel@tonic-gate 		    ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) {
1575*0Sstevel@tonic-gate 			((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX;
1576*0Sstevel@tonic-gate 			qreply(q, mp);
1577*0Sstevel@tonic-gate 		} else {
1578*0Sstevel@tonic-gate 			/*
1579*0Sstevel@tonic-gate 			 * These MC_SERVICE type messages are used by upper
1580*0Sstevel@tonic-gate 			 * modules to tell this driver to send input up
1581*0Sstevel@tonic-gate 			 * immediately, or that it can wait for normal
1582*0Sstevel@tonic-gate 			 * processing that may or may not be done. Sun
1583*0Sstevel@tonic-gate 			 * requires these for the mouse module.
1584*0Sstevel@tonic-gate 			 */
1585*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl);
1586*0Sstevel@tonic-gate 			switch (*mp->b_rptr) {
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 			case MC_SERVICEIMM:
1589*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
1590*0Sstevel@tonic-gate 				za->za_flags |= ZAS_SERVICEIMM;
1591*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
1592*0Sstevel@tonic-gate 				break;
1593*0Sstevel@tonic-gate 
1594*0Sstevel@tonic-gate 			case MC_SERVICEDEF:
1595*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
1596*0Sstevel@tonic-gate 				za->za_flags &= ~ZAS_SERVICEIMM;
1597*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
1598*0Sstevel@tonic-gate 				break;
1599*0Sstevel@tonic-gate 			}
1600*0Sstevel@tonic-gate 			freemsg(mp);
1601*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
1602*0Sstevel@tonic-gate 		}
1603*0Sstevel@tonic-gate 		break;
1604*0Sstevel@tonic-gate 
1605*0Sstevel@tonic-gate 	default:
1606*0Sstevel@tonic-gate 		/*
1607*0Sstevel@tonic-gate 		 * "No, I don't want a subscription to Chain Store Age,
1608*0Sstevel@tonic-gate 		 * thank you anyway."
1609*0Sstevel@tonic-gate 		 */
1610*0Sstevel@tonic-gate 		freemsg(mp);
1611*0Sstevel@tonic-gate 		break;
1612*0Sstevel@tonic-gate 	}
1613*0Sstevel@tonic-gate }
1614*0Sstevel@tonic-gate 
1615*0Sstevel@tonic-gate /*
1616*0Sstevel@tonic-gate  * zs read service procedure
1617*0Sstevel@tonic-gate  */
1618*0Sstevel@tonic-gate static void
1619*0Sstevel@tonic-gate zsa_rsrv(queue_t *q)
1620*0Sstevel@tonic-gate {
1621*0Sstevel@tonic-gate 	struct asyncline	*za;
1622*0Sstevel@tonic-gate 	struct zscom		*zs;
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 	if (((za = (struct asyncline *)q->q_ptr) != NULL) &&
1625*0Sstevel@tonic-gate 	    (za->za_ttycommon.t_cflag & CRTSXOFF)) {
1626*0Sstevel@tonic-gate 		zs = za->za_common;
1627*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
1628*0Sstevel@tonic-gate 		ZSSETSOFT(zs);
1629*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
1630*0Sstevel@tonic-gate 	}
1631*0Sstevel@tonic-gate }
1632*0Sstevel@tonic-gate 
1633*0Sstevel@tonic-gate /*
1634*0Sstevel@tonic-gate  * Transmitter interrupt service routine.
1635*0Sstevel@tonic-gate  * If there's more data to transmit in the current pseudo-DMA block,
1636*0Sstevel@tonic-gate  * and the transmitter is ready, send the next character if output
1637*0Sstevel@tonic-gate  * is not stopped or draining.
1638*0Sstevel@tonic-gate  * Otherwise, queue up a soft interrupt.
1639*0Sstevel@tonic-gate  */
1640*0Sstevel@tonic-gate static void
1641*0Sstevel@tonic-gate zsa_txint(struct zscom *zs)
1642*0Sstevel@tonic-gate {
1643*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
1644*0Sstevel@tonic-gate 	register uchar_t *wr_cur;
1645*0Sstevel@tonic-gate 	register uchar_t s0;
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 	s0 = SCC_READ0();
1648*0Sstevel@tonic-gate 
1649*0Sstevel@tonic-gate 	if ((wr_cur = zs->zs_wr_cur) != NULL) {
1650*0Sstevel@tonic-gate 		if (wr_cur < zs->zs_wr_lim) {
1651*0Sstevel@tonic-gate 			if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
1652*0Sstevel@tonic-gate 			    !(s0 & ZSRR0_CTS)) {
1653*0Sstevel@tonic-gate 				SCC_WRITE0(ZSWR0_RESET_TXINT);
1654*0Sstevel@tonic-gate 				za->za_rcv_flags_mask |= DO_RETRANSMIT;
1655*0Sstevel@tonic-gate 				return;
1656*0Sstevel@tonic-gate 			}
1657*0Sstevel@tonic-gate 			SCC_WRITEDATA(*wr_cur++);
1658*0Sstevel@tonic-gate #ifdef ZSA_DEBUG
1659*0Sstevel@tonic-gate 			za->za_wr++;
1660*0Sstevel@tonic-gate #endif
1661*0Sstevel@tonic-gate 			zs->zs_wr_cur = wr_cur;
1662*0Sstevel@tonic-gate 			zs->zs_flags |= ZS_PROGRESS;
1663*0Sstevel@tonic-gate 			return;
1664*0Sstevel@tonic-gate 		} else {
1665*0Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
1666*0Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
1667*0Sstevel@tonic-gate 			/*
1668*0Sstevel@tonic-gate 			 * Use the rcv_flags_mask as it is set and
1669*0Sstevel@tonic-gate 			 * test while holding the zs_excl_hi mutex
1670*0Sstevel@tonic-gate 			 */
1671*0Sstevel@tonic-gate 			za->za_rcv_flags_mask |= DO_TRANSMIT;
1672*0Sstevel@tonic-gate 			SCC_WRITE0(ZSWR0_RESET_TXINT);
1673*0Sstevel@tonic-gate 			ZSSETSOFT(zs);
1674*0Sstevel@tonic-gate 			return;
1675*0Sstevel@tonic-gate 		}
1676*0Sstevel@tonic-gate 	}
1677*0Sstevel@tonic-gate 
1678*0Sstevel@tonic-gate 	if (za->za_flowc != '\0' && (!(za->za_flags & ZAS_DRAINING))) {
1679*0Sstevel@tonic-gate 		if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
1680*0Sstevel@tonic-gate 		    !(s0 & ZSRR0_CTS)) {
1681*0Sstevel@tonic-gate 			SCC_WRITE0(ZSWR0_RESET_TXINT);
1682*0Sstevel@tonic-gate 			return;
1683*0Sstevel@tonic-gate 		}
1684*0Sstevel@tonic-gate 		SCC_WRITEDATA(za->za_flowc);
1685*0Sstevel@tonic-gate 		za->za_flowc = '\0';
1686*0Sstevel@tonic-gate 		return;
1687*0Sstevel@tonic-gate 	}
1688*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_TXINT);
1689*0Sstevel@tonic-gate 	/*
1690*0Sstevel@tonic-gate 	 * Set DO_TRANSMIT bit so that the soft interrupt can
1691*0Sstevel@tonic-gate 	 * test it and unset the ZAS_BUSY in za_flags while holding
1692*0Sstevel@tonic-gate 	 * the mutex zs_excl and zs_excl_hi
1693*0Sstevel@tonic-gate 	 */
1694*0Sstevel@tonic-gate 	za->za_rcv_flags_mask |= DO_TRANSMIT;
1695*0Sstevel@tonic-gate 	ZSSETSOFT(zs);
1696*0Sstevel@tonic-gate }
1697*0Sstevel@tonic-gate 
1698*0Sstevel@tonic-gate /*
1699*0Sstevel@tonic-gate  * External/Status interrupt.
1700*0Sstevel@tonic-gate  */
1701*0Sstevel@tonic-gate static void
1702*0Sstevel@tonic-gate zsa_xsint(struct zscom *zs)
1703*0Sstevel@tonic-gate {
1704*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
1705*0Sstevel@tonic-gate 	register uchar_t s0, x0;
1706*0Sstevel@tonic-gate 
1707*0Sstevel@tonic-gate 	s0 = SCC_READ0();
1708*0Sstevel@tonic-gate 	ZSA_R0_LOG(s0);
1709*0Sstevel@tonic-gate 	x0 = s0 ^ za->za_rr0;
1710*0Sstevel@tonic-gate 	za->za_rr0 = s0;
1711*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_STATUS);
1712*0Sstevel@tonic-gate 
1713*0Sstevel@tonic-gate 	/*
1714*0Sstevel@tonic-gate 	 * PPS (Pulse Per Second) support.
1715*0Sstevel@tonic-gate 	 */
1716*0Sstevel@tonic-gate 	if (za->za_pps && (x0 & ZSRR0_CD) && (s0 & ZSRR0_CD)) {
1717*0Sstevel@tonic-gate 		/*
1718*0Sstevel@tonic-gate 		 * This code captures a timestamp at the designated
1719*0Sstevel@tonic-gate 		 * transition of the PPS signal (CD asserted).  The
1720*0Sstevel@tonic-gate 		 * code provides a pointer to the timestamp, as well
1721*0Sstevel@tonic-gate 		 * as the hardware counter value at the capture.
1722*0Sstevel@tonic-gate 		 *
1723*0Sstevel@tonic-gate 		 * Note: the kernel has nano based time values while
1724*0Sstevel@tonic-gate 		 * NTP requires micro based, an in-line fast algorithm
1725*0Sstevel@tonic-gate 		 * to convert nsec to usec is used here -- see hrt2ts()
1726*0Sstevel@tonic-gate 		 * in common/os/timers.c for a full description.
1727*0Sstevel@tonic-gate 		 */
1728*0Sstevel@tonic-gate 		struct timeval *tvp = &ppsclockev.tv;
1729*0Sstevel@tonic-gate 		timespec_t ts;
1730*0Sstevel@tonic-gate 		int nsec, usec;
1731*0Sstevel@tonic-gate 
1732*0Sstevel@tonic-gate 		LED_OFF;
1733*0Sstevel@tonic-gate 		gethrestime(&ts);
1734*0Sstevel@tonic-gate 		LED_ON;
1735*0Sstevel@tonic-gate 		nsec = ts.tv_nsec;
1736*0Sstevel@tonic-gate 		usec = nsec + (nsec >> 2);
1737*0Sstevel@tonic-gate 		usec = nsec + (usec >> 1);
1738*0Sstevel@tonic-gate 		usec = nsec + (usec >> 2);
1739*0Sstevel@tonic-gate 		usec = nsec + (usec >> 4);
1740*0Sstevel@tonic-gate 		usec = nsec - (usec >> 3);
1741*0Sstevel@tonic-gate 		usec = nsec + (usec >> 2);
1742*0Sstevel@tonic-gate 		usec = nsec + (usec >> 3);
1743*0Sstevel@tonic-gate 		usec = nsec + (usec >> 4);
1744*0Sstevel@tonic-gate 		usec = nsec + (usec >> 1);
1745*0Sstevel@tonic-gate 		usec = nsec + (usec >> 6);
1746*0Sstevel@tonic-gate 		tvp->tv_usec = usec >> 10;
1747*0Sstevel@tonic-gate 		tvp->tv_sec = ts.tv_sec;
1748*0Sstevel@tonic-gate 
1749*0Sstevel@tonic-gate 		++ppsclockev.serial;
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate 		/*
1752*0Sstevel@tonic-gate 		 * Because the kernel keeps a high-resolution time, pass the
1753*0Sstevel@tonic-gate 		 * current highres timestamp in tvp and zero in usec.
1754*0Sstevel@tonic-gate 		 */
1755*0Sstevel@tonic-gate 		ddi_hardpps(tvp, 0);
1756*0Sstevel@tonic-gate 	}
1757*0Sstevel@tonic-gate 
1758*0Sstevel@tonic-gate 	ZSA_KICK_RCV;
1759*0Sstevel@tonic-gate 
1760*0Sstevel@tonic-gate 	if ((x0 & ZSRR0_BREAK) && (s0 & ZSRR0_BREAK) == 0) {
1761*0Sstevel@tonic-gate #ifdef SLAVIO_BUG
1762*0Sstevel@tonic-gate 		/*
1763*0Sstevel@tonic-gate 		 * ZSRR0_BREAK turned off.  This means that the break sequence
1764*0Sstevel@tonic-gate 		 * has completed (i.e., the stop bit finally arrived).
1765*0Sstevel@tonic-gate 		 */
1766*0Sstevel@tonic-gate 		if ((s0 & ZSRR0_RX_READY) == 0) {
1767*0Sstevel@tonic-gate 			/*
1768*0Sstevel@tonic-gate 			 * SLAVIO will generate a separate STATUS change
1769*0Sstevel@tonic-gate 			 * interrupt when the break sequence completes.
1770*0Sstevel@tonic-gate 			 * SCC will combine both, taking the higher priority
1771*0Sstevel@tonic-gate 			 * one, the receive.  Should still see the ext/stat.
1772*0Sstevel@tonic-gate 			 * bit in REG3 on SCC.  If no ext/stat, it must be
1773*0Sstevel@tonic-gate 			 * a SLAVIO.
1774*0Sstevel@tonic-gate 			 */
1775*0Sstevel@tonic-gate 			za->za_breakoff = 1;
1776*0Sstevel@tonic-gate 		} else {
1777*0Sstevel@tonic-gate 			/*
1778*0Sstevel@tonic-gate 			 * The NUL character in the receiver is part of the
1779*0Sstevel@tonic-gate 			 * break sequence; it is discarded.
1780*0Sstevel@tonic-gate 			 */
1781*0Sstevel@tonic-gate 			(void) SCC_READDATA(); /* swallow null */
1782*0Sstevel@tonic-gate 		}
1783*0Sstevel@tonic-gate #else /* SLAVIO_BUG */
1784*0Sstevel@tonic-gate 		/*
1785*0Sstevel@tonic-gate 		 * ZSRR0_BREAK turned off.  This means that the break sequence
1786*0Sstevel@tonic-gate 		 * has completed (i.e., the stop bit finally arrived).  The NUL
1787*0Sstevel@tonic-gate 		 * character in the receiver is part of the break sequence;
1788*0Sstevel@tonic-gate 		 * it is discarded.
1789*0Sstevel@tonic-gate 		 */
1790*0Sstevel@tonic-gate 		(void) SCC_READDATA(); /* swallow null */
1791*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */
1792*0Sstevel@tonic-gate 		SCC_WRITE0(ZSWR0_RESET_ERRORS);
1793*0Sstevel@tonic-gate 
1794*0Sstevel@tonic-gate 		/*
1795*0Sstevel@tonic-gate 		 * Note: this will cause an abort if a break occurs on
1796*0Sstevel@tonic-gate 		 * the "keyboard device", regardless of whether the
1797*0Sstevel@tonic-gate 		 * "keyboard device" is a real keyboard or just a
1798*0Sstevel@tonic-gate 		 * terminal on a serial line. This permits you to
1799*0Sstevel@tonic-gate 		 * abort a workstation by unplugging the keyboard,
1800*0Sstevel@tonic-gate 		 * even if the normal abort key sequence isn't working.
1801*0Sstevel@tonic-gate 		 */
1802*0Sstevel@tonic-gate 		if ((za->za_dev == kbddev) ||
1803*0Sstevel@tonic-gate 		    ((za->za_dev == rconsdev) || (za->za_dev == stdindev)) &&
1804*0Sstevel@tonic-gate 		    (abort_enable != KIOCABORTALTERNATE)) {
1805*0Sstevel@tonic-gate 			abort_sequence_enter((char *)NULL);
1806*0Sstevel@tonic-gate 			/*
1807*0Sstevel@tonic-gate 			 * We just broke into the monitor or debugger,
1808*0Sstevel@tonic-gate 			 * ignore the break in this case so whatever
1809*0Sstevel@tonic-gate 			 * random program that was running doesn't get
1810*0Sstevel@tonic-gate 			 * a SIGINT.
1811*0Sstevel@tonic-gate 			 */
1812*0Sstevel@tonic-gate 			return;
1813*0Sstevel@tonic-gate 		}
1814*0Sstevel@tonic-gate 		za->za_break = 1;
1815*0Sstevel@tonic-gate 	}
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate 	/*
1818*0Sstevel@tonic-gate 	 * If hardware flow control is enabled, (re)start output
1819*0Sstevel@tonic-gate 	 * when CTS is reasserted.
1820*0Sstevel@tonic-gate 	 */
1821*0Sstevel@tonic-gate 	if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
1822*0Sstevel@tonic-gate 	    (x0 & ZSRR0_CTS) && (s0 & ZSRR0_CTS) &&
1823*0Sstevel@tonic-gate 	    (za->za_rcv_flags_mask & DO_RETRANSMIT))
1824*0Sstevel@tonic-gate 			za->za_rcv_flags_mask |= DO_TRANSMIT;
1825*0Sstevel@tonic-gate 
1826*0Sstevel@tonic-gate 	za->za_ext = 1;
1827*0Sstevel@tonic-gate 	ZSSETSOFT(zs);
1828*0Sstevel@tonic-gate }
1829*0Sstevel@tonic-gate 
1830*0Sstevel@tonic-gate /*
1831*0Sstevel@tonic-gate  * Receive Interrupt
1832*0Sstevel@tonic-gate  */
1833*0Sstevel@tonic-gate static void
1834*0Sstevel@tonic-gate zsa_rxint(struct zscom *zs)
1835*0Sstevel@tonic-gate {
1836*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
1837*0Sstevel@tonic-gate 	register uchar_t c;
1838*0Sstevel@tonic-gate 	register uchar_t *rd_cur = zs->zs_rd_cur;
1839*0Sstevel@tonic-gate 	register uchar_t *rd_lim = zs->zs_rd_lim;
1840*0Sstevel@tonic-gate 	register mblk_t	*bp;
1841*0Sstevel@tonic-gate 	register uint_t	fm = za->za_rcv_flags_mask;
1842*0Sstevel@tonic-gate 
1843*0Sstevel@tonic-gate 
1844*0Sstevel@tonic-gate #ifdef ZSA_DEBUG
1845*0Sstevel@tonic-gate 	za->za_rd++;
1846*0Sstevel@tonic-gate #endif
1847*0Sstevel@tonic-gate 	c = (fm >> 16) & (SCC_READDATA());
1848*0Sstevel@tonic-gate 
1849*0Sstevel@tonic-gate 	/*
1850*0Sstevel@tonic-gate 	 * Check for character break sequence
1851*0Sstevel@tonic-gate 	 */
1852*0Sstevel@tonic-gate 	if ((abort_enable == KIOCABORTALTERNATE) && (za->za_dev == rconsdev)) {
1853*0Sstevel@tonic-gate 		if (abort_charseq_recognize(c))
1854*0Sstevel@tonic-gate 			abort_sequence_enter((char *)NULL);
1855*0Sstevel@tonic-gate 	}
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate 	if (!rd_cur) {
1858*0Sstevel@tonic-gate #ifdef SLAVIO_BUG
1859*0Sstevel@tonic-gate 		/*
1860*0Sstevel@tonic-gate 		 * SLAVIO generates FE for the start of break and
1861*0Sstevel@tonic-gate 		 * during break when parity is set.  End of break is
1862*0Sstevel@tonic-gate 		 * detected when the first character is received.
1863*0Sstevel@tonic-gate 		 * This character is always garbage and is thrown away.
1864*0Sstevel@tonic-gate 		 */
1865*0Sstevel@tonic-gate 		if (za->za_slav_break) {
1866*0Sstevel@tonic-gate 			za->za_slav_break = 0;
1867*0Sstevel@tonic-gate 			za->za_rr0 |= ZSRR0_BREAK;
1868*0Sstevel@tonic-gate 			zsa_xsint(zs);
1869*0Sstevel@tonic-gate 			return;
1870*0Sstevel@tonic-gate 		}
1871*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 		if (c == 0 && (za->za_rr0 & ZSRR0_BREAK)) {
1874*0Sstevel@tonic-gate 			/*
1875*0Sstevel@tonic-gate 			 * A break sequence was under way, and a NUL character
1876*0Sstevel@tonic-gate 			 * was received. Discard the NUL character, as it is
1877*0Sstevel@tonic-gate 			 * part of the break sequence; if ZSRR0_BREAK turned
1878*0Sstevel@tonic-gate 			 * off, indicating that the break sequence has com-
1879*0Sstevel@tonic-gate 			 * pleted, call "zsa_xsint" to properly handle the
1880*0Sstevel@tonic-gate 			 * error. It would appear that External/Status
1881*0Sstevel@tonic-gate 			 * interrupts get lost occasionally, so this ensures
1882*0Sstevel@tonic-gate 			 * that one is delivered.
1883*0Sstevel@tonic-gate 			 */
1884*0Sstevel@tonic-gate 			c = SCC_READ0();
1885*0Sstevel@tonic-gate 			if (!(c & ZSRR0_BREAK))
1886*0Sstevel@tonic-gate 				zsa_xsint(zs);
1887*0Sstevel@tonic-gate 			return;
1888*0Sstevel@tonic-gate 		}
1889*0Sstevel@tonic-gate 
1890*0Sstevel@tonic-gate #ifdef SLAVIO_BUG
1891*0Sstevel@tonic-gate 		if (c == 0 && za->za_breakoff) {
1892*0Sstevel@tonic-gate 			/*
1893*0Sstevel@tonic-gate 			 * A break sequence completed, but SLAVIO generates
1894*0Sstevel@tonic-gate 			 * the NULL character interrupt late, so we throw the
1895*0Sstevel@tonic-gate 			 * NULL away now.
1896*0Sstevel@tonic-gate 			 */
1897*0Sstevel@tonic-gate 			return;
1898*0Sstevel@tonic-gate 		}
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate 		/*
1901*0Sstevel@tonic-gate 		 * make sure it gets cleared.
1902*0Sstevel@tonic-gate 		 */
1903*0Sstevel@tonic-gate 		za->za_breakoff = 0;
1904*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */
1905*0Sstevel@tonic-gate 
1906*0Sstevel@tonic-gate 		ZSA_KICK_RCV;	/* We can have M_BREAK msg */
1907*0Sstevel@tonic-gate 		ZSA_ALLOCB(bp);
1908*0Sstevel@tonic-gate 		if (!bp) {
1909*0Sstevel@tonic-gate 			za->za_sw_overrun++;
1910*0Sstevel@tonic-gate 			ZSSETSOFT(zs);
1911*0Sstevel@tonic-gate 			return;
1912*0Sstevel@tonic-gate 		}
1913*0Sstevel@tonic-gate 		za->za_rcvblk = bp;
1914*0Sstevel@tonic-gate 		zs->zs_rd_cur = rd_cur = bp->b_wptr;
1915*0Sstevel@tonic-gate 		zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim;
1916*0Sstevel@tonic-gate 		if (za->za_kick_rcv_id == 0)
1917*0Sstevel@tonic-gate 			ZSSETSOFT(zs);
1918*0Sstevel@tonic-gate 	}
1919*0Sstevel@tonic-gate 	if (c == 0377 && (fm & DO_ESC)) {
1920*0Sstevel@tonic-gate 		if (rd_lim < rd_cur + 2) {
1921*0Sstevel@tonic-gate 			ZSA_ALLOCB(bp);
1922*0Sstevel@tonic-gate 			ZSA_KICK_RCV;
1923*0Sstevel@tonic-gate 			if (!bp) {
1924*0Sstevel@tonic-gate 				za->za_sw_overrun++;
1925*0Sstevel@tonic-gate 				return;
1926*0Sstevel@tonic-gate 			}
1927*0Sstevel@tonic-gate 			za->za_rcvblk = bp;
1928*0Sstevel@tonic-gate 			zs->zs_rd_cur = rd_cur = bp->b_wptr;
1929*0Sstevel@tonic-gate 			zs->zs_rd_lim = rd_lim = bp->b_datap->db_lim;
1930*0Sstevel@tonic-gate 		}
1931*0Sstevel@tonic-gate 		*rd_cur++ = c;
1932*0Sstevel@tonic-gate 	}
1933*0Sstevel@tonic-gate 
1934*0Sstevel@tonic-gate 
1935*0Sstevel@tonic-gate 	*rd_cur++ = c;
1936*0Sstevel@tonic-gate 	zs->zs_rd_cur = rd_cur;
1937*0Sstevel@tonic-gate 
1938*0Sstevel@tonic-gate 	if (rd_cur == rd_lim) {
1939*0Sstevel@tonic-gate 		ZSA_KICK_RCV;
1940*0Sstevel@tonic-gate 	} else if ((fm & DO_STOPC) && (c == (fm & 0xff))) {
1941*0Sstevel@tonic-gate 		za->za_do_kick_rcv_in_softint = 1;
1942*0Sstevel@tonic-gate 		ZSSETSOFT(zs);
1943*0Sstevel@tonic-gate 	}
1944*0Sstevel@tonic-gate 
1945*0Sstevel@tonic-gate 	if ((za->za_flags & ZAS_SERVICEIMM) || g_nocluster) {
1946*0Sstevel@tonic-gate 		/*
1947*0Sstevel@tonic-gate 		 * Send the data up immediately
1948*0Sstevel@tonic-gate 		 */
1949*0Sstevel@tonic-gate 		ZSA_KICK_RCV;
1950*0Sstevel@tonic-gate 	}
1951*0Sstevel@tonic-gate }
1952*0Sstevel@tonic-gate 
1953*0Sstevel@tonic-gate /*
1954*0Sstevel@tonic-gate  * Special receive condition interrupt handler.
1955*0Sstevel@tonic-gate  */
1956*0Sstevel@tonic-gate static void
1957*0Sstevel@tonic-gate zsa_srint(struct zscom *zs)
1958*0Sstevel@tonic-gate {
1959*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
1960*0Sstevel@tonic-gate 	register short s1;
1961*0Sstevel@tonic-gate 	register uchar_t c;
1962*0Sstevel@tonic-gate 	register uchar_t c1;
1963*0Sstevel@tonic-gate 	register mblk_t *bp = za->za_rcvblk;
1964*0Sstevel@tonic-gate 	register uchar_t *rd_cur = zs->zs_rd_cur;
1965*0Sstevel@tonic-gate 
1966*0Sstevel@tonic-gate 	SCC_READ(1, s1);
1967*0Sstevel@tonic-gate 	if (s1 & (ZSRR1_FE | ZSRR1_PE | ZSRR1_DO)) {
1968*0Sstevel@tonic-gate 		c = SCC_READDATA();	/* swallow bad character */
1969*0Sstevel@tonic-gate 	}
1970*0Sstevel@tonic-gate #ifdef SLAVIO_BUG
1971*0Sstevel@tonic-gate 	/*
1972*0Sstevel@tonic-gate 	 * SLAVIO does not handle breaks properly when parity is enabled.
1973*0Sstevel@tonic-gate 	 *
1974*0Sstevel@tonic-gate 	 * In general, if a null character is received when a framing
1975*0Sstevel@tonic-gate 	 * error occurs then it is a break condition and not a real
1976*0Sstevel@tonic-gate 	 * framing error. The null character must be limited to the
1977*0Sstevel@tonic-gate 	 * number of bits including the parity bit. For example, a 6
1978*0Sstevel@tonic-gate 	 * bit character with parity would be null if the lower 7 bits
1979*0Sstevel@tonic-gate 	 * read from the receive fifo were 0. (The higher order bits are
1980*0Sstevel@tonic-gate 	 * padded with 1 and/or the stop bits.) The only exception to this
1981*0Sstevel@tonic-gate 	 * general rule would be an 8 bit null character with parity being
1982*0Sstevel@tonic-gate 	 * a 1 in the parity bit and a framing error. This exception
1983*0Sstevel@tonic-gate 	 * can be determined by examining the parity error bit in RREG 1.
1984*0Sstevel@tonic-gate 	 *
1985*0Sstevel@tonic-gate 	 * A null character, even parity, 8 bits, no parity error,
1986*0Sstevel@tonic-gate 	 * (0 0000 0000) with framing error is a break condition.
1987*0Sstevel@tonic-gate 	 *
1988*0Sstevel@tonic-gate 	 * A null character, even parity, 8 bits, parity error,
1989*0Sstevel@tonic-gate 	 * (1 0000 0000) with framing error is a framing error.
1990*0Sstevel@tonic-gate 	 *
1991*0Sstevel@tonic-gate 	 * A null character, odd parity, 8 bits, parity error
1992*0Sstevel@tonic-gate 	 * (0 0000 0000) with framing error is a break condition.
1993*0Sstevel@tonic-gate 	 *
1994*0Sstevel@tonic-gate 	 * A null character, odd parity, 8 bits, no parity error,
1995*0Sstevel@tonic-gate 	 * (1 0000 0000) with framing error is a framing error.
1996*0Sstevel@tonic-gate 	 */
1997*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & PARENB) {
1998*0Sstevel@tonic-gate 		switch (za->za_ttycommon.t_cflag & CSIZE) {
1999*0Sstevel@tonic-gate 
2000*0Sstevel@tonic-gate 		case CS5:
2001*0Sstevel@tonic-gate 			c1 = c & 0x3f;
2002*0Sstevel@tonic-gate 			break;
2003*0Sstevel@tonic-gate 
2004*0Sstevel@tonic-gate 		case CS6:
2005*0Sstevel@tonic-gate 			c1 = c & 0x7f;
2006*0Sstevel@tonic-gate 			break;
2007*0Sstevel@tonic-gate 
2008*0Sstevel@tonic-gate 		case CS7:
2009*0Sstevel@tonic-gate 			c1 = c & 0xff;
2010*0Sstevel@tonic-gate 			break;
2011*0Sstevel@tonic-gate 
2012*0Sstevel@tonic-gate 		case CS8:
2013*0Sstevel@tonic-gate 			if ((za->za_ttycommon.t_cflag & PARODD) &&
2014*0Sstevel@tonic-gate 			    !(s1 & ZSRR1_PE))
2015*0Sstevel@tonic-gate 				c1 = 0xff;
2016*0Sstevel@tonic-gate 			else if (!(za->za_ttycommon.t_cflag & PARODD) &&
2017*0Sstevel@tonic-gate 			    (s1 & ZSRR1_PE))
2018*0Sstevel@tonic-gate 				c1 = 0xff;
2019*0Sstevel@tonic-gate 			else
2020*0Sstevel@tonic-gate 				c1 = c;
2021*0Sstevel@tonic-gate 			break;
2022*0Sstevel@tonic-gate 		}
2023*0Sstevel@tonic-gate 
2024*0Sstevel@tonic-gate 		/*
2025*0Sstevel@tonic-gate 		 * We fake start of break condition.
2026*0Sstevel@tonic-gate 		 */
2027*0Sstevel@tonic-gate 		if ((s1 & ZSRR1_FE) && c1 == 0) {
2028*0Sstevel@tonic-gate 			za->za_slav_break = 1;
2029*0Sstevel@tonic-gate 			return;
2030*0Sstevel@tonic-gate 		}
2031*0Sstevel@tonic-gate 	}
2032*0Sstevel@tonic-gate #endif /* SLAVIO_BUG */
2033*0Sstevel@tonic-gate 
2034*0Sstevel@tonic-gate 	if (s1 & ZSRR1_PE) {
2035*0Sstevel@tonic-gate 
2036*0Sstevel@tonic-gate 		/*
2037*0Sstevel@tonic-gate 		 * Mark the parity error so zsa_process will
2038*0Sstevel@tonic-gate 		 * notice it and send it up in an M_BREAK
2039*0Sstevel@tonic-gate 		 * message; ldterm will do the actual parity error
2040*0Sstevel@tonic-gate 		 * processing
2041*0Sstevel@tonic-gate 		 */
2042*0Sstevel@tonic-gate 
2043*0Sstevel@tonic-gate 		if (bp && zs->zs_rd_cur) {	/* M_DATA msg */
2044*0Sstevel@tonic-gate 			ZSA_KICK_RCV;
2045*0Sstevel@tonic-gate 			bp = NULL;
2046*0Sstevel@tonic-gate 		}
2047*0Sstevel@tonic-gate 		if (!bp)
2048*0Sstevel@tonic-gate 			ZSA_ALLOCB(bp);
2049*0Sstevel@tonic-gate 		if (!bp) {
2050*0Sstevel@tonic-gate 			za->za_sw_overrun++;
2051*0Sstevel@tonic-gate 			ZSSETSOFT(zs);
2052*0Sstevel@tonic-gate 		} else {
2053*0Sstevel@tonic-gate 			za->za_rcvblk = bp;
2054*0Sstevel@tonic-gate 			zs->zs_rd_cur = rd_cur = bp->b_wptr;
2055*0Sstevel@tonic-gate 			zs->zs_rd_lim = bp->b_datap->db_lim;
2056*0Sstevel@tonic-gate 			*rd_cur++ = c;
2057*0Sstevel@tonic-gate 			zs->zs_rd_cur = rd_cur;
2058*0Sstevel@tonic-gate 			bp->b_datap->db_type = M_BREAK;
2059*0Sstevel@tonic-gate 			if (bp->b_datap->db_lim <= rd_cur)
2060*0Sstevel@tonic-gate 				ZSA_KICK_RCV;
2061*0Sstevel@tonic-gate 			za->za_do_kick_rcv_in_softint = 1;
2062*0Sstevel@tonic-gate 			ZSSETSOFT(zs);
2063*0Sstevel@tonic-gate 
2064*0Sstevel@tonic-gate 		}
2065*0Sstevel@tonic-gate 	}
2066*0Sstevel@tonic-gate 	SCC_WRITE0(ZSWR0_RESET_ERRORS);
2067*0Sstevel@tonic-gate 	if (s1 & ZSRR1_DO) {
2068*0Sstevel@tonic-gate 		za->za_hw_overrun++;
2069*0Sstevel@tonic-gate 		ZSSETSOFT(zs);
2070*0Sstevel@tonic-gate 	}
2071*0Sstevel@tonic-gate }
2072*0Sstevel@tonic-gate 
2073*0Sstevel@tonic-gate /*
2074*0Sstevel@tonic-gate  * Process software interrupts (or poll)
2075*0Sstevel@tonic-gate  * Crucial points:
2076*0Sstevel@tonic-gate  * 3.	BUG - breaks are handled "out-of-band" - their relative position
2077*0Sstevel@tonic-gate  *	among input events is lost, as well as multiple breaks together.
2078*0Sstevel@tonic-gate  *	This is probably not a problem in practice.
2079*0Sstevel@tonic-gate  */
2080*0Sstevel@tonic-gate static int
2081*0Sstevel@tonic-gate zsa_softint(struct zscom *zs)
2082*0Sstevel@tonic-gate {
2083*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
2084*0Sstevel@tonic-gate 	register uchar_t r0;
2085*0Sstevel@tonic-gate 	register uchar_t za_kick_active;
2086*0Sstevel@tonic-gate 	register int	m_error;
2087*0Sstevel@tonic-gate 	register int	allocbcount = 0;
2088*0Sstevel@tonic-gate 	register int 	do_ttycommon_qfull = 0;
2089*0Sstevel@tonic-gate 	boolean_t	hangup = B_FALSE, unhangup = B_FALSE;
2090*0Sstevel@tonic-gate 	boolean_t	m_break = B_FALSE, wakeup = B_FALSE;
2091*0Sstevel@tonic-gate 	register queue_t *q;
2092*0Sstevel@tonic-gate 	register mblk_t	*bp;
2093*0Sstevel@tonic-gate 	register mblk_t *head = NULL, *tail = NULL;
2094*0Sstevel@tonic-gate 
2095*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
2096*0Sstevel@tonic-gate 	if (zs->zs_suspended || (zs->zs_flags & ZS_CLOSED)) {
2097*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2098*0Sstevel@tonic-gate 		return (0);
2099*0Sstevel@tonic-gate 	}
2100*0Sstevel@tonic-gate 	q = za->za_ttycommon.t_readq;
2101*0Sstevel@tonic-gate 	if (za->za_flags & ZAS_WOPEN && !q) {
2102*0Sstevel@tonic-gate 		if (za->za_ext) {
2103*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2104*0Sstevel@tonic-gate 			r0 = SCC_READ0();
2105*0Sstevel@tonic-gate 			za->za_ext = 0;
2106*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2107*0Sstevel@tonic-gate 			/*
2108*0Sstevel@tonic-gate 			 * carrier up?
2109*0Sstevel@tonic-gate 			 */
2110*0Sstevel@tonic-gate 			if ((r0 & ZSRR0_CD) ||
2111*0Sstevel@tonic-gate 			    (za->za_ttycommon.t_flags & TS_SOFTCAR)) {
2112*0Sstevel@tonic-gate 				/*
2113*0Sstevel@tonic-gate 				 * carrier present
2114*0Sstevel@tonic-gate 				 */
2115*0Sstevel@tonic-gate 				if ((za->za_flags & ZAS_CARR_ON) == 0) {
2116*0Sstevel@tonic-gate 					za->za_flags |= ZAS_CARR_ON;
2117*0Sstevel@tonic-gate 					mutex_exit(zs->zs_excl);
2118*0Sstevel@tonic-gate 					cv_broadcast(&zs->zs_flags_cv);
2119*0Sstevel@tonic-gate 					return (0);
2120*0Sstevel@tonic-gate 				}
2121*0Sstevel@tonic-gate 			}
2122*0Sstevel@tonic-gate 		}
2123*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2124*0Sstevel@tonic-gate 		return (0);
2125*0Sstevel@tonic-gate 	}
2126*0Sstevel@tonic-gate 	q = za->za_ttycommon.t_readq;
2127*0Sstevel@tonic-gate 	if (!q) {
2128*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2129*0Sstevel@tonic-gate 		return (0);
2130*0Sstevel@tonic-gate 	}
2131*0Sstevel@tonic-gate 
2132*0Sstevel@tonic-gate 	m_error = za->za_m_error;
2133*0Sstevel@tonic-gate 	za->za_m_error = 0;
2134*0Sstevel@tonic-gate 
2135*0Sstevel@tonic-gate 	if (za->za_do_kick_rcv_in_softint) {
2136*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
2137*0Sstevel@tonic-gate 		ZSA_KICK_RCV;
2138*0Sstevel@tonic-gate 		za->za_do_kick_rcv_in_softint = 0;
2139*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2140*0Sstevel@tonic-gate 	}
2141*0Sstevel@tonic-gate 
2142*0Sstevel@tonic-gate 	za_kick_active = za->za_kick_active;
2143*0Sstevel@tonic-gate 
2144*0Sstevel@tonic-gate 	while (!za_kick_active) {
2145*0Sstevel@tonic-gate 	    ZSA_SEEQ(bp);
2146*0Sstevel@tonic-gate 	    if (!bp)
2147*0Sstevel@tonic-gate 		break;
2148*0Sstevel@tonic-gate 
2149*0Sstevel@tonic-gate 	    allocbcount++;
2150*0Sstevel@tonic-gate 
2151*0Sstevel@tonic-gate 	    if (bp->b_datap->db_type <= QPCTL) {
2152*0Sstevel@tonic-gate 		if (!(canputnext(q))) {
2153*0Sstevel@tonic-gate 			if (za->za_grace_flow_control >=
2154*0Sstevel@tonic-gate 				zsa_grace_flow_control) {
2155*0Sstevel@tonic-gate 			    if (za->za_ttycommon.t_cflag & CRTSXOFF) {
2156*0Sstevel@tonic-gate 					allocbcount--;
2157*0Sstevel@tonic-gate 					break;
2158*0Sstevel@tonic-gate 			    }
2159*0Sstevel@tonic-gate 			    ZSA_GETQ(bp);
2160*0Sstevel@tonic-gate 			    freemsg(bp);
2161*0Sstevel@tonic-gate 			    do_ttycommon_qfull = 1;
2162*0Sstevel@tonic-gate 			    continue;
2163*0Sstevel@tonic-gate 			} else
2164*0Sstevel@tonic-gate 			    za->za_grace_flow_control++;
2165*0Sstevel@tonic-gate 		} else
2166*0Sstevel@tonic-gate 			za->za_grace_flow_control = 0;
2167*0Sstevel@tonic-gate 	    }
2168*0Sstevel@tonic-gate 	    ZSA_GETQ(bp);
2169*0Sstevel@tonic-gate 	    if (!head) {
2170*0Sstevel@tonic-gate 		head = bp;
2171*0Sstevel@tonic-gate 	    } else {
2172*0Sstevel@tonic-gate 		if (!tail)
2173*0Sstevel@tonic-gate 			tail = head;
2174*0Sstevel@tonic-gate 		tail->b_next = bp;
2175*0Sstevel@tonic-gate 		tail = bp;
2176*0Sstevel@tonic-gate 	    }
2177*0Sstevel@tonic-gate 	}
2178*0Sstevel@tonic-gate 
2179*0Sstevel@tonic-gate 	if (allocbcount)
2180*0Sstevel@tonic-gate 		ZSA_GETBLOCK(zs, allocbcount);
2181*0Sstevel@tonic-gate 
2182*0Sstevel@tonic-gate 	if (za->za_ext) {
2183*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
2184*0Sstevel@tonic-gate 		r0 = SCC_READ0();
2185*0Sstevel@tonic-gate 		za->za_ext = 0;
2186*0Sstevel@tonic-gate 		/*
2187*0Sstevel@tonic-gate 		 * carrier up?
2188*0Sstevel@tonic-gate 		 */
2189*0Sstevel@tonic-gate 		if ((r0 & ZSRR0_CD) ||
2190*0Sstevel@tonic-gate 			(za->za_ttycommon.t_flags & TS_SOFTCAR)) {
2191*0Sstevel@tonic-gate 			/*
2192*0Sstevel@tonic-gate 			 * carrier present
2193*0Sstevel@tonic-gate 			 */
2194*0Sstevel@tonic-gate 			if ((za->za_flags & ZAS_CARR_ON) == 0) {
2195*0Sstevel@tonic-gate 				za->za_flags |= ZAS_CARR_ON;
2196*0Sstevel@tonic-gate 				unhangup = B_TRUE;
2197*0Sstevel@tonic-gate 				wakeup = B_TRUE;
2198*0Sstevel@tonic-gate 			}
2199*0Sstevel@tonic-gate 		} else {
2200*0Sstevel@tonic-gate 			if ((za->za_flags & ZAS_CARR_ON) &&
2201*0Sstevel@tonic-gate 			    !(za->za_ttycommon.t_cflag & CLOCAL)) {
2202*0Sstevel@tonic-gate 				/*
2203*0Sstevel@tonic-gate 				 * Carrier went away.
2204*0Sstevel@tonic-gate 				 * Drop DTR, abort any output in progress,
2205*0Sstevel@tonic-gate 				 * indicate that output is not stopped, and
2206*0Sstevel@tonic-gate 				 * send a hangup notification upstream.
2207*0Sstevel@tonic-gate 				 */
2208*0Sstevel@tonic-gate 				(void) zsmctl(zs, ZSWR5_DTR, DMBIC);
2209*0Sstevel@tonic-gate 				if ((za->za_flags & ZAS_BUSY) &&
2210*0Sstevel@tonic-gate 				    (zs->zs_wr_cur != NULL)) {
2211*0Sstevel@tonic-gate 					zs->zs_wr_cur = NULL;
2212*0Sstevel@tonic-gate 					zs->zs_wr_lim = NULL;
2213*0Sstevel@tonic-gate 				}
2214*0Sstevel@tonic-gate 				hangup = B_TRUE;
2215*0Sstevel@tonic-gate 				wakeup = B_TRUE;
2216*0Sstevel@tonic-gate 				za->za_flags &= ~(ZAS_STOPPED | ZAS_CARR_ON |
2217*0Sstevel@tonic-gate 				    ZAS_BUSY);
2218*0Sstevel@tonic-gate 				za->za_rcv_flags_mask &= ~(DO_TRANSMIT |
2219*0Sstevel@tonic-gate 				    DO_RETRANSMIT);
2220*0Sstevel@tonic-gate 			}
2221*0Sstevel@tonic-gate 		}
2222*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2223*0Sstevel@tonic-gate 		if (hangup && (bp = za->za_xmitblk) != NULL) {
2224*0Sstevel@tonic-gate 			za->za_xmitblk = NULL;
2225*0Sstevel@tonic-gate 			freeb(bp);
2226*0Sstevel@tonic-gate 		}
2227*0Sstevel@tonic-gate 	}
2228*0Sstevel@tonic-gate 
2229*0Sstevel@tonic-gate 	if (za->za_break != 0) {
2230*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
2231*0Sstevel@tonic-gate 		r0 = SCC_READ0();
2232*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2233*0Sstevel@tonic-gate 		if ((r0 & ZSRR0_BREAK) == 0) {
2234*0Sstevel@tonic-gate 			za->za_break = 0;
2235*0Sstevel@tonic-gate 			m_break = B_TRUE;
2236*0Sstevel@tonic-gate 		}
2237*0Sstevel@tonic-gate 	}
2238*0Sstevel@tonic-gate 
2239*0Sstevel@tonic-gate 	/*
2240*0Sstevel@tonic-gate 	 * If a transmission has finished, indicate that it's
2241*0Sstevel@tonic-gate 	 * finished, and start that line up again.
2242*0Sstevel@tonic-gate 	 */
2243*0Sstevel@tonic-gate 
2244*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
2245*0Sstevel@tonic-gate 	if (za->za_rcv_flags_mask & DO_TRANSMIT) {
2246*0Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_TRANSMIT;
2247*0Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BUSY;
2248*0Sstevel@tonic-gate 
2249*0Sstevel@tonic-gate 		if ((za->za_ttycommon.t_cflag & CRTSCTS) &&
2250*0Sstevel@tonic-gate 		    (za->za_rcv_flags_mask & DO_RETRANSMIT) &&
2251*0Sstevel@tonic-gate 		    zs->zs_wr_cur)
2252*0Sstevel@tonic-gate 			bp = NULL;
2253*0Sstevel@tonic-gate 		else {
2254*0Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
2255*0Sstevel@tonic-gate 			bp = za->za_xmitblk;
2256*0Sstevel@tonic-gate 			za->za_xmitblk = 0;
2257*0Sstevel@tonic-gate 		}
2258*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2259*0Sstevel@tonic-gate 		if (bp)
2260*0Sstevel@tonic-gate 			freemsg(bp);
2261*0Sstevel@tonic-gate 		zsa_start(zs);
2262*0Sstevel@tonic-gate 		/* if we didn't start anything, then notify waiters */
2263*0Sstevel@tonic-gate 		if (!(za->za_flags & ZAS_BUSY))
2264*0Sstevel@tonic-gate 			wakeup = B_TRUE;
2265*0Sstevel@tonic-gate 	} else {
2266*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2267*0Sstevel@tonic-gate 	}
2268*0Sstevel@tonic-gate 
2269*0Sstevel@tonic-gate 
2270*0Sstevel@tonic-gate 	/*
2271*0Sstevel@tonic-gate 	 * A note about these overrun bits: all they do is *tell* someone
2272*0Sstevel@tonic-gate 	 * about an error- They do not track multiple errors. In fact,
2273*0Sstevel@tonic-gate 	 * you could consider them latched register bits if you like.
2274*0Sstevel@tonic-gate 	 * We are only interested in printing the error message once for
2275*0Sstevel@tonic-gate 	 * any cluster of overrun errrors.
2276*0Sstevel@tonic-gate 	 */
2277*0Sstevel@tonic-gate 	if ((!za->za_kick_rcv_id) && (zs->zs_rd_cur || za_kick_active)) {
2278*0Sstevel@tonic-gate 	    if (g_zsticks)
2279*0Sstevel@tonic-gate 		za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs, g_zsticks);
2280*0Sstevel@tonic-gate 	    else
2281*0Sstevel@tonic-gate 		za->za_kick_rcv_id = timeout(zsa_kick_rcv, zs,
2282*0Sstevel@tonic-gate 		    zsticks[SPEED(za->za_ttycommon.t_cflag)]);
2283*0Sstevel@tonic-gate 	    za->za_kick_rcv_count = ZA_KICK_RCV_COUNT;
2284*0Sstevel@tonic-gate 	}
2285*0Sstevel@tonic-gate 	za->za_soft_active = 1;
2286*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
2287*0Sstevel@tonic-gate 
2288*0Sstevel@tonic-gate 	if (!hangup && do_ttycommon_qfull) {
2289*0Sstevel@tonic-gate 		ttycommon_qfull(&za->za_ttycommon, q);
2290*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
2291*0Sstevel@tonic-gate 		zsa_start(zs);
2292*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2293*0Sstevel@tonic-gate 	}
2294*0Sstevel@tonic-gate 
2295*0Sstevel@tonic-gate 	if (za->za_hw_overrun > 10) {
2296*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zs%d: silo overflow\n", UNIT(za->za_dev));
2297*0Sstevel@tonic-gate 		za->za_hw_overrun = 0;
2298*0Sstevel@tonic-gate 	}
2299*0Sstevel@tonic-gate 
2300*0Sstevel@tonic-gate 	if (za->za_sw_overrun > 10) {
2301*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zs%d:ring buffer overflow\n",
2302*0Sstevel@tonic-gate 		    UNIT(za->za_dev));
2303*0Sstevel@tonic-gate 		za->za_sw_overrun = 0;
2304*0Sstevel@tonic-gate 	}
2305*0Sstevel@tonic-gate 
2306*0Sstevel@tonic-gate 	if (unhangup)
2307*0Sstevel@tonic-gate 		(void) putnextctl(q, M_UNHANGUP);
2308*0Sstevel@tonic-gate 
2309*0Sstevel@tonic-gate 	if (m_break)
2310*0Sstevel@tonic-gate 		(void) putnextctl(q, M_BREAK);
2311*0Sstevel@tonic-gate 
2312*0Sstevel@tonic-gate 	while (head) {
2313*0Sstevel@tonic-gate 		if (!tail) {
2314*0Sstevel@tonic-gate 			putnext(q, head);
2315*0Sstevel@tonic-gate 			break;
2316*0Sstevel@tonic-gate 		}
2317*0Sstevel@tonic-gate 		bp = head;
2318*0Sstevel@tonic-gate 		head = head->b_next;
2319*0Sstevel@tonic-gate 		bp->b_next = NULL;
2320*0Sstevel@tonic-gate 		putnext(q, bp);
2321*0Sstevel@tonic-gate 	}
2322*0Sstevel@tonic-gate 
2323*0Sstevel@tonic-gate 	if (hangup) {
2324*0Sstevel@tonic-gate 		int flushflag;
2325*0Sstevel@tonic-gate 
2326*0Sstevel@tonic-gate 		/*
2327*0Sstevel@tonic-gate 		 * If we're in the midst of close, then flush everything.  Don't
2328*0Sstevel@tonic-gate 		 * leave stale ioctls lying about.
2329*0Sstevel@tonic-gate 		 */
2330*0Sstevel@tonic-gate 		flushflag = (zs->zs_flags & ZS_CLOSING) ? FLUSHALL : FLUSHDATA;
2331*0Sstevel@tonic-gate 		flushq(za->za_ttycommon.t_writeq, flushflag);
2332*0Sstevel@tonic-gate 		(void) putnextctl(q, M_HANGUP);
2333*0Sstevel@tonic-gate 	}
2334*0Sstevel@tonic-gate 
2335*0Sstevel@tonic-gate 	if (m_error)
2336*0Sstevel@tonic-gate 		(void) putnextctl1(q, M_ERROR, m_error);
2337*0Sstevel@tonic-gate 
2338*0Sstevel@tonic-gate 	za->za_soft_active = 0;
2339*0Sstevel@tonic-gate 
2340*0Sstevel@tonic-gate 	if (wakeup || (zs->zs_flags & ZS_CLOSED))
2341*0Sstevel@tonic-gate 		cv_broadcast(&zs->zs_flags_cv);
2342*0Sstevel@tonic-gate 
2343*0Sstevel@tonic-gate 	return (0);
2344*0Sstevel@tonic-gate }
2345*0Sstevel@tonic-gate 
2346*0Sstevel@tonic-gate /*
2347*0Sstevel@tonic-gate  * Start output on a line, unless it's busy, frozen, or otherwise.
2348*0Sstevel@tonic-gate  */
2349*0Sstevel@tonic-gate static void
2350*0Sstevel@tonic-gate zsa_start(struct zscom *zs)
2351*0Sstevel@tonic-gate {
2352*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
2353*0Sstevel@tonic-gate 	register int cc;
2354*0Sstevel@tonic-gate 	register queue_t *q;
2355*0Sstevel@tonic-gate 	register mblk_t *bp;
2356*0Sstevel@tonic-gate 	uchar_t *rptr, *wptr;
2357*0Sstevel@tonic-gate 
2358*0Sstevel@tonic-gate 	/*
2359*0Sstevel@tonic-gate 	 * If the chip is busy (i.e., we're waiting for a break timeout
2360*0Sstevel@tonic-gate 	 * to expire, or for the current transmission to finish, or for
2361*0Sstevel@tonic-gate 	 * output to finish draining from chip), don't grab anything new.
2362*0Sstevel@tonic-gate 	 */
2363*0Sstevel@tonic-gate 	if ((za->za_flags & (ZAS_BREAK|ZAS_BUSY|ZAS_DRAINING)) ||
2364*0Sstevel@tonic-gate 	    zs->zs_suspended)
2365*0Sstevel@tonic-gate 		return;
2366*0Sstevel@tonic-gate 
2367*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS) {
2368*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
2369*0Sstevel@tonic-gate 		if (za->za_rcv_flags_mask & DO_RETRANSMIT) {
2370*0Sstevel@tonic-gate 			rptr = zs->zs_wr_cur;
2371*0Sstevel@tonic-gate 			wptr = zs->zs_wr_lim;
2372*0Sstevel@tonic-gate 			goto zsa_start_retransmit;
2373*0Sstevel@tonic-gate 
2374*0Sstevel@tonic-gate 		}
2375*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2376*0Sstevel@tonic-gate 	}
2377*0Sstevel@tonic-gate 
2378*0Sstevel@tonic-gate 	/*
2379*0Sstevel@tonic-gate 	 * If we have a flow-control character to transmit, do it now.
2380*0Sstevel@tonic-gate 	 */
2381*0Sstevel@tonic-gate 	if (za->za_flowc != '\0') {
2382*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
2383*0Sstevel@tonic-gate 		if (za->za_ttycommon.t_cflag & CRTSCTS) {
2384*0Sstevel@tonic-gate 			if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) !=
2385*0Sstevel@tonic-gate 			    (ZSRR0_CTS|ZSRR0_TX_READY)) {
2386*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
2387*0Sstevel@tonic-gate 				return;
2388*0Sstevel@tonic-gate 			}
2389*0Sstevel@tonic-gate 		} else if (!(SCC_READ0() & ZSRR0_TX_READY)) {
2390*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2391*0Sstevel@tonic-gate 			return;
2392*0Sstevel@tonic-gate 		}
2393*0Sstevel@tonic-gate 
2394*0Sstevel@tonic-gate 		ZSDELAY();
2395*0Sstevel@tonic-gate 		SCC_WRITEDATA(za->za_flowc);
2396*0Sstevel@tonic-gate 		za->za_flowc = '\0';
2397*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2398*0Sstevel@tonic-gate 		return;
2399*0Sstevel@tonic-gate 	}
2400*0Sstevel@tonic-gate 
2401*0Sstevel@tonic-gate 	/*
2402*0Sstevel@tonic-gate 	 * If we're waiting for a delay timeout to expire, don't grab
2403*0Sstevel@tonic-gate 	 * anything new.
2404*0Sstevel@tonic-gate 	 */
2405*0Sstevel@tonic-gate 	if (za->za_flags & ZAS_DELAY)
2406*0Sstevel@tonic-gate 		return;
2407*0Sstevel@tonic-gate 
2408*0Sstevel@tonic-gate 	if ((q = za->za_ttycommon.t_writeq) == NULL)
2409*0Sstevel@tonic-gate 		return;	/* not attached to a stream */
2410*0Sstevel@tonic-gate 
2411*0Sstevel@tonic-gate zsa_start_again:
2412*0Sstevel@tonic-gate 	for (;;) {
2413*0Sstevel@tonic-gate 		if ((bp = getq(q)) == NULL)
2414*0Sstevel@tonic-gate 			return;	/* no data to transmit */
2415*0Sstevel@tonic-gate 
2416*0Sstevel@tonic-gate 		/*
2417*0Sstevel@tonic-gate 		 * We have a message block to work on.
2418*0Sstevel@tonic-gate 		 * Check whether it's a break, a delay, or an ioctl (the latter
2419*0Sstevel@tonic-gate 		 * occurs if the ioctl in question was waiting for the output
2420*0Sstevel@tonic-gate 		 * to drain). If it's one of those, process it immediately.
2421*0Sstevel@tonic-gate 		 */
2422*0Sstevel@tonic-gate 		switch (bp->b_datap->db_type) {
2423*0Sstevel@tonic-gate 
2424*0Sstevel@tonic-gate 		case M_BREAK:
2425*0Sstevel@tonic-gate 			/*
2426*0Sstevel@tonic-gate 			 * Set the break bit, and arrange for "zsa_restart"
2427*0Sstevel@tonic-gate 			 * to be called in 1/4 second; it will turn the
2428*0Sstevel@tonic-gate 			 * break bit off, and call "zsa_start" to grab
2429*0Sstevel@tonic-gate 			 * the next message.
2430*0Sstevel@tonic-gate 			 */
2431*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2432*0Sstevel@tonic-gate 			SCC_BIS(5, ZSWR5_BREAK);
2433*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2434*0Sstevel@tonic-gate 			if (!za->za_zsa_restart_id) {
2435*0Sstevel@tonic-gate 				za->za_zsa_restart_id =
2436*0Sstevel@tonic-gate 				    timeout(zsa_restart, zs, hz/4);
2437*0Sstevel@tonic-gate 			}
2438*0Sstevel@tonic-gate 			za->za_flags |= ZAS_BREAK;
2439*0Sstevel@tonic-gate 			freemsg(bp);
2440*0Sstevel@tonic-gate 			return;	/* wait for this to finish */
2441*0Sstevel@tonic-gate 
2442*0Sstevel@tonic-gate 		case M_DELAY:
2443*0Sstevel@tonic-gate 			/*
2444*0Sstevel@tonic-gate 			 * Arrange for "zsa_restart" to be called when the
2445*0Sstevel@tonic-gate 			 * delay expires; it will turn MTS_DELAY off,
2446*0Sstevel@tonic-gate 			 * and call "zsa_start" to grab the next message.
2447*0Sstevel@tonic-gate 			 */
2448*0Sstevel@tonic-gate 			if (! za->za_zsa_restart_id) {
2449*0Sstevel@tonic-gate 				za->za_zsa_restart_id = timeout(zsa_restart,
2450*0Sstevel@tonic-gate 				    zs,
2451*0Sstevel@tonic-gate 				    (int)(*(unsigned char *)bp->b_rptr + 6));
2452*0Sstevel@tonic-gate 			}
2453*0Sstevel@tonic-gate 			za->za_flags |= ZAS_DELAY;
2454*0Sstevel@tonic-gate 			freemsg(bp);
2455*0Sstevel@tonic-gate 			return;	/* wait for this to finish */
2456*0Sstevel@tonic-gate 
2457*0Sstevel@tonic-gate 		case M_IOCTL:
2458*0Sstevel@tonic-gate 			/*
2459*0Sstevel@tonic-gate 			 * This ioctl was waiting for the output ahead of
2460*0Sstevel@tonic-gate 			 * it to drain; obviously, it has. Do it, and
2461*0Sstevel@tonic-gate 			 * then grab the next message after it.
2462*0Sstevel@tonic-gate 			 */
2463*0Sstevel@tonic-gate 			zsa_ioctl(za, q, bp);
2464*0Sstevel@tonic-gate 			continue;
2465*0Sstevel@tonic-gate 		default: /* M_DATA */
2466*0Sstevel@tonic-gate 			goto zsa_start_transmit;
2467*0Sstevel@tonic-gate 		}
2468*0Sstevel@tonic-gate 
2469*0Sstevel@tonic-gate 	}
2470*0Sstevel@tonic-gate zsa_start_transmit:
2471*0Sstevel@tonic-gate 	/*
2472*0Sstevel@tonic-gate 	 * We have data to transmit. If output is stopped, put
2473*0Sstevel@tonic-gate 	 * it back and try again later.
2474*0Sstevel@tonic-gate 	 */
2475*0Sstevel@tonic-gate 	if (za->za_flags & ZAS_STOPPED) {
2476*0Sstevel@tonic-gate 		(void) putbq(q, bp);
2477*0Sstevel@tonic-gate 		return;
2478*0Sstevel@tonic-gate 	}
2479*0Sstevel@tonic-gate 
2480*0Sstevel@tonic-gate 	za->za_xmitblk = bp;
2481*0Sstevel@tonic-gate 	rptr = bp->b_rptr;
2482*0Sstevel@tonic-gate 	wptr = bp->b_wptr;
2483*0Sstevel@tonic-gate 	cc = wptr - rptr;
2484*0Sstevel@tonic-gate 	bp = bp->b_cont;
2485*0Sstevel@tonic-gate 	if (bp != NULL) {
2486*0Sstevel@tonic-gate 		za->za_xmitblk->b_cont = NULL;
2487*0Sstevel@tonic-gate 		(void) putbq(q, bp);	/* not done with this message yet */
2488*0Sstevel@tonic-gate 	}
2489*0Sstevel@tonic-gate 
2490*0Sstevel@tonic-gate 	if (rptr >= wptr) {
2491*0Sstevel@tonic-gate 		freeb(za->za_xmitblk);
2492*0Sstevel@tonic-gate 		za->za_xmitblk = NULL;
2493*0Sstevel@tonic-gate 		goto zsa_start_again;
2494*0Sstevel@tonic-gate 	}
2495*0Sstevel@tonic-gate 
2496*0Sstevel@tonic-gate 	/*
2497*0Sstevel@tonic-gate 	 * In 5-bit mode, the high order bits are used
2498*0Sstevel@tonic-gate 	 * to indicate character sizes less than five,
2499*0Sstevel@tonic-gate 	 * so we need to explicitly mask before transmitting
2500*0Sstevel@tonic-gate 	 */
2501*0Sstevel@tonic-gate 	if ((za->za_ttycommon.t_cflag & CSIZE) == CS5) {
2502*0Sstevel@tonic-gate 		register unsigned char *p = rptr;
2503*0Sstevel@tonic-gate 		register int cnt = cc;
2504*0Sstevel@tonic-gate 
2505*0Sstevel@tonic-gate 		while (cnt--)
2506*0Sstevel@tonic-gate 			*p++ &= (unsigned char) 0x1f;
2507*0Sstevel@tonic-gate 	}
2508*0Sstevel@tonic-gate 
2509*0Sstevel@tonic-gate 	/*
2510*0Sstevel@tonic-gate 	 * Set up this block for pseudo-DMA.
2511*0Sstevel@tonic-gate 	 */
2512*0Sstevel@tonic-gate 
2513*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
2514*0Sstevel@tonic-gate 	zs->zs_wr_cur = rptr;
2515*0Sstevel@tonic-gate 	zs->zs_wr_lim = wptr;
2516*0Sstevel@tonic-gate 
2517*0Sstevel@tonic-gate zsa_start_retransmit:
2518*0Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~DO_TRANSMIT;
2519*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS) {
2520*0Sstevel@tonic-gate 		if ((SCC_READ0() & (ZSRR0_CTS|ZSRR0_TX_READY)) !=
2521*0Sstevel@tonic-gate 			(ZSRR0_CTS|ZSRR0_TX_READY)) {
2522*0Sstevel@tonic-gate 			za->za_rcv_flags_mask |= DO_RETRANSMIT;
2523*0Sstevel@tonic-gate 			za->za_flags |= ZAS_BUSY;
2524*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2525*0Sstevel@tonic-gate 			return;
2526*0Sstevel@tonic-gate 		}
2527*0Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
2528*0Sstevel@tonic-gate 	} else if (!(SCC_READ0() & ZSRR0_TX_READY)) {
2529*0Sstevel@tonic-gate 			za->za_flags |= ZAS_BUSY;
2530*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2531*0Sstevel@tonic-gate 			return;
2532*0Sstevel@tonic-gate 	}
2533*0Sstevel@tonic-gate 	/*
2534*0Sstevel@tonic-gate 	 * If the transmitter is ready, shove the first
2535*0Sstevel@tonic-gate 	 * character out.
2536*0Sstevel@tonic-gate 	 */
2537*0Sstevel@tonic-gate 	ZSDELAY();
2538*0Sstevel@tonic-gate 	SCC_WRITEDATA(*rptr++);
2539*0Sstevel@tonic-gate #ifdef ZSA_DEBUG
2540*0Sstevel@tonic-gate 	za->za_wr++;
2541*0Sstevel@tonic-gate #endif
2542*0Sstevel@tonic-gate 	zs->zs_wr_cur = rptr;
2543*0Sstevel@tonic-gate 	za->za_flags |= ZAS_BUSY;
2544*0Sstevel@tonic-gate 	zs->zs_flags |= ZS_PROGRESS;
2545*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
2546*0Sstevel@tonic-gate }
2547*0Sstevel@tonic-gate 
2548*0Sstevel@tonic-gate /*
2549*0Sstevel@tonic-gate  * Restart output on a line after a delay or break timer expired.
2550*0Sstevel@tonic-gate  */
2551*0Sstevel@tonic-gate static void
2552*0Sstevel@tonic-gate zsa_restart(void *arg)
2553*0Sstevel@tonic-gate {
2554*0Sstevel@tonic-gate 	struct zscom *zs = arg;
2555*0Sstevel@tonic-gate 	struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
2556*0Sstevel@tonic-gate 
2557*0Sstevel@tonic-gate 	/*
2558*0Sstevel@tonic-gate 	 * If break timer expired, turn off the break bit.
2559*0Sstevel@tonic-gate 	 */
2560*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
2561*0Sstevel@tonic-gate 	if (!za->za_zsa_restart_id) {
2562*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2563*0Sstevel@tonic-gate 		return;
2564*0Sstevel@tonic-gate 	}
2565*0Sstevel@tonic-gate 	za->za_zsa_restart_id = 0;
2566*0Sstevel@tonic-gate 	if (za->za_flags & ZAS_BREAK) {
2567*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
2568*0Sstevel@tonic-gate 		SCC_BIC(5, ZSWR5_BREAK);
2569*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2570*0Sstevel@tonic-gate 	}
2571*0Sstevel@tonic-gate 	za->za_flags &= ~(ZAS_DELAY|ZAS_BREAK);
2572*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_writeq != NULL)
2573*0Sstevel@tonic-gate 		zsa_start(zs);
2574*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
2575*0Sstevel@tonic-gate 	cv_broadcast(&zs->zs_flags_cv);
2576*0Sstevel@tonic-gate }
2577*0Sstevel@tonic-gate 
2578*0Sstevel@tonic-gate /*
2579*0Sstevel@tonic-gate  * See if the receiver has any data after zs_tick delay
2580*0Sstevel@tonic-gate  */
2581*0Sstevel@tonic-gate static void
2582*0Sstevel@tonic-gate zsa_kick_rcv(void *arg)
2583*0Sstevel@tonic-gate {
2584*0Sstevel@tonic-gate 	struct zscom *zs = arg;
2585*0Sstevel@tonic-gate 	struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
2586*0Sstevel@tonic-gate 	queue_t *q;
2587*0Sstevel@tonic-gate 	int	tmp;
2588*0Sstevel@tonic-gate 	mblk_t	*mp;
2589*0Sstevel@tonic-gate 	uchar_t za_soft_active, za_kick_active;
2590*0Sstevel@tonic-gate 	int	allocbcount = 0;
2591*0Sstevel@tonic-gate 	int do_ttycommon_qfull = 0;
2592*0Sstevel@tonic-gate 	mblk_t *head = NULL, *tail = NULL;
2593*0Sstevel@tonic-gate 
2594*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
2595*0Sstevel@tonic-gate 	if (za->za_kick_rcv_id == 0 || (zs->zs_flags & ZS_CLOSED)) {
2596*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2597*0Sstevel@tonic-gate 		return;
2598*0Sstevel@tonic-gate 	}
2599*0Sstevel@tonic-gate 	za_soft_active = za->za_soft_active;
2600*0Sstevel@tonic-gate 	za_kick_active = za->za_kick_active;
2601*0Sstevel@tonic-gate 	q = za->za_ttycommon.t_readq;
2602*0Sstevel@tonic-gate 	if (!q) {
2603*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2604*0Sstevel@tonic-gate 		return;
2605*0Sstevel@tonic-gate 	}
2606*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
2607*0Sstevel@tonic-gate 	if (zs->zs_rd_cur) {
2608*0Sstevel@tonic-gate 		ZSA_KICK_RCV;
2609*0Sstevel@tonic-gate 		za->za_kick_rcv_count = tmp = ZA_KICK_RCV_COUNT;
2610*0Sstevel@tonic-gate 	} else
2611*0Sstevel@tonic-gate 		tmp = --za->za_kick_rcv_count;
2612*0Sstevel@tonic-gate 	if (tmp > 0 || za_soft_active || za_kick_active) {
2613*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2614*0Sstevel@tonic-gate 		if (g_zsticks)
2615*0Sstevel@tonic-gate 			za->za_kick_rcv_id = timeout(zsa_kick_rcv,
2616*0Sstevel@tonic-gate 			    zs, g_zsticks);
2617*0Sstevel@tonic-gate 		else
2618*0Sstevel@tonic-gate 			za->za_kick_rcv_id = timeout(zsa_kick_rcv,
2619*0Sstevel@tonic-gate 			    zs, zsticks[SPEED(za->za_ttycommon.t_cflag)]);
2620*0Sstevel@tonic-gate 		if (za_soft_active || za_kick_active) {
2621*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl);
2622*0Sstevel@tonic-gate 			return;
2623*0Sstevel@tonic-gate 		}
2624*0Sstevel@tonic-gate 	} else {
2625*0Sstevel@tonic-gate 		za->za_kick_rcv_id = 0;
2626*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
2627*0Sstevel@tonic-gate 	}
2628*0Sstevel@tonic-gate 
2629*0Sstevel@tonic-gate 
2630*0Sstevel@tonic-gate 	for (;;) {
2631*0Sstevel@tonic-gate 	    ZSA_SEEQ(mp);
2632*0Sstevel@tonic-gate 	    if (!mp)
2633*0Sstevel@tonic-gate 		break;
2634*0Sstevel@tonic-gate 
2635*0Sstevel@tonic-gate 	    allocbcount++;
2636*0Sstevel@tonic-gate 
2637*0Sstevel@tonic-gate 	    if (mp->b_datap->db_type <= QPCTL) {
2638*0Sstevel@tonic-gate 		if (!(canputnext(q))) {
2639*0Sstevel@tonic-gate 			if (za->za_grace_flow_control >=
2640*0Sstevel@tonic-gate 				zsa_grace_flow_control) {
2641*0Sstevel@tonic-gate 			    if (za->za_ttycommon.t_cflag & CRTSXOFF) {
2642*0Sstevel@tonic-gate 					allocbcount--;
2643*0Sstevel@tonic-gate 					break;
2644*0Sstevel@tonic-gate 			    }
2645*0Sstevel@tonic-gate 			    ZSA_GETQ(mp);
2646*0Sstevel@tonic-gate 			    freemsg(mp);
2647*0Sstevel@tonic-gate 			    do_ttycommon_qfull = 1;
2648*0Sstevel@tonic-gate 			    continue;
2649*0Sstevel@tonic-gate 			} else
2650*0Sstevel@tonic-gate 			    za->za_grace_flow_control++;
2651*0Sstevel@tonic-gate 		} else
2652*0Sstevel@tonic-gate 			za->za_grace_flow_control = 0;
2653*0Sstevel@tonic-gate 	    }
2654*0Sstevel@tonic-gate 	    ZSA_GETQ(mp);
2655*0Sstevel@tonic-gate 	    if (!head) {
2656*0Sstevel@tonic-gate 		head = mp;
2657*0Sstevel@tonic-gate 	    } else {
2658*0Sstevel@tonic-gate 		if (!tail)
2659*0Sstevel@tonic-gate 			tail = head;
2660*0Sstevel@tonic-gate 		tail->b_next = mp;
2661*0Sstevel@tonic-gate 		tail = mp;
2662*0Sstevel@tonic-gate 	    }
2663*0Sstevel@tonic-gate 	}
2664*0Sstevel@tonic-gate 
2665*0Sstevel@tonic-gate 	if (allocbcount)
2666*0Sstevel@tonic-gate 		ZSA_GETBLOCK(zs, allocbcount);
2667*0Sstevel@tonic-gate 
2668*0Sstevel@tonic-gate 	za->za_kick_active = 1;
2669*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
2670*0Sstevel@tonic-gate 
2671*0Sstevel@tonic-gate 	if (do_ttycommon_qfull) {
2672*0Sstevel@tonic-gate 		ttycommon_qfull(&za->za_ttycommon, q);
2673*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl);
2674*0Sstevel@tonic-gate 		zsa_start(zs);
2675*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2676*0Sstevel@tonic-gate 	}
2677*0Sstevel@tonic-gate 
2678*0Sstevel@tonic-gate 	while (head) {
2679*0Sstevel@tonic-gate 		if (!tail) {
2680*0Sstevel@tonic-gate 			putnext(q, head);
2681*0Sstevel@tonic-gate 			break;
2682*0Sstevel@tonic-gate 		}
2683*0Sstevel@tonic-gate 		mp = head;
2684*0Sstevel@tonic-gate 		head = head->b_next;
2685*0Sstevel@tonic-gate 		mp->b_next = NULL;
2686*0Sstevel@tonic-gate 		putnext(q, mp);
2687*0Sstevel@tonic-gate 
2688*0Sstevel@tonic-gate 	}
2689*0Sstevel@tonic-gate 	za->za_kick_active = 0;
2690*0Sstevel@tonic-gate 
2691*0Sstevel@tonic-gate 	if (zs->zs_flags & ZS_CLOSED)
2692*0Sstevel@tonic-gate 		cv_broadcast(&zs->zs_flags_cv);
2693*0Sstevel@tonic-gate }
2694*0Sstevel@tonic-gate 
2695*0Sstevel@tonic-gate /*
2696*0Sstevel@tonic-gate  * Retry an "ioctl", now that "bufcall" claims we may be able to allocate
2697*0Sstevel@tonic-gate  * the buffer we need.
2698*0Sstevel@tonic-gate  */
2699*0Sstevel@tonic-gate static void
2700*0Sstevel@tonic-gate zsa_reioctl(void *arg)
2701*0Sstevel@tonic-gate {
2702*0Sstevel@tonic-gate 	struct asyncline *za = arg;
2703*0Sstevel@tonic-gate 	struct zscom *zs = za->za_common;
2704*0Sstevel@tonic-gate 	queue_t *q;
2705*0Sstevel@tonic-gate 	mblk_t	 *mp;
2706*0Sstevel@tonic-gate 
2707*0Sstevel@tonic-gate 	/*
2708*0Sstevel@tonic-gate 	 * The bufcall is no longer pending.
2709*0Sstevel@tonic-gate 	 */
2710*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
2711*0Sstevel@tonic-gate 	if (!za->za_wbufcid) {
2712*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2713*0Sstevel@tonic-gate 		return;
2714*0Sstevel@tonic-gate 	}
2715*0Sstevel@tonic-gate 	za->za_wbufcid = 0;
2716*0Sstevel@tonic-gate 	if ((q = za->za_ttycommon.t_writeq) == NULL) {
2717*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
2718*0Sstevel@tonic-gate 		return;
2719*0Sstevel@tonic-gate 	}
2720*0Sstevel@tonic-gate 	if ((mp = za->za_ttycommon.t_iocpending) != NULL) {
2721*0Sstevel@tonic-gate 		/*
2722*0Sstevel@tonic-gate 		 * not pending any more
2723*0Sstevel@tonic-gate 		 */
2724*0Sstevel@tonic-gate 		za->za_ttycommon.t_iocpending = NULL;
2725*0Sstevel@tonic-gate 		zsa_ioctl(za, q, mp);
2726*0Sstevel@tonic-gate 	}
2727*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
2728*0Sstevel@tonic-gate }
2729*0Sstevel@tonic-gate 
2730*0Sstevel@tonic-gate /*
2731*0Sstevel@tonic-gate  * Process an "ioctl" message sent down to us.
2732*0Sstevel@tonic-gate  * Note that we don't need to get any locks until we are ready to access
2733*0Sstevel@tonic-gate  * the hardware. Nothing we access until then is going to be altered
2734*0Sstevel@tonic-gate  * outside of the STREAMS framework, so we should be safe.
2735*0Sstevel@tonic-gate  */
2736*0Sstevel@tonic-gate static void
2737*0Sstevel@tonic-gate zsa_ioctl(struct asyncline *za, queue_t *wq, mblk_t *mp)
2738*0Sstevel@tonic-gate {
2739*0Sstevel@tonic-gate 	register struct zscom *zs = za->za_common;
2740*0Sstevel@tonic-gate 	register struct iocblk *iocp;
2741*0Sstevel@tonic-gate 	register unsigned datasize;
2742*0Sstevel@tonic-gate 	int error;
2743*0Sstevel@tonic-gate 	register mblk_t *tmp;
2744*0Sstevel@tonic-gate 
2745*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iocpending != NULL) {
2746*0Sstevel@tonic-gate 		/*
2747*0Sstevel@tonic-gate 		 * We were holding an "ioctl" response pending the
2748*0Sstevel@tonic-gate 		 * availability of an "mblk" to hold data to be passed up;
2749*0Sstevel@tonic-gate 		 * another "ioctl" came through, which means that "ioctl"
2750*0Sstevel@tonic-gate 		 * must have timed out or been aborted.
2751*0Sstevel@tonic-gate 		 */
2752*0Sstevel@tonic-gate 		freemsg(za->za_ttycommon.t_iocpending);
2753*0Sstevel@tonic-gate 		za->za_ttycommon.t_iocpending = NULL;
2754*0Sstevel@tonic-gate 	}
2755*0Sstevel@tonic-gate 
2756*0Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
2757*0Sstevel@tonic-gate 
2758*0Sstevel@tonic-gate 	/*
2759*0Sstevel@tonic-gate 	 * The only way in which "ttycommon_ioctl" can fail is if the "ioctl"
2760*0Sstevel@tonic-gate 	 * requires a response containing data to be returned to the user,
2761*0Sstevel@tonic-gate 	 * and no mblk could be allocated for the data.
2762*0Sstevel@tonic-gate 	 * No such "ioctl" alters our state. Thus, we always go ahead and
2763*0Sstevel@tonic-gate 	 * do any state-changes the "ioctl" calls for. If we couldn't allocate
2764*0Sstevel@tonic-gate 	 * the data, "ttycommon_ioctl" has stashed the "ioctl" away safely, so
2765*0Sstevel@tonic-gate 	 * we just call "bufcall" to request that we be called back when we
2766*0Sstevel@tonic-gate 	 * stand a better chance of allocating the data.
2767*0Sstevel@tonic-gate 	 */
2768*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
2769*0Sstevel@tonic-gate 	datasize = ttycommon_ioctl(&za->za_ttycommon, wq, mp, &error);
2770*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
2771*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_flags & TS_SOFTCAR)
2772*0Sstevel@tonic-gate 		zssoftCAR[zs->zs_unit] = 1;
2773*0Sstevel@tonic-gate 	else
2774*0Sstevel@tonic-gate 		zssoftCAR[zs->zs_unit] = 0;
2775*0Sstevel@tonic-gate 	if (datasize != 0) {
2776*0Sstevel@tonic-gate 		if (za->za_wbufcid)
2777*0Sstevel@tonic-gate 			unbufcall(za->za_wbufcid);
2778*0Sstevel@tonic-gate 		za->za_wbufcid = bufcall(datasize, BPRI_HI, zsa_reioctl, za);
2779*0Sstevel@tonic-gate 		return;
2780*0Sstevel@tonic-gate 	}
2781*0Sstevel@tonic-gate 
2782*0Sstevel@tonic-gate 
2783*0Sstevel@tonic-gate 	if (error == 0) {
2784*0Sstevel@tonic-gate 		/*
2785*0Sstevel@tonic-gate 		 * "ttycommon_ioctl" did most of the work; we just use the
2786*0Sstevel@tonic-gate 		 * data it set up.
2787*0Sstevel@tonic-gate 		 */
2788*0Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
2789*0Sstevel@tonic-gate 
2790*0Sstevel@tonic-gate 		case TCSETS:
2791*0Sstevel@tonic-gate 		case TCSETSW:
2792*0Sstevel@tonic-gate 		case TCSETSF:
2793*0Sstevel@tonic-gate 		case TCSETA:
2794*0Sstevel@tonic-gate 		case TCSETAW:
2795*0Sstevel@tonic-gate 		case TCSETAF:
2796*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2797*0Sstevel@tonic-gate 			zsa_program(za, 1);
2798*0Sstevel@tonic-gate 			zsa_set_za_rcv_flags_mask(za);
2799*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2800*0Sstevel@tonic-gate 			break;
2801*0Sstevel@tonic-gate 		}
2802*0Sstevel@tonic-gate 	} else if (error < 0) {
2803*0Sstevel@tonic-gate 		/*
2804*0Sstevel@tonic-gate 		 * "ttycommon_ioctl" didn't do anything; we process it here.
2805*0Sstevel@tonic-gate 		 */
2806*0Sstevel@tonic-gate 		error = 0;
2807*0Sstevel@tonic-gate 
2808*0Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
2809*0Sstevel@tonic-gate 
2810*0Sstevel@tonic-gate 		case TCSBRK:
2811*0Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (int));
2812*0Sstevel@tonic-gate 			if (error != 0)
2813*0Sstevel@tonic-gate 				break;
2814*0Sstevel@tonic-gate 
2815*0Sstevel@tonic-gate 			if (*(int *)mp->b_cont->b_rptr == 0) {
2816*0Sstevel@tonic-gate 				/*
2817*0Sstevel@tonic-gate 				 * The delay ensures that a 3 byte transmit
2818*0Sstevel@tonic-gate 				 * fifo is empty.
2819*0Sstevel@tonic-gate 				 */
2820*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl);
2821*0Sstevel@tonic-gate 				delay(ztdelay(SPEED(za->za_ttycommon.t_cflag)));
2822*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl);
2823*0Sstevel@tonic-gate 
2824*0Sstevel@tonic-gate 				/*
2825*0Sstevel@tonic-gate 				 * Set the break bit, and arrange for
2826*0Sstevel@tonic-gate 				 * "zsa_restart" to be called in 1/4 second;
2827*0Sstevel@tonic-gate 				 * it will turn the break bit off, and call
2828*0Sstevel@tonic-gate 				 * "zsa_start" to grab the next message.
2829*0Sstevel@tonic-gate 				 */
2830*0Sstevel@tonic-gate 				mutex_enter(zs->zs_excl_hi);
2831*0Sstevel@tonic-gate 				SCC_BIS(5, ZSWR5_BREAK);
2832*0Sstevel@tonic-gate 				if (!za->za_zsa_restart_id) {
2833*0Sstevel@tonic-gate 					mutex_exit(zs->zs_excl_hi);
2834*0Sstevel@tonic-gate 					za->za_zsa_restart_id =
2835*0Sstevel@tonic-gate 					    timeout(zsa_restart, zs, hz / 4);
2836*0Sstevel@tonic-gate 					mutex_enter(zs->zs_excl_hi);
2837*0Sstevel@tonic-gate 				}
2838*0Sstevel@tonic-gate 				za->za_flags |= ZAS_BREAK;
2839*0Sstevel@tonic-gate 				mutex_exit(zs->zs_excl_hi);
2840*0Sstevel@tonic-gate 			}
2841*0Sstevel@tonic-gate 			break;
2842*0Sstevel@tonic-gate 
2843*0Sstevel@tonic-gate 		case TIOCSBRK:
2844*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2845*0Sstevel@tonic-gate 			SCC_BIS(5, ZSWR5_BREAK);
2846*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2847*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
2848*0Sstevel@tonic-gate 			break;
2849*0Sstevel@tonic-gate 
2850*0Sstevel@tonic-gate 		case TIOCCBRK:
2851*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2852*0Sstevel@tonic-gate 			SCC_BIC(5, ZSWR5_BREAK);
2853*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2854*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
2855*0Sstevel@tonic-gate 			break;
2856*0Sstevel@tonic-gate 
2857*0Sstevel@tonic-gate 		case TIOCMSET:
2858*0Sstevel@tonic-gate 		case TIOCMBIS:
2859*0Sstevel@tonic-gate 		case TIOCMBIC: {
2860*0Sstevel@tonic-gate 			int mlines;
2861*0Sstevel@tonic-gate 
2862*0Sstevel@tonic-gate 			if (iocp->ioc_count == TRANSPARENT) {
2863*0Sstevel@tonic-gate 				mcopyin(mp, NULL, sizeof (int), NULL);
2864*0Sstevel@tonic-gate 				break;
2865*0Sstevel@tonic-gate 			}
2866*0Sstevel@tonic-gate 
2867*0Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (int));
2868*0Sstevel@tonic-gate 			if (error != 0)
2869*0Sstevel@tonic-gate 				break;
2870*0Sstevel@tonic-gate 
2871*0Sstevel@tonic-gate 			mlines = *(int *)mp->b_cont->b_rptr;
2872*0Sstevel@tonic-gate 
2873*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2874*0Sstevel@tonic-gate 			switch (iocp->ioc_cmd) {
2875*0Sstevel@tonic-gate 			case TIOCMSET:
2876*0Sstevel@tonic-gate 				(void) zsmctl(zs, dmtozs(mlines), DMSET);
2877*0Sstevel@tonic-gate 				break;
2878*0Sstevel@tonic-gate 			case TIOCMBIS:
2879*0Sstevel@tonic-gate 				(void) zsmctl(zs, dmtozs(mlines), DMBIS);
2880*0Sstevel@tonic-gate 				break;
2881*0Sstevel@tonic-gate 			case TIOCMBIC:
2882*0Sstevel@tonic-gate 				(void) zsmctl(zs, dmtozs(mlines), DMBIC);
2883*0Sstevel@tonic-gate 				break;
2884*0Sstevel@tonic-gate 			}
2885*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2886*0Sstevel@tonic-gate 
2887*0Sstevel@tonic-gate 			mioc2ack(mp, NULL, 0, 0);
2888*0Sstevel@tonic-gate 			break;
2889*0Sstevel@tonic-gate 		}
2890*0Sstevel@tonic-gate 
2891*0Sstevel@tonic-gate 		case TIOCMGET:
2892*0Sstevel@tonic-gate 			tmp = allocb(sizeof (int), BPRI_MED);
2893*0Sstevel@tonic-gate 			if (tmp == NULL) {
2894*0Sstevel@tonic-gate 				error = EAGAIN;
2895*0Sstevel@tonic-gate 				break;
2896*0Sstevel@tonic-gate 			}
2897*0Sstevel@tonic-gate 			if (iocp->ioc_count != TRANSPARENT)
2898*0Sstevel@tonic-gate 				mioc2ack(mp, tmp, sizeof (int), 0);
2899*0Sstevel@tonic-gate 			else
2900*0Sstevel@tonic-gate 				mcopyout(mp, NULL, sizeof (int), NULL, tmp);
2901*0Sstevel@tonic-gate 
2902*0Sstevel@tonic-gate 			mutex_enter(zs->zs_excl_hi);
2903*0Sstevel@tonic-gate 			*(int *)mp->b_cont->b_rptr =
2904*0Sstevel@tonic-gate 			    zstodm(zsmctl(zs, 0, DMGET));
2905*0Sstevel@tonic-gate 			mutex_exit(zs->zs_excl_hi);
2906*0Sstevel@tonic-gate 			/*
2907*0Sstevel@tonic-gate 			 * qreply done below
2908*0Sstevel@tonic-gate 			 */
2909*0Sstevel@tonic-gate 			break;
2910*0Sstevel@tonic-gate 
2911*0Sstevel@tonic-gate 		default:
2912*0Sstevel@tonic-gate 			/*
2913*0Sstevel@tonic-gate 			 * If we don't understand it, it's an error. NAK it.
2914*0Sstevel@tonic-gate 			 */
2915*0Sstevel@tonic-gate 			error = EINVAL;
2916*0Sstevel@tonic-gate 			break;
2917*0Sstevel@tonic-gate 		}
2918*0Sstevel@tonic-gate 	}
2919*0Sstevel@tonic-gate 
2920*0Sstevel@tonic-gate 	if (error != 0) {
2921*0Sstevel@tonic-gate 		iocp->ioc_error = error;
2922*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
2923*0Sstevel@tonic-gate 	}
2924*0Sstevel@tonic-gate 
2925*0Sstevel@tonic-gate 	ZSA_QREPLY(wq, mp);
2926*0Sstevel@tonic-gate }
2927*0Sstevel@tonic-gate 
2928*0Sstevel@tonic-gate 
2929*0Sstevel@tonic-gate static int
2930*0Sstevel@tonic-gate dmtozs(int bits)
2931*0Sstevel@tonic-gate {
2932*0Sstevel@tonic-gate 	register int b = 0;
2933*0Sstevel@tonic-gate 
2934*0Sstevel@tonic-gate 	if (bits & TIOCM_CAR)
2935*0Sstevel@tonic-gate 		b |= ZSRR0_CD;
2936*0Sstevel@tonic-gate 	if (bits & TIOCM_CTS)
2937*0Sstevel@tonic-gate 		b |= ZSRR0_CTS;
2938*0Sstevel@tonic-gate 	if (bits & TIOCM_RTS)
2939*0Sstevel@tonic-gate 		b |= ZSWR5_RTS;
2940*0Sstevel@tonic-gate 	if (bits & TIOCM_DTR)
2941*0Sstevel@tonic-gate 		b |= ZSWR5_DTR;
2942*0Sstevel@tonic-gate 	return (b);
2943*0Sstevel@tonic-gate }
2944*0Sstevel@tonic-gate 
2945*0Sstevel@tonic-gate static int
2946*0Sstevel@tonic-gate zstodm(int bits)
2947*0Sstevel@tonic-gate {
2948*0Sstevel@tonic-gate 	register int b;
2949*0Sstevel@tonic-gate 
2950*0Sstevel@tonic-gate 	b = 0;
2951*0Sstevel@tonic-gate 	if (bits & ZSRR0_CD)
2952*0Sstevel@tonic-gate 		b |= TIOCM_CAR;
2953*0Sstevel@tonic-gate 	if (bits & ZSRR0_CTS)
2954*0Sstevel@tonic-gate 		b |= TIOCM_CTS;
2955*0Sstevel@tonic-gate 	if (bits & ZSWR5_RTS)
2956*0Sstevel@tonic-gate 		b |= TIOCM_RTS;
2957*0Sstevel@tonic-gate 	if (bits & ZSWR5_DTR)
2958*0Sstevel@tonic-gate 		b |= TIOCM_DTR;
2959*0Sstevel@tonic-gate 	return (b);
2960*0Sstevel@tonic-gate }
2961*0Sstevel@tonic-gate 
2962*0Sstevel@tonic-gate /*
2963*0Sstevel@tonic-gate  * Assemble registers and flags necessary to program the port to our liking.
2964*0Sstevel@tonic-gate  * For async operation, most of this is based on the values of
2965*0Sstevel@tonic-gate  * the "c_iflag" and "c_cflag" fields supplied to us.
2966*0Sstevel@tonic-gate  */
2967*0Sstevel@tonic-gate static void
2968*0Sstevel@tonic-gate zsa_program(struct asyncline *za, int setibaud)
2969*0Sstevel@tonic-gate {
2970*0Sstevel@tonic-gate 	register struct zscom *zs = za->za_common;
2971*0Sstevel@tonic-gate 	register struct zs_prog *zspp;
2972*0Sstevel@tonic-gate 	register int wr3, wr4, wr5, wr15, speed, baudrate, flags = 0;
2973*0Sstevel@tonic-gate 
2974*0Sstevel@tonic-gate 	if ((baudrate = SPEED(za->za_ttycommon.t_cflag)) == 0) {
2975*0Sstevel@tonic-gate 		/*
2976*0Sstevel@tonic-gate 		 * Hang up line.
2977*0Sstevel@tonic-gate 		 */
2978*0Sstevel@tonic-gate 		(void) zsmctl(zs, ZS_OFF, DMSET);
2979*0Sstevel@tonic-gate 		return;
2980*0Sstevel@tonic-gate 	}
2981*0Sstevel@tonic-gate 
2982*0Sstevel@tonic-gate 	/*
2983*0Sstevel@tonic-gate 	 * set input speed same as output, as split speed not supported
2984*0Sstevel@tonic-gate 	 */
2985*0Sstevel@tonic-gate 	if (setibaud) {
2986*0Sstevel@tonic-gate 		za->za_ttycommon.t_cflag &= ~(CIBAUD);
2987*0Sstevel@tonic-gate 		if (baudrate > CBAUD) {
2988*0Sstevel@tonic-gate 			za->za_ttycommon.t_cflag |= CIBAUDEXT;
2989*0Sstevel@tonic-gate 			za->za_ttycommon.t_cflag |=
2990*0Sstevel@tonic-gate 				(((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);
2991*0Sstevel@tonic-gate 		} else {
2992*0Sstevel@tonic-gate 			za->za_ttycommon.t_cflag &= ~CIBAUDEXT;
2993*0Sstevel@tonic-gate 			za->za_ttycommon.t_cflag |=
2994*0Sstevel@tonic-gate 				((baudrate << IBSHIFT) & CIBAUD);
2995*0Sstevel@tonic-gate 		}
2996*0Sstevel@tonic-gate 	}
2997*0Sstevel@tonic-gate 
2998*0Sstevel@tonic-gate 	/*
2999*0Sstevel@tonic-gate 	 * Do not allow the console/keyboard device to have its receiver
3000*0Sstevel@tonic-gate 	 * disabled; doing that would mean you couldn't type an abort
3001*0Sstevel@tonic-gate 	 * sequence.
3002*0Sstevel@tonic-gate 	 */
3003*0Sstevel@tonic-gate 	if ((za->za_dev == rconsdev) || (za->za_dev == kbddev) ||
3004*0Sstevel@tonic-gate 	    (za->za_dev == stdindev) || (za->za_ttycommon.t_cflag & CREAD))
3005*0Sstevel@tonic-gate 		wr3 = ZSWR3_RX_ENABLE;
3006*0Sstevel@tonic-gate 	else
3007*0Sstevel@tonic-gate 		wr3 = 0;
3008*0Sstevel@tonic-gate 	wr4 = ZSWR4_X16_CLK;
3009*0Sstevel@tonic-gate 	wr5 = (zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR)) | ZSWR5_TX_ENABLE;
3010*0Sstevel@tonic-gate 
3011*0Sstevel@tonic-gate 	if (zsb134_weird && baudrate == B134) {	/* what a joke! */
3012*0Sstevel@tonic-gate 		/*
3013*0Sstevel@tonic-gate 		 * XXX - should B134 set all this crap in the compatibility
3014*0Sstevel@tonic-gate 		 * module, leaving this stuff fairly clean?
3015*0Sstevel@tonic-gate 		 */
3016*0Sstevel@tonic-gate 		flags |= ZSP_PARITY_SPECIAL;
3017*0Sstevel@tonic-gate 		wr3 |= ZSWR3_RX_6;
3018*0Sstevel@tonic-gate 		wr4 |= ZSWR4_PARITY_ENABLE | ZSWR4_PARITY_EVEN;
3019*0Sstevel@tonic-gate 		wr4 |= ZSWR4_1_5_STOP;
3020*0Sstevel@tonic-gate 		wr5 |= ZSWR5_TX_6;
3021*0Sstevel@tonic-gate 	} else {
3022*0Sstevel@tonic-gate 
3023*0Sstevel@tonic-gate 		switch (za->za_ttycommon.t_cflag & CSIZE) {
3024*0Sstevel@tonic-gate 
3025*0Sstevel@tonic-gate 		case CS5:
3026*0Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_5;
3027*0Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_5;
3028*0Sstevel@tonic-gate 			break;
3029*0Sstevel@tonic-gate 
3030*0Sstevel@tonic-gate 		case CS6:
3031*0Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_6;
3032*0Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_6;
3033*0Sstevel@tonic-gate 			break;
3034*0Sstevel@tonic-gate 
3035*0Sstevel@tonic-gate 		case CS7:
3036*0Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_7;
3037*0Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_7;
3038*0Sstevel@tonic-gate 			break;
3039*0Sstevel@tonic-gate 
3040*0Sstevel@tonic-gate 		case CS8:
3041*0Sstevel@tonic-gate 			wr3 |= ZSWR3_RX_8;
3042*0Sstevel@tonic-gate 			wr5 |= ZSWR5_TX_8;
3043*0Sstevel@tonic-gate 			break;
3044*0Sstevel@tonic-gate 		}
3045*0Sstevel@tonic-gate 
3046*0Sstevel@tonic-gate 		if (za->za_ttycommon.t_cflag & PARENB) {
3047*0Sstevel@tonic-gate 			/*
3048*0Sstevel@tonic-gate 			 * The PARITY_SPECIAL bit causes a special rx
3049*0Sstevel@tonic-gate 			 * interrupt on parity errors. Turn it on if
3050*0Sstevel@tonic-gate 			 * we're checking the parity of characters.
3051*0Sstevel@tonic-gate 			 */
3052*0Sstevel@tonic-gate 			if (za->za_ttycommon.t_iflag & INPCK)
3053*0Sstevel@tonic-gate 				flags |= ZSP_PARITY_SPECIAL;
3054*0Sstevel@tonic-gate 			wr4 |= ZSWR4_PARITY_ENABLE;
3055*0Sstevel@tonic-gate 			if (!(za->za_ttycommon.t_cflag & PARODD))
3056*0Sstevel@tonic-gate 				wr4 |= ZSWR4_PARITY_EVEN;
3057*0Sstevel@tonic-gate 		}
3058*0Sstevel@tonic-gate 		wr4 |= (za->za_ttycommon.t_cflag & CSTOPB) ?
3059*0Sstevel@tonic-gate 		    ZSWR4_2_STOP : ZSWR4_1_STOP;
3060*0Sstevel@tonic-gate 	}
3061*0Sstevel@tonic-gate 
3062*0Sstevel@tonic-gate #if 0
3063*0Sstevel@tonic-gate 	/*
3064*0Sstevel@tonic-gate 	 * The AUTO_CD_CTS flag enables the hardware flow control feature of
3065*0Sstevel@tonic-gate 	 * the 8530, which allows the state of CTS and DCD to control the
3066*0Sstevel@tonic-gate 	 * enabling of the transmitter and receiver, respectively. The
3067*0Sstevel@tonic-gate 	 * receiver and transmitter still must have their enable bits set in
3068*0Sstevel@tonic-gate 	 * WR3 and WR5, respectively, for CTS and DCD to be monitored this way.
3069*0Sstevel@tonic-gate 	 * Hardware flow control can thus be implemented with no help from
3070*0Sstevel@tonic-gate 	 * software.
3071*0Sstevel@tonic-gate 	 */
3072*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS)
3073*0Sstevel@tonic-gate 		wr3 |= ZSWR3_AUTO_CD_CTS;
3074*0Sstevel@tonic-gate #endif
3075*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CRTSCTS)
3076*0Sstevel@tonic-gate 		wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD | ZSR15_CTS;
3077*0Sstevel@tonic-gate 	else
3078*0Sstevel@tonic-gate 		wr15 = ZSR15_BREAK | ZSR15_TX_UNDER | ZSR15_CD;
3079*0Sstevel@tonic-gate 
3080*0Sstevel@tonic-gate 	speed = zs->zs_wreg[12] + (zs->zs_wreg[13] << 8);
3081*0Sstevel@tonic-gate 
3082*0Sstevel@tonic-gate 	/*
3083*0Sstevel@tonic-gate 	 * Here we assemble a set of changes to be passed to zs_program.
3084*0Sstevel@tonic-gate 	 * Note: Write Register 15 must be set to enable BREAK and UNDERrun
3085*0Sstevel@tonic-gate 	 * interrupts.  It must also enable CD interrupts which, although
3086*0Sstevel@tonic-gate 	 * not processed by the hardware interrupt handler, will be processed
3087*0Sstevel@tonic-gate 	 * by zsa_process, indirectly resulting in a SIGHUP being delivered
3088*0Sstevel@tonic-gate 	 * to the controlling process if CD drops.  CTS interrupts must NOT
3089*0Sstevel@tonic-gate 	 * be enabled.  We don't use them at all, and they will hang IPC/IPX
3090*0Sstevel@tonic-gate 	 * systems at boot time if synchronous modems that supply transmit
3091*0Sstevel@tonic-gate 	 * clock are attached to any of their serial ports.
3092*0Sstevel@tonic-gate 	 */
3093*0Sstevel@tonic-gate 	if (((zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) &&
3094*0Sstevel@tonic-gate 	    !(flags & ZSP_PARITY_SPECIAL)) ||
3095*0Sstevel@tonic-gate 	    (!(zs->zs_wreg[1] & ZSWR1_PARITY_SPECIAL) &&
3096*0Sstevel@tonic-gate 	    (flags & ZSP_PARITY_SPECIAL)) ||
3097*0Sstevel@tonic-gate 	    wr3 != zs->zs_wreg[3] || wr4 != zs->zs_wreg[4] ||
3098*0Sstevel@tonic-gate 	    wr5 != zs->zs_wreg[5] || wr15 != zs->zs_wreg[15] ||
3099*0Sstevel@tonic-gate 	    speed != zs_speeds[baudrate]) {
3100*0Sstevel@tonic-gate 
3101*0Sstevel@tonic-gate 		za->za_flags |= ZAS_DRAINING;
3102*0Sstevel@tonic-gate 		zspp = &zs_prog[zs->zs_unit];
3103*0Sstevel@tonic-gate 		zspp->zs = zs;
3104*0Sstevel@tonic-gate 		zspp->flags = (uchar_t)flags;
3105*0Sstevel@tonic-gate 		zspp->wr4 = (uchar_t)wr4;
3106*0Sstevel@tonic-gate 		zspp->wr11 = (uchar_t)(ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD);
3107*0Sstevel@tonic-gate 
3108*0Sstevel@tonic-gate 		speed = zs_speeds[baudrate];
3109*0Sstevel@tonic-gate 		zspp->wr12 = (uchar_t)(speed & 0xff);
3110*0Sstevel@tonic-gate 		zspp->wr13 = (uchar_t)((speed >> 8) & 0xff);
3111*0Sstevel@tonic-gate 		zspp->wr3 = (uchar_t)wr3;
3112*0Sstevel@tonic-gate 		zspp->wr5 = (uchar_t)wr5;
3113*0Sstevel@tonic-gate 		zspp->wr15 = (uchar_t)wr15;
3114*0Sstevel@tonic-gate 
3115*0Sstevel@tonic-gate 		zs_program(zspp);
3116*0Sstevel@tonic-gate 		za->za_flags &= ~ZAS_DRAINING;
3117*0Sstevel@tonic-gate 	}
3118*0Sstevel@tonic-gate }
3119*0Sstevel@tonic-gate 
3120*0Sstevel@tonic-gate /*
3121*0Sstevel@tonic-gate  * Get the current speed of the console and turn it into something
3122*0Sstevel@tonic-gate  * UNIX knows about - used to preserve console speed when UNIX comes up.
3123*0Sstevel@tonic-gate  */
3124*0Sstevel@tonic-gate int
3125*0Sstevel@tonic-gate zsgetspeed(dev_t dev)
3126*0Sstevel@tonic-gate {
3127*0Sstevel@tonic-gate 	register struct zscom *zs;
3128*0Sstevel@tonic-gate 	register int uspeed, zspeed;
3129*0Sstevel@tonic-gate 	register uchar_t rr;
3130*0Sstevel@tonic-gate 
3131*0Sstevel@tonic-gate 	zs = &zscom[UNIT(dev)];
3132*0Sstevel@tonic-gate 	SCC_READ(12, zspeed);
3133*0Sstevel@tonic-gate 	SCC_READ(13, rr);
3134*0Sstevel@tonic-gate 	zspeed |= rr << 8;
3135*0Sstevel@tonic-gate 	for (uspeed = 0; uspeed < NSPEED; uspeed++)
3136*0Sstevel@tonic-gate 		if (zs_speeds[uspeed] == zspeed)
3137*0Sstevel@tonic-gate 			return (uspeed);
3138*0Sstevel@tonic-gate 	/*
3139*0Sstevel@tonic-gate 	 * 9600 baud if we can't figure it out
3140*0Sstevel@tonic-gate 	 */
3141*0Sstevel@tonic-gate 	return (ISPEED);
3142*0Sstevel@tonic-gate }
3143*0Sstevel@tonic-gate 
3144*0Sstevel@tonic-gate /*
3145*0Sstevel@tonic-gate  * callback routine when enough memory is available.
3146*0Sstevel@tonic-gate  */
3147*0Sstevel@tonic-gate static void
3148*0Sstevel@tonic-gate zsa_callback(void *arg)
3149*0Sstevel@tonic-gate {
3150*0Sstevel@tonic-gate 	struct zscom *zs = arg;
3151*0Sstevel@tonic-gate 	struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
3152*0Sstevel@tonic-gate 	int allocbcount = zsa_rstandby;
3153*0Sstevel@tonic-gate 
3154*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
3155*0Sstevel@tonic-gate 	if (za->za_bufcid) {
3156*0Sstevel@tonic-gate 		za->za_bufcid = 0;
3157*0Sstevel@tonic-gate 		ZSA_GETBLOCK(zs, allocbcount);
3158*0Sstevel@tonic-gate 	}
3159*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
3160*0Sstevel@tonic-gate }
3161*0Sstevel@tonic-gate 
3162*0Sstevel@tonic-gate /*
3163*0Sstevel@tonic-gate  * Set the receiver flags
3164*0Sstevel@tonic-gate  */
3165*0Sstevel@tonic-gate static void
3166*0Sstevel@tonic-gate zsa_set_za_rcv_flags_mask(struct asyncline *za)
3167*0Sstevel@tonic-gate {
3168*0Sstevel@tonic-gate 	register uint_t mask;
3169*0Sstevel@tonic-gate 
3170*0Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~0xFF;
3171*0Sstevel@tonic-gate 	switch (za->za_ttycommon.t_cflag & CSIZE) {
3172*0Sstevel@tonic-gate 	case CS5:
3173*0Sstevel@tonic-gate 		mask = 0x1f;
3174*0Sstevel@tonic-gate 		break;
3175*0Sstevel@tonic-gate 	case CS6:
3176*0Sstevel@tonic-gate 		mask = 0x3f;
3177*0Sstevel@tonic-gate 		break;
3178*0Sstevel@tonic-gate 	case CS7:
3179*0Sstevel@tonic-gate 		mask = 0x7f;
3180*0Sstevel@tonic-gate 		break;
3181*0Sstevel@tonic-gate 	default:
3182*0Sstevel@tonic-gate 		mask = 0xff;
3183*0Sstevel@tonic-gate 	}
3184*0Sstevel@tonic-gate 
3185*0Sstevel@tonic-gate 	za->za_rcv_flags_mask &= ~(0xFF << 16);
3186*0Sstevel@tonic-gate 	za->za_rcv_flags_mask |=  mask << 16;
3187*0Sstevel@tonic-gate 
3188*0Sstevel@tonic-gate 	if ((za->za_ttycommon.t_iflag & PARMRK) &&
3189*0Sstevel@tonic-gate 	    !(za->za_ttycommon.t_iflag & (IGNPAR|ISTRIP))) {
3190*0Sstevel@tonic-gate 		za->za_rcv_flags_mask |= DO_ESC;
3191*0Sstevel@tonic-gate 	} else
3192*0Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_ESC;
3193*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IXON) {
3194*0Sstevel@tonic-gate 		za->za_rcv_flags_mask |= DO_STOPC;
3195*0Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~0xFF;
3196*0Sstevel@tonic-gate 		za->za_rcv_flags_mask |= za->za_ttycommon.t_stopc;
3197*0Sstevel@tonic-gate 	} else
3198*0Sstevel@tonic-gate 		za->za_rcv_flags_mask &= ~DO_STOPC;
3199*0Sstevel@tonic-gate }
3200*0Sstevel@tonic-gate 
3201*0Sstevel@tonic-gate static int
3202*0Sstevel@tonic-gate zsa_suspend(struct zscom *zs)
3203*0Sstevel@tonic-gate {
3204*0Sstevel@tonic-gate 	struct asyncline	*za;
3205*0Sstevel@tonic-gate 	queue_t			*q;
3206*0Sstevel@tonic-gate 	mblk_t			*bp = NULL;
3207*0Sstevel@tonic-gate 	timeout_id_t		restart_id, kick_rcv_id;
3208*0Sstevel@tonic-gate 	struct zs_prog		*zspp;
3209*0Sstevel@tonic-gate 
3210*0Sstevel@tonic-gate 	za = (struct asyncline *)&zs->zs_priv_str;
3211*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
3212*0Sstevel@tonic-gate 	if (zs->zs_suspended) {
3213*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
3214*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
3215*0Sstevel@tonic-gate 	}
3216*0Sstevel@tonic-gate 	zs->zs_suspended = 1;
3217*0Sstevel@tonic-gate 
3218*0Sstevel@tonic-gate 	/*
3219*0Sstevel@tonic-gate 	 * Turn off interrupts and get any bytes in receiver
3220*0Sstevel@tonic-gate 	 */
3221*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
3222*0Sstevel@tonic-gate 	SCC_BIC(1, ZSWR1_INIT);
3223*0Sstevel@tonic-gate 	ZSA_KICK_RCV;
3224*0Sstevel@tonic-gate 	restart_id = za->za_zsa_restart_id;
3225*0Sstevel@tonic-gate 	za->za_zsa_restart_id = 0;
3226*0Sstevel@tonic-gate 	kick_rcv_id = za->za_kick_rcv_id;
3227*0Sstevel@tonic-gate 	za->za_kick_rcv_id = 0;
3228*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
3229*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
3230*0Sstevel@tonic-gate 
3231*0Sstevel@tonic-gate 	/*
3232*0Sstevel@tonic-gate 	 * Cancel any timeouts
3233*0Sstevel@tonic-gate 	 */
3234*0Sstevel@tonic-gate 	if (restart_id)
3235*0Sstevel@tonic-gate 		(void) untimeout(restart_id);
3236*0Sstevel@tonic-gate 	if (kick_rcv_id)
3237*0Sstevel@tonic-gate 		(void) untimeout(kick_rcv_id);
3238*0Sstevel@tonic-gate 
3239*0Sstevel@tonic-gate 	/*
3240*0Sstevel@tonic-gate 	 * Since we have turned off interrupts, zsa_txint will not be called
3241*0Sstevel@tonic-gate 	 * and no new chars will given to the chip. We just wait for the
3242*0Sstevel@tonic-gate 	 * current character(s) to drain.
3243*0Sstevel@tonic-gate 	 */
3244*0Sstevel@tonic-gate 	delay(ztdelay(za->za_ttycommon.t_cflag & CBAUD));
3245*0Sstevel@tonic-gate 
3246*0Sstevel@tonic-gate 	/*
3247*0Sstevel@tonic-gate 	 * Return remains of partially sent message to queue
3248*0Sstevel@tonic-gate 	 */
3249*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
3250*0Sstevel@tonic-gate 	if ((q = za->za_ttycommon.t_writeq) != NULL) {
3251*0Sstevel@tonic-gate 		mutex_enter(zs->zs_excl_hi);
3252*0Sstevel@tonic-gate 		if ((zs->zs_wr_cur) != NULL) {
3253*0Sstevel@tonic-gate 			za->za_flags &= ~ZAS_BUSY;
3254*0Sstevel@tonic-gate 			za->za_rcv_flags_mask &= ~DO_RETRANSMIT;
3255*0Sstevel@tonic-gate 			bp = za->za_xmitblk;
3256*0Sstevel@tonic-gate 			bp->b_rptr = zs->zs_wr_cur;
3257*0Sstevel@tonic-gate 			zs->zs_wr_cur = NULL;
3258*0Sstevel@tonic-gate 			zs->zs_wr_lim = NULL;
3259*0Sstevel@tonic-gate 			za->za_xmitblk = NULL;
3260*0Sstevel@tonic-gate 		}
3261*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl_hi);
3262*0Sstevel@tonic-gate 		if (bp)
3263*0Sstevel@tonic-gate 			(void) putbq(q, bp);
3264*0Sstevel@tonic-gate 	}
3265*0Sstevel@tonic-gate 
3266*0Sstevel@tonic-gate 	/*
3267*0Sstevel@tonic-gate 	 * Stop any breaks in progress.
3268*0Sstevel@tonic-gate 	 */
3269*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
3270*0Sstevel@tonic-gate 	if (zs->zs_wreg[5] & ZSWR5_BREAK) {
3271*0Sstevel@tonic-gate 		SCC_BIC(5, ZSWR5_BREAK);
3272*0Sstevel@tonic-gate 		za->za_flags &= ~ZAS_BREAK;
3273*0Sstevel@tonic-gate 	}
3274*0Sstevel@tonic-gate 
3275*0Sstevel@tonic-gate 	/*
3276*0Sstevel@tonic-gate 	 * Now get a copy of current registers setting.
3277*0Sstevel@tonic-gate 	 */
3278*0Sstevel@tonic-gate 	zspp = &zs_prog[zs->zs_unit];
3279*0Sstevel@tonic-gate 	zspp->zs = zs;
3280*0Sstevel@tonic-gate 	zspp->flags = 0;
3281*0Sstevel@tonic-gate 	zspp->wr3 = zs->zs_wreg[3];
3282*0Sstevel@tonic-gate 	zspp->wr4 = zs->zs_wreg[4];
3283*0Sstevel@tonic-gate 	zspp->wr5 = zs->zs_wreg[5];
3284*0Sstevel@tonic-gate 	zspp->wr11 = zs->zs_wreg[11];
3285*0Sstevel@tonic-gate 	zspp->wr12 = zs->zs_wreg[12];
3286*0Sstevel@tonic-gate 	zspp->wr13 = zs->zs_wreg[13];
3287*0Sstevel@tonic-gate 	zspp->wr15 = zs->zs_wreg[15];
3288*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
3289*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
3290*0Sstevel@tonic-gate 	/*
3291*0Sstevel@tonic-gate 	 * We do this on the off chance that zsa_close is waiting on a timed
3292*0Sstevel@tonic-gate 	 * break to complete and nothing else.
3293*0Sstevel@tonic-gate 	 */
3294*0Sstevel@tonic-gate 	cv_broadcast(&zs->zs_flags_cv);
3295*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
3296*0Sstevel@tonic-gate }
3297*0Sstevel@tonic-gate 
3298*0Sstevel@tonic-gate static int
3299*0Sstevel@tonic-gate zsa_resume(struct zscom *zs)
3300*0Sstevel@tonic-gate {
3301*0Sstevel@tonic-gate 	register struct asyncline *za;
3302*0Sstevel@tonic-gate 	struct zs_prog	*zspp;
3303*0Sstevel@tonic-gate 
3304*0Sstevel@tonic-gate 	za = (struct asyncline *)&zs->zs_priv_str;
3305*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl);
3306*0Sstevel@tonic-gate 	if (!(zs->zs_suspended)) {
3307*0Sstevel@tonic-gate 		mutex_exit(zs->zs_excl);
3308*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
3309*0Sstevel@tonic-gate 	}
3310*0Sstevel@tonic-gate 
3311*0Sstevel@tonic-gate 	/*
3312*0Sstevel@tonic-gate 	 * Restore H/W state
3313*0Sstevel@tonic-gate 	 */
3314*0Sstevel@tonic-gate 	mutex_enter(zs->zs_excl_hi);
3315*0Sstevel@tonic-gate 	zspp = &zs_prog[zs->zs_unit];
3316*0Sstevel@tonic-gate 	zs_program(zspp);
3317*0Sstevel@tonic-gate 
3318*0Sstevel@tonic-gate 	/*
3319*0Sstevel@tonic-gate 	 * Enable all interrupts for this chip and delay to let chip settle
3320*0Sstevel@tonic-gate 	 */
3321*0Sstevel@tonic-gate 	SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT);
3322*0Sstevel@tonic-gate 	DELAY(4000);
3323*0Sstevel@tonic-gate 
3324*0Sstevel@tonic-gate 	/*
3325*0Sstevel@tonic-gate 	 * Restart receiving and transmitting
3326*0Sstevel@tonic-gate 	 */
3327*0Sstevel@tonic-gate 	zs->zs_suspended = 0;
3328*0Sstevel@tonic-gate 	za->za_rcv_flags_mask |= DO_TRANSMIT;
3329*0Sstevel@tonic-gate 	za->za_ext = 1;
3330*0Sstevel@tonic-gate 	ZSSETSOFT(zs);
3331*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl_hi);
3332*0Sstevel@tonic-gate 	mutex_exit(zs->zs_excl);
3333*0Sstevel@tonic-gate 
3334*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
3335*0Sstevel@tonic-gate }
3336*0Sstevel@tonic-gate 
3337*0Sstevel@tonic-gate #ifdef ZSA_DEBUG
3338*0Sstevel@tonic-gate static void
3339*0Sstevel@tonic-gate zsa_print_info(struct zscom *zs)
3340*0Sstevel@tonic-gate {
3341*0Sstevel@tonic-gate 	register struct asyncline *za = (struct asyncline *)&zs->zs_priv_str;
3342*0Sstevel@tonic-gate 	register queue_t *q = za->za_ttycommon.t_writeq;
3343*0Sstevel@tonic-gate 
3344*0Sstevel@tonic-gate 	printf(" next q=%s\n", (RD(q))->q_next->q_qinfo->qi_minfo->mi_idname);
3345*0Sstevel@tonic-gate 	printf("unit=%d\n", zs->zs_unit);
3346*0Sstevel@tonic-gate 	printf("tflag:\n");
3347*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_flags & TS_SOFTCAR) printf(" t_fl:TS_SOFTCAR");
3348*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_flags & TS_XCLUDE) printf(" t_fl:TS_XCLUDE");
3349*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IGNBRK) printf(" t_ifl:IGNBRK");
3350*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & BRKINT) printf(" t_ifl:BRKINT");
3351*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IGNPAR) printf(" t_ifl:IGNPAR");
3352*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & PARMRK) printf(" t_ifl:PARMRK");
3353*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & INPCK) printf(" t_ifl:INPCK");
3354*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & ISTRIP) printf(" t_ifl:ISTRIP");
3355*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & INLCR) printf(" t_ifl:INLCR");
3356*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IGNCR) printf(" t_ifl:IGNCR");
3357*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & ICRNL) printf(" t_ifl:ICRNL");
3358*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IUCLC) printf(" t_ifl:IUCLC");
3359*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IXON) printf(" t_ifl:IXON");
3360*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_iflag & IXOFF) printf(" t_ifl:IXOFF");
3361*0Sstevel@tonic-gate 
3362*0Sstevel@tonic-gate 	printf("\n");
3363*0Sstevel@tonic-gate 
3364*0Sstevel@tonic-gate 
3365*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS5) printf(" t_cfl:CS5");
3366*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS6) printf(" t_cfl:CS6");
3367*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS7) printf(" t_cfl:CS7");
3368*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSIZE == CS8) printf(" t_cfl:CS8");
3369*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CSTOPB) printf(" t_cfl:CSTOPB");
3370*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CREAD) printf(" t_cfl:CREAD");
3371*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & PARENB) printf(" t_cfl:PARENB");
3372*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & PARODD) printf(" t_cfl:PARODD");
3373*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & HUPCL) printf(" t_cfl:HUPCL");
3374*0Sstevel@tonic-gate 	if (za->za_ttycommon.t_cflag & CLOCAL) printf(" t_cfl:CLOCAL");
3375*0Sstevel@tonic-gate 	printf(" t_stopc=%x", za->za_ttycommon.t_stopc);
3376*0Sstevel@tonic-gate 	printf("\n");
3377*0Sstevel@tonic-gate }
3378*0Sstevel@tonic-gate #endif
3379*0Sstevel@tonic-gate 
3380*0Sstevel@tonic-gate /*
3381*0Sstevel@tonic-gate  * Check for abort character sequence
3382*0Sstevel@tonic-gate  */
3383*0Sstevel@tonic-gate static boolean_t
3384*0Sstevel@tonic-gate abort_charseq_recognize(uchar_t ch)
3385*0Sstevel@tonic-gate {
3386*0Sstevel@tonic-gate 	static int state = 0;
3387*0Sstevel@tonic-gate #define	CNTRL(c) ((c)&037)
3388*0Sstevel@tonic-gate 	static char sequence[] = { '\r', '~', CNTRL('b') };
3389*0Sstevel@tonic-gate 
3390*0Sstevel@tonic-gate 	if (ch == sequence[state]) {
3391*0Sstevel@tonic-gate 		if (++state >= sizeof (sequence)) {
3392*0Sstevel@tonic-gate 			state = 0;
3393*0Sstevel@tonic-gate 			return (B_TRUE);
3394*0Sstevel@tonic-gate 		}
3395*0Sstevel@tonic-gate 	} else {
3396*0Sstevel@tonic-gate 		state = (ch == sequence[0]) ? 1 : 0;
3397*0Sstevel@tonic-gate 	}
3398*0Sstevel@tonic-gate 	return (B_FALSE);
3399*0Sstevel@tonic-gate }
3400