xref: /titanic_44/usr/src/uts/common/io/wscons.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * "Workstation console" multiplexor driver for Sun.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * Sends output to the primary frame buffer using the PROM monitor;
33*7c478bd9Sstevel@tonic-gate  * gets input from a stream linked below us that is the "keyboard
34*7c478bd9Sstevel@tonic-gate  * driver", below which is linked the primary keyboard.
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/termios.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/termio.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/tty.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/strredir.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/console.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
66*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
67*7c478bd9Sstevel@tonic-gate #include <sys/terminal-emulator.h>
68*7c478bd9Sstevel@tonic-gate #endif
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #define	MINLINES	10
71*7c478bd9Sstevel@tonic-gate #define	MAXLINES	48
72*7c478bd9Sstevel@tonic-gate #define	LOSCREENLINES	34
73*7c478bd9Sstevel@tonic-gate #define	HISCREENLINES	48
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate #define	MINCOLS		10
76*7c478bd9Sstevel@tonic-gate #define	MAXCOLS		120
77*7c478bd9Sstevel@tonic-gate #define	LOSCREENCOLS	80
78*7c478bd9Sstevel@tonic-gate #define	HISCREENCOLS	120
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static struct wscons {
81*7c478bd9Sstevel@tonic-gate 	int	wc_flags;		/* random flags (protected by */
82*7c478bd9Sstevel@tonic-gate 					/* write-side exclusion lock  */
83*7c478bd9Sstevel@tonic-gate 	dev_t	wc_dev;			/* major/minor for this device */
84*7c478bd9Sstevel@tonic-gate 	tty_common_t wc_ttycommon;	/* data common to all tty drivers */
85*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
86*7c478bd9Sstevel@tonic-gate 	int	wc_pendc;		/* pending output character */
87*7c478bd9Sstevel@tonic-gate 	int	wc_defer_output;	/* set if output device is "slow" */
88*7c478bd9Sstevel@tonic-gate #endif
89*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
90*7c478bd9Sstevel@tonic-gate 	struct terminal_emulator *wc_tem;	/* Terminal emulator state */
91*7c478bd9Sstevel@tonic-gate #endif
92*7c478bd9Sstevel@tonic-gate 	queue_t	*wc_kbdqueue;		/* "console keyboard" device queue */
93*7c478bd9Sstevel@tonic-gate 					/* below us */
94*7c478bd9Sstevel@tonic-gate 	bufcall_id_t wc_bufcallid;	/* id returned by qbufcall */
95*7c478bd9Sstevel@tonic-gate 	timeout_id_t wc_timeoutid;	/* id returned by qtimeout */
96*7c478bd9Sstevel@tonic-gate 	cons_polledio_t		wc_polledio; /* polled I/O function pointers */
97*7c478bd9Sstevel@tonic-gate 	cons_polledio_t		*wc_kb_polledio; /* keyboard's polledio */
98*7c478bd9Sstevel@tonic-gate 	unsigned int	wc_kb_getpolledio_id; /* id for kb CONSOPENPOLLEDIO */
99*7c478bd9Sstevel@tonic-gate 	mblk_t	*wc_pending_link;	/* I_PLINK pending for kb polledio */
100*7c478bd9Sstevel@tonic-gate } wscons;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #define	WCS_ISOPEN	0x00000001	/* open is complete */
103*7c478bd9Sstevel@tonic-gate #define	WCS_STOPPED	0x00000002	/* output is stopped */
104*7c478bd9Sstevel@tonic-gate #define	WCS_DELAY	0x00000004	/* waiting for delay to finish */
105*7c478bd9Sstevel@tonic-gate #define	WCS_BUSY	0x00000008	/* waiting for transmission to finish */
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate static int	wcopen(queue_t *, dev_t *, int, int, cred_t *);
108*7c478bd9Sstevel@tonic-gate static int	wcclose(queue_t *, int, cred_t *);
109*7c478bd9Sstevel@tonic-gate static int	wcuwput(queue_t *, mblk_t *);
110*7c478bd9Sstevel@tonic-gate static int	wclrput(queue_t *, mblk_t *);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate static struct module_info wcm_info = {
113*7c478bd9Sstevel@tonic-gate 	0,
114*7c478bd9Sstevel@tonic-gate 	"wc",
115*7c478bd9Sstevel@tonic-gate 	0,
116*7c478bd9Sstevel@tonic-gate 	INFPSZ,
117*7c478bd9Sstevel@tonic-gate 	2048,
118*7c478bd9Sstevel@tonic-gate 	128
119*7c478bd9Sstevel@tonic-gate };
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate static struct qinit wcurinit = {
122*7c478bd9Sstevel@tonic-gate 	putq,
123*7c478bd9Sstevel@tonic-gate 	NULL,
124*7c478bd9Sstevel@tonic-gate 	wcopen,
125*7c478bd9Sstevel@tonic-gate 	wcclose,
126*7c478bd9Sstevel@tonic-gate 	NULL,
127*7c478bd9Sstevel@tonic-gate 	&wcm_info,
128*7c478bd9Sstevel@tonic-gate 	NULL
129*7c478bd9Sstevel@tonic-gate };
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate static struct qinit wcuwinit = {
132*7c478bd9Sstevel@tonic-gate 	wcuwput,
133*7c478bd9Sstevel@tonic-gate 	NULL,
134*7c478bd9Sstevel@tonic-gate 	wcopen,
135*7c478bd9Sstevel@tonic-gate 	wcclose,
136*7c478bd9Sstevel@tonic-gate 	NULL,
137*7c478bd9Sstevel@tonic-gate 	&wcm_info,
138*7c478bd9Sstevel@tonic-gate 	NULL
139*7c478bd9Sstevel@tonic-gate };
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate static struct qinit wclrinit = {
142*7c478bd9Sstevel@tonic-gate 	wclrput,
143*7c478bd9Sstevel@tonic-gate 	NULL,
144*7c478bd9Sstevel@tonic-gate 	NULL,
145*7c478bd9Sstevel@tonic-gate 	NULL,
146*7c478bd9Sstevel@tonic-gate 	NULL,
147*7c478bd9Sstevel@tonic-gate 	&wcm_info,
148*7c478bd9Sstevel@tonic-gate 	NULL
149*7c478bd9Sstevel@tonic-gate };
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate  * We always putnext directly to the underlying queue.
153*7c478bd9Sstevel@tonic-gate  */
154*7c478bd9Sstevel@tonic-gate static struct qinit wclwinit = {
155*7c478bd9Sstevel@tonic-gate 	NULL,
156*7c478bd9Sstevel@tonic-gate 	NULL,
157*7c478bd9Sstevel@tonic-gate 	NULL,
158*7c478bd9Sstevel@tonic-gate 	NULL,
159*7c478bd9Sstevel@tonic-gate 	NULL,
160*7c478bd9Sstevel@tonic-gate 	&wcm_info,
161*7c478bd9Sstevel@tonic-gate 	NULL
162*7c478bd9Sstevel@tonic-gate };
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate static struct streamtab wcinfo = {
165*7c478bd9Sstevel@tonic-gate 	&wcurinit,
166*7c478bd9Sstevel@tonic-gate 	&wcuwinit,
167*7c478bd9Sstevel@tonic-gate 	&wclrinit,
168*7c478bd9Sstevel@tonic-gate 	&wclwinit,
169*7c478bd9Sstevel@tonic-gate };
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate static int wc_info(dev_info_t *, ddi_info_cmd_t, void *, void **result);
172*7c478bd9Sstevel@tonic-gate static int wc_attach(dev_info_t *, ddi_attach_cmd_t);
173*7c478bd9Sstevel@tonic-gate static dev_info_t *wc_dip;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(wc_ops, nulldev, nulldev, wc_attach, nodev, nodev,
176*7c478bd9Sstevel@tonic-gate     wc_info, D_MTPERMOD | D_MP, &wcinfo);
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate static void	wcreioctl(void *);
179*7c478bd9Sstevel@tonic-gate static void 	wcioctl(queue_t *, mblk_t *);
180*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
181*7c478bd9Sstevel@tonic-gate static void	wcopoll(void *);
182*7c478bd9Sstevel@tonic-gate static void	wconsout(void *);
183*7c478bd9Sstevel@tonic-gate #endif
184*7c478bd9Sstevel@tonic-gate static void	wcrstrt(void *);
185*7c478bd9Sstevel@tonic-gate static void	wcstart(void);
186*7c478bd9Sstevel@tonic-gate static void	wc_open_kb_polledio(struct wscons *wc, queue_t *q, mblk_t *mp);
187*7c478bd9Sstevel@tonic-gate static void	wc_close_kb_polledio(struct wscons *wc, queue_t *q, mblk_t *mp);
188*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
189*7c478bd9Sstevel@tonic-gate static void	wc_putchar(struct cons_polledio_arg *arg, unsigned char c);
190*7c478bd9Sstevel@tonic-gate #endif
191*7c478bd9Sstevel@tonic-gate static boolean_t wc_ischar(struct cons_polledio_arg *arg);
192*7c478bd9Sstevel@tonic-gate static int	wc_getchar(struct cons_polledio_arg *arg);
193*7c478bd9Sstevel@tonic-gate static void	wc_polled_enter(struct cons_polledio_arg *arg);
194*7c478bd9Sstevel@tonic-gate static void	wc_polled_exit(struct cons_polledio_arg *arg);
195*7c478bd9Sstevel@tonic-gate static void	wc_get_size(struct wscons *wscons);
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
198*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
199*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
200*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
201*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
202*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate static struct dev_ops wc_ops;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate /*
207*7c478bd9Sstevel@tonic-gate  * Debug printing
208*7c478bd9Sstevel@tonic-gate  */
209*7c478bd9Sstevel@tonic-gate #ifndef DPRINTF
210*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
211*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
212*7c478bd9Sstevel@tonic-gate static void	wc_dprintf(const char *fmt, ...) __KPRINTFLIKE(1);
213*7c478bd9Sstevel@tonic-gate #define	DPRINTF(l, m, args) \
214*7c478bd9Sstevel@tonic-gate 	(((l) >= wc_errlevel) && ((m) & wc_errmask) ?	\
215*7c478bd9Sstevel@tonic-gate 		wc_dprintf args :				\
216*7c478bd9Sstevel@tonic-gate 		(void) 0)
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate /*
219*7c478bd9Sstevel@tonic-gate  * Severity levels for printing
220*7c478bd9Sstevel@tonic-gate  */
221*7c478bd9Sstevel@tonic-gate #define	PRINT_L0	0	/* print every message */
222*7c478bd9Sstevel@tonic-gate #define	PRINT_L1	1	/* debug */
223*7c478bd9Sstevel@tonic-gate #define	PRINT_L2	2	/* quiet */
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate /*
226*7c478bd9Sstevel@tonic-gate  * Masks
227*7c478bd9Sstevel@tonic-gate  */
228*7c478bd9Sstevel@tonic-gate #define	PRINT_MASK_ALL		0xFFFFFFFFU
229*7c478bd9Sstevel@tonic-gate uint_t	wc_errmask = PRINT_MASK_ALL;
230*7c478bd9Sstevel@tonic-gate uint_t	wc_errlevel = PRINT_L2;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate #else
233*7c478bd9Sstevel@tonic-gate #define	DPRINTF(l, m, args)	/* NOTHING */
234*7c478bd9Sstevel@tonic-gate #endif
235*7c478bd9Sstevel@tonic-gate #endif
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate /*
238*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
239*7c478bd9Sstevel@tonic-gate  */
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
242*7c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a pseudo driver */
243*7c478bd9Sstevel@tonic-gate 	"Workstation multiplexer Driver 'wc' %I%",
244*7c478bd9Sstevel@tonic-gate 	&wc_ops,	/* driver ops */
245*7c478bd9Sstevel@tonic-gate };
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
248*7c478bd9Sstevel@tonic-gate 	MODREV_1,
249*7c478bd9Sstevel@tonic-gate 	&modldrv,
250*7c478bd9Sstevel@tonic-gate 	NULL
251*7c478bd9Sstevel@tonic-gate };
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate int
254*7c478bd9Sstevel@tonic-gate _init(void)
255*7c478bd9Sstevel@tonic-gate {
256*7c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate int
260*7c478bd9Sstevel@tonic-gate _fini(void)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate int
266*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
267*7c478bd9Sstevel@tonic-gate {
268*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
269*7c478bd9Sstevel@tonic-gate }
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
272*7c478bd9Sstevel@tonic-gate static int
273*7c478bd9Sstevel@tonic-gate wc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
274*7c478bd9Sstevel@tonic-gate {
275*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "wscons", S_IFCHR,
276*7c478bd9Sstevel@tonic-gate 	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
277*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
278*7c478bd9Sstevel@tonic-gate 		return (-1);
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 	wc_dip = devi;
281*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
282*7c478bd9Sstevel@tonic-gate }
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
285*7c478bd9Sstevel@tonic-gate static int
286*7c478bd9Sstevel@tonic-gate wc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
287*7c478bd9Sstevel@tonic-gate 	void **result)
288*7c478bd9Sstevel@tonic-gate {
289*7c478bd9Sstevel@tonic-gate 	int error;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
292*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
293*7c478bd9Sstevel@tonic-gate 		if (wc_dip == NULL) {
294*7c478bd9Sstevel@tonic-gate 			error = DDI_FAILURE;
295*7c478bd9Sstevel@tonic-gate 		} else {
296*7c478bd9Sstevel@tonic-gate 			*result = (void *) wc_dip;
297*7c478bd9Sstevel@tonic-gate 			error = DDI_SUCCESS;
298*7c478bd9Sstevel@tonic-gate 		}
299*7c478bd9Sstevel@tonic-gate 		break;
300*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
301*7c478bd9Sstevel@tonic-gate 		*result = (void *)0;
302*7c478bd9Sstevel@tonic-gate 		error = DDI_SUCCESS;
303*7c478bd9Sstevel@tonic-gate 		break;
304*7c478bd9Sstevel@tonic-gate 	default:
305*7c478bd9Sstevel@tonic-gate 		error = DDI_FAILURE;
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 	return (error);
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
311*7c478bd9Sstevel@tonic-gate /*
312*7c478bd9Sstevel@tonic-gate  * Output buffer. Protected by the per-module inner perimeter.
313*7c478bd9Sstevel@tonic-gate  */
314*7c478bd9Sstevel@tonic-gate #define	MAXHIWAT	2000
315*7c478bd9Sstevel@tonic-gate static char obuf[MAXHIWAT];
316*7c478bd9Sstevel@tonic-gate #endif
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
319*7c478bd9Sstevel@tonic-gate static int
320*7c478bd9Sstevel@tonic-gate wcopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
321*7c478bd9Sstevel@tonic-gate {
322*7c478bd9Sstevel@tonic-gate 	struct termios *termiosp;
323*7c478bd9Sstevel@tonic-gate 	int len;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	if (getminor(*devp) != 0)
326*7c478bd9Sstevel@tonic-gate 		return (ENXIO);		/* sorry, only one per customer */
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	if (!(wscons.wc_flags & WCS_ISOPEN)) {
329*7c478bd9Sstevel@tonic-gate 		mutex_init(&wscons.wc_ttycommon.t_excl, NULL, MUTEX_DEFAULT,
330*7c478bd9Sstevel@tonic-gate 		    NULL);
331*7c478bd9Sstevel@tonic-gate 		wscons.wc_ttycommon.t_iflag = 0;
332*7c478bd9Sstevel@tonic-gate 		/*
333*7c478bd9Sstevel@tonic-gate 		 * Get the default termios settings (cflag).
334*7c478bd9Sstevel@tonic-gate 		 * These are stored as a property in the
335*7c478bd9Sstevel@tonic-gate 		 * "options" node.
336*7c478bd9Sstevel@tonic-gate 		 */
337*7c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY,
338*7c478bd9Sstevel@tonic-gate 		    ddi_root_node(), 0, "ttymodes",
339*7c478bd9Sstevel@tonic-gate 		    (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
340*7c478bd9Sstevel@tonic-gate 		    len == sizeof (struct termios)) {
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 			wscons.wc_ttycommon.t_cflag = termiosp->c_cflag;
343*7c478bd9Sstevel@tonic-gate 			kmem_free(termiosp, len);
344*7c478bd9Sstevel@tonic-gate 		} else {
345*7c478bd9Sstevel@tonic-gate 			/*
346*7c478bd9Sstevel@tonic-gate 			 * Gack!  Whine about it.
347*7c478bd9Sstevel@tonic-gate 			 */
348*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
349*7c478bd9Sstevel@tonic-gate 			    "wc: Couldn't get ttymodes property!\n");
350*7c478bd9Sstevel@tonic-gate 		}
351*7c478bd9Sstevel@tonic-gate 		wscons.wc_ttycommon.t_iocpending = NULL;
352*7c478bd9Sstevel@tonic-gate 		wscons.wc_flags = WCS_ISOPEN;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 		wc_get_size(&wscons);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 		bzero(&(wscons.wc_polledio), sizeof (wscons.wc_polledio));
357*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_version = CONSPOLLEDIO_V0;
358*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_argument =
359*7c478bd9Sstevel@tonic-gate 			(struct cons_polledio_arg *)&wscons;
360*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
361*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_putchar = wc_putchar;
362*7c478bd9Sstevel@tonic-gate #else
363*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_putchar = NULL;
364*7c478bd9Sstevel@tonic-gate #endif
365*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_getchar = wc_getchar;
366*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_ischar = wc_ischar;
367*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_enter = wc_polled_enter;
368*7c478bd9Sstevel@tonic-gate 		wscons.wc_polledio.cons_polledio_exit = wc_polled_exit;
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
371*7c478bd9Sstevel@tonic-gate 		/*
372*7c478bd9Sstevel@tonic-gate 		 * If we're talking directly to a framebuffer, we assume
373*7c478bd9Sstevel@tonic-gate 		 * that it's a "slow" device, so that rendering should be
374*7c478bd9Sstevel@tonic-gate 		 * deferred to a timeout or softcall so that we write
375*7c478bd9Sstevel@tonic-gate 		 * a bunch of characters at once.
376*7c478bd9Sstevel@tonic-gate 		 */
377*7c478bd9Sstevel@tonic-gate 		wscons.wc_defer_output = prom_stdout_is_framebuffer();
378*7c478bd9Sstevel@tonic-gate #endif
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	if (wscons.wc_ttycommon.t_flags & TS_XCLUDE) {
382*7c478bd9Sstevel@tonic-gate 		if (secpolicy_excl_open(crp) != 0) {
383*7c478bd9Sstevel@tonic-gate 			return (EBUSY);
384*7c478bd9Sstevel@tonic-gate 		}
385*7c478bd9Sstevel@tonic-gate 	}
386*7c478bd9Sstevel@tonic-gate 	wscons.wc_ttycommon.t_readq = q;
387*7c478bd9Sstevel@tonic-gate 	wscons.wc_ttycommon.t_writeq = WR(q);
388*7c478bd9Sstevel@tonic-gate 	qprocson(q);
389*7c478bd9Sstevel@tonic-gate 	return (0);
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
393*7c478bd9Sstevel@tonic-gate static int
394*7c478bd9Sstevel@tonic-gate wcclose(queue_t *q, int flag, cred_t *crp)
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
397*7c478bd9Sstevel@tonic-gate 	if (wscons.wc_bufcallid != 0) {
398*7c478bd9Sstevel@tonic-gate 		qunbufcall(q, wscons.wc_bufcallid);
399*7c478bd9Sstevel@tonic-gate 		wscons.wc_bufcallid = 0;
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 	if (wscons.wc_timeoutid != 0) {
402*7c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, wscons.wc_timeoutid);
403*7c478bd9Sstevel@tonic-gate 		wscons.wc_timeoutid = 0;
404*7c478bd9Sstevel@tonic-gate 	}
405*7c478bd9Sstevel@tonic-gate 	ttycommon_close(&wscons.wc_ttycommon);
406*7c478bd9Sstevel@tonic-gate 	wscons.wc_flags = 0;
407*7c478bd9Sstevel@tonic-gate 	return (0);
408*7c478bd9Sstevel@tonic-gate }
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate /*
411*7c478bd9Sstevel@tonic-gate  * Put procedure for upper write queue.
412*7c478bd9Sstevel@tonic-gate  * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;
413*7c478bd9Sstevel@tonic-gate  * queue up M_BREAK, M_DELAY, and M_DATA messages for processing by
414*7c478bd9Sstevel@tonic-gate  * the start routine, and then call the start routine; discard
415*7c478bd9Sstevel@tonic-gate  * everything else.
416*7c478bd9Sstevel@tonic-gate  */
417*7c478bd9Sstevel@tonic-gate static int
418*7c478bd9Sstevel@tonic-gate wcuwput(queue_t *q, mblk_t *mp)
419*7c478bd9Sstevel@tonic-gate {
420*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	case M_STOP:
423*7c478bd9Sstevel@tonic-gate 		wscons.wc_flags |= WCS_STOPPED;
424*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
425*7c478bd9Sstevel@tonic-gate 		break;
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	case M_START:
428*7c478bd9Sstevel@tonic-gate 		wscons.wc_flags &= ~WCS_STOPPED;
429*7c478bd9Sstevel@tonic-gate 		wcstart();
430*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
431*7c478bd9Sstevel@tonic-gate 		break;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	case M_IOCTL: {
434*7c478bd9Sstevel@tonic-gate 		struct iocblk *iocp;
435*7c478bd9Sstevel@tonic-gate 		struct linkblk *linkp;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
438*7c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		case I_LINK:	/* stupid, but permitted */
441*7c478bd9Sstevel@tonic-gate 		case I_PLINK:
442*7c478bd9Sstevel@tonic-gate 			if (wscons.wc_kbdqueue != NULL) {
443*7c478bd9Sstevel@tonic-gate 				/* somebody already linked */
444*7c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EINVAL);
445*7c478bd9Sstevel@tonic-gate 				return (0);
446*7c478bd9Sstevel@tonic-gate 			}
447*7c478bd9Sstevel@tonic-gate 			linkp = (struct linkblk *)mp->b_cont->b_rptr;
448*7c478bd9Sstevel@tonic-gate 			wscons.wc_kbdqueue = WR(linkp->l_qbot);
449*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
450*7c478bd9Sstevel@tonic-gate 			iocp->ioc_count = 0;
451*7c478bd9Sstevel@tonic-gate 			wc_open_kb_polledio(&wscons, q, mp);
452*7c478bd9Sstevel@tonic-gate 			break;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 		case I_UNLINK:	/* stupid, but permitted */
455*7c478bd9Sstevel@tonic-gate 		case I_PUNLINK:
456*7c478bd9Sstevel@tonic-gate 			linkp = (struct linkblk *)mp->b_cont->b_rptr;
457*7c478bd9Sstevel@tonic-gate 			if (wscons.wc_kbdqueue != WR(linkp->l_qbot)) {
458*7c478bd9Sstevel@tonic-gate 				/* not us */
459*7c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EINVAL);
460*7c478bd9Sstevel@tonic-gate 				return (0);
461*7c478bd9Sstevel@tonic-gate 			}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
464*7c478bd9Sstevel@tonic-gate 			iocp->ioc_count = 0;
465*7c478bd9Sstevel@tonic-gate 			wc_close_kb_polledio(&wscons, q, mp);
466*7c478bd9Sstevel@tonic-gate 			break;
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 		case TCSETSW:
469*7c478bd9Sstevel@tonic-gate 		case TCSETSF:
470*7c478bd9Sstevel@tonic-gate 		case TCSETAW:
471*7c478bd9Sstevel@tonic-gate 		case TCSETAF:
472*7c478bd9Sstevel@tonic-gate 		case TCSBRK:
473*7c478bd9Sstevel@tonic-gate 			/*
474*7c478bd9Sstevel@tonic-gate 			 * The changes do not take effect until all
475*7c478bd9Sstevel@tonic-gate 			 * output queued before them is drained.
476*7c478bd9Sstevel@tonic-gate 			 * Put this message on the queue, so that
477*7c478bd9Sstevel@tonic-gate 			 * "wcstart" will see it when it's done
478*7c478bd9Sstevel@tonic-gate 			 * with the output before it.  Poke the
479*7c478bd9Sstevel@tonic-gate 			 * start routine, just in case.
480*7c478bd9Sstevel@tonic-gate 			 */
481*7c478bd9Sstevel@tonic-gate 			(void) putq(q, mp);
482*7c478bd9Sstevel@tonic-gate 			wcstart();
483*7c478bd9Sstevel@tonic-gate 			break;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 		case CONSSETABORTENABLE:
486*7c478bd9Sstevel@tonic-gate 		case CONSGETABORTENABLE:
487*7c478bd9Sstevel@tonic-gate 		case KIOCSDIRECT:
488*7c478bd9Sstevel@tonic-gate 			if (wscons.wc_kbdqueue != NULL) {
489*7c478bd9Sstevel@tonic-gate 				(void) putnext(wscons.wc_kbdqueue, mp);
490*7c478bd9Sstevel@tonic-gate 				break;
491*7c478bd9Sstevel@tonic-gate 			}
492*7c478bd9Sstevel@tonic-gate 			/* fall through */
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 		default:
495*7c478bd9Sstevel@tonic-gate 			/*
496*7c478bd9Sstevel@tonic-gate 			 * Do it now.
497*7c478bd9Sstevel@tonic-gate 			 */
498*7c478bd9Sstevel@tonic-gate 			wcioctl(q, mp);
499*7c478bd9Sstevel@tonic-gate 			break;
500*7c478bd9Sstevel@tonic-gate 		}
501*7c478bd9Sstevel@tonic-gate 		break;
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
505*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
506*7c478bd9Sstevel@tonic-gate 			/*
507*7c478bd9Sstevel@tonic-gate 			 * Flush our write queue.
508*7c478bd9Sstevel@tonic-gate 			 */
509*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);	/* XXX doesn't flush M_DELAY */
510*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;	/* it has been flushed */
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
513*7c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
514*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);	/* give the read queues a crack at it */
515*7c478bd9Sstevel@tonic-gate 		} else
516*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
517*7c478bd9Sstevel@tonic-gate 		break;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	case M_BREAK:
520*7c478bd9Sstevel@tonic-gate 		/*
521*7c478bd9Sstevel@tonic-gate 		 * Ignore these, as they make no sense.
522*7c478bd9Sstevel@tonic-gate 		 */
523*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
524*7c478bd9Sstevel@tonic-gate 		break;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	case M_DELAY:
527*7c478bd9Sstevel@tonic-gate 	case M_DATA:
528*7c478bd9Sstevel@tonic-gate 		/*
529*7c478bd9Sstevel@tonic-gate 		 * Queue the message up to be transmitted,
530*7c478bd9Sstevel@tonic-gate 		 * and poke the start routine.
531*7c478bd9Sstevel@tonic-gate 		 */
532*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
533*7c478bd9Sstevel@tonic-gate 		wcstart();
534*7c478bd9Sstevel@tonic-gate 		break;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	default:
537*7c478bd9Sstevel@tonic-gate 		/*
538*7c478bd9Sstevel@tonic-gate 		 * "No, I don't want a subscription to Chain Store Age,
539*7c478bd9Sstevel@tonic-gate 		 * thank you anyway."
540*7c478bd9Sstevel@tonic-gate 		 */
541*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
542*7c478bd9Sstevel@tonic-gate 		break;
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	return (0);
546*7c478bd9Sstevel@tonic-gate }
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate /*
549*7c478bd9Sstevel@tonic-gate  * Retry an "ioctl", now that "qbufcall" claims we may be able to allocate
550*7c478bd9Sstevel@tonic-gate  * the buffer we need.
551*7c478bd9Sstevel@tonic-gate  */
552*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
553*7c478bd9Sstevel@tonic-gate static void
554*7c478bd9Sstevel@tonic-gate wcreioctl(void *arg)
555*7c478bd9Sstevel@tonic-gate {
556*7c478bd9Sstevel@tonic-gate 	queue_t *q;
557*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	wscons.wc_bufcallid = 0;
560*7c478bd9Sstevel@tonic-gate 	q = wscons.wc_ttycommon.t_writeq;
561*7c478bd9Sstevel@tonic-gate 	if ((mp = wscons.wc_ttycommon.t_iocpending) != NULL) {
562*7c478bd9Sstevel@tonic-gate 		/* not pending any more */
563*7c478bd9Sstevel@tonic-gate 		wscons.wc_ttycommon.t_iocpending = NULL;
564*7c478bd9Sstevel@tonic-gate 		wcioctl(q, mp);
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate /*
569*7c478bd9Sstevel@tonic-gate  * Process an "ioctl" message sent down to us.
570*7c478bd9Sstevel@tonic-gate  */
571*7c478bd9Sstevel@tonic-gate static void
572*7c478bd9Sstevel@tonic-gate wcioctl(queue_t *q, mblk_t *mp)
573*7c478bd9Sstevel@tonic-gate {
574*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
575*7c478bd9Sstevel@tonic-gate 	size_t datasize;
576*7c478bd9Sstevel@tonic-gate 	int error;
577*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
578*7c478bd9Sstevel@tonic-gate 	int len;
579*7c478bd9Sstevel@tonic-gate #endif
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
584*7c478bd9Sstevel@tonic-gate 	case TIOCSWINSZ:
585*7c478bd9Sstevel@tonic-gate 		/*
586*7c478bd9Sstevel@tonic-gate 		 * Ignore all attempts to set the screen size; the
587*7c478bd9Sstevel@tonic-gate 		 * value in the EEPROM is guaranteed (modulo PROM bugs)
588*7c478bd9Sstevel@tonic-gate 		 * to be the value used by the PROM monitor code, so it
589*7c478bd9Sstevel@tonic-gate 		 * is by definition correct.  Many programs (e.g.,
590*7c478bd9Sstevel@tonic-gate 		 * "login" and "tset") will attempt to reset the size
591*7c478bd9Sstevel@tonic-gate 		 * to (0, 0) or (34, 80), neither of which is
592*7c478bd9Sstevel@tonic-gate 		 * necessarily correct.
593*7c478bd9Sstevel@tonic-gate 		 * We just ACK the message, so as not to disturb
594*7c478bd9Sstevel@tonic-gate 		 * programs that set the sizes.
595*7c478bd9Sstevel@tonic-gate 		 */
596*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = 0;	/* no data returned */
597*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
598*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
599*7c478bd9Sstevel@tonic-gate 		return;
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	case CONSOPENPOLLEDIO:
602*7c478bd9Sstevel@tonic-gate 		DPRINTF(PRINT_L1, PRINT_MASK_ALL,
603*7c478bd9Sstevel@tonic-gate 			("wcioctl: CONSOPENPOLLEDIO\n"));
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct cons_polledio *));
606*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
607*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
608*7c478bd9Sstevel@tonic-gate 			return;
609*7c478bd9Sstevel@tonic-gate 		}
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		/*
612*7c478bd9Sstevel@tonic-gate 		 * If the keyboard driver does not support polled I/O
613*7c478bd9Sstevel@tonic-gate 		 * then NAK this request.
614*7c478bd9Sstevel@tonic-gate 		 */
615*7c478bd9Sstevel@tonic-gate 		if (wscons.wc_kb_polledio != NULL) {
616*7c478bd9Sstevel@tonic-gate 			/*
617*7c478bd9Sstevel@tonic-gate 			 * We are given an appropriate-sized data block,
618*7c478bd9Sstevel@tonic-gate 			 * and return a pointer to our structure in it.
619*7c478bd9Sstevel@tonic-gate 			 */
620*7c478bd9Sstevel@tonic-gate 			*(struct cons_polledio **)mp->b_cont->b_rptr =
621*7c478bd9Sstevel@tonic-gate 				&wscons.wc_polledio;
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
624*7c478bd9Sstevel@tonic-gate 		} else {
625*7c478bd9Sstevel@tonic-gate 			/*
626*7c478bd9Sstevel@tonic-gate 			 * The driver does not support polled mode, so NAK
627*7c478bd9Sstevel@tonic-gate 			 * the request.
628*7c478bd9Sstevel@tonic-gate 			 */
629*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ENXIO);
630*7c478bd9Sstevel@tonic-gate 			return;
631*7c478bd9Sstevel@tonic-gate 		}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
634*7c478bd9Sstevel@tonic-gate 		break;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
637*7c478bd9Sstevel@tonic-gate 	case WC_OPEN_FB:
638*7c478bd9Sstevel@tonic-gate 		/*
639*7c478bd9Sstevel@tonic-gate 		 * Start out pessimistic, so that we can just jump to
640*7c478bd9Sstevel@tonic-gate 		 * the reply to bail out.
641*7c478bd9Sstevel@tonic-gate 		 */
642*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		/*
645*7c478bd9Sstevel@tonic-gate 		 * First test:  really, this should be done only from
646*7c478bd9Sstevel@tonic-gate 		 * inside the kernel.  Unfortunately, that information
647*7c478bd9Sstevel@tonic-gate 		 * doesn't seem to be available in a streams ioctl,
648*7c478bd9Sstevel@tonic-gate 		 * so restrict it to root only.  (Perhaps we could check
649*7c478bd9Sstevel@tonic-gate 		 * for ioc_cr == kcred.)
650*7c478bd9Sstevel@tonic-gate 		 */
651*7c478bd9Sstevel@tonic-gate 		if ((iocp->ioc_error = secpolicy_console(iocp->ioc_cr)) != 0)
652*7c478bd9Sstevel@tonic-gate 			goto open_fail;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 		/*
655*7c478bd9Sstevel@tonic-gate 		 * Some miscellaneous checks...
656*7c478bd9Sstevel@tonic-gate 		 */
657*7c478bd9Sstevel@tonic-gate 		iocp->ioc_error = EINVAL;
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 		/*
660*7c478bd9Sstevel@tonic-gate 		 * If we're already open, fail.
661*7c478bd9Sstevel@tonic-gate 		 */
662*7c478bd9Sstevel@tonic-gate 		if (wscons.wc_tem != NULL)
663*7c478bd9Sstevel@tonic-gate 			goto open_fail;
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 		/*
666*7c478bd9Sstevel@tonic-gate 		 * If we don't have exactly one continuation block, fail.
667*7c478bd9Sstevel@tonic-gate 		 */
668*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont == NULL ||
669*7c478bd9Sstevel@tonic-gate 		    mp->b_cont->b_cont != NULL)
670*7c478bd9Sstevel@tonic-gate 			goto open_fail;
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 		/*
673*7c478bd9Sstevel@tonic-gate 		 * If there's no null terminator in the string, fail.
674*7c478bd9Sstevel@tonic-gate 		 */
675*7c478bd9Sstevel@tonic-gate 		len = mp->b_cont->b_wptr - mp->b_cont->b_rptr;
676*7c478bd9Sstevel@tonic-gate 		if (memchr(mp->b_cont->b_rptr, 0, len) == NULL)
677*7c478bd9Sstevel@tonic-gate 			goto open_fail;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 		/*
680*7c478bd9Sstevel@tonic-gate 		 * NOTE:  should eventually get default
681*7c478bd9Sstevel@tonic-gate 		 * dimensions from a property, e.g. screen-#rows.
682*7c478bd9Sstevel@tonic-gate 		 */
683*7c478bd9Sstevel@tonic-gate 		iocp->ioc_error = tem_init(&wscons.wc_tem,
684*7c478bd9Sstevel@tonic-gate 			(char *)mp->b_cont->b_rptr, iocp->ioc_cr,
685*7c478bd9Sstevel@tonic-gate 			0, 0);
686*7c478bd9Sstevel@tonic-gate 		/*
687*7c478bd9Sstevel@tonic-gate 		 * Of course, if the terminal emulator initialization
688*7c478bd9Sstevel@tonic-gate 		 * failed, fail.
689*7c478bd9Sstevel@tonic-gate 		 */
690*7c478bd9Sstevel@tonic-gate 		if (iocp->ioc_error != 0)
691*7c478bd9Sstevel@tonic-gate 			goto open_fail;
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 		/*
694*7c478bd9Sstevel@tonic-gate 		 * Refresh terminal size with info from terminal emulator.
695*7c478bd9Sstevel@tonic-gate 		 */
696*7c478bd9Sstevel@tonic-gate 		wc_get_size(&wscons);
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 		/*
699*7c478bd9Sstevel@tonic-gate 		 * ... and succeed.
700*7c478bd9Sstevel@tonic-gate 		 */
701*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate open_fail:
704*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
705*7c478bd9Sstevel@tonic-gate 		break;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	case WC_CLOSE_FB:
708*7c478bd9Sstevel@tonic-gate 		/*
709*7c478bd9Sstevel@tonic-gate 		 * There's nothing that can call this, so it's not
710*7c478bd9Sstevel@tonic-gate 		 * really implemented.
711*7c478bd9Sstevel@tonic-gate 		 */
712*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
713*7c478bd9Sstevel@tonic-gate 		/*
714*7c478bd9Sstevel@tonic-gate 		 * However, if it were implemented, it would clearly
715*7c478bd9Sstevel@tonic-gate 		 * be root-only.
716*7c478bd9Sstevel@tonic-gate 		 */
717*7c478bd9Sstevel@tonic-gate 		if ((iocp->ioc_error = secpolicy_console(iocp->ioc_cr)) != 0)
718*7c478bd9Sstevel@tonic-gate 			goto close_fail;
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 		iocp->ioc_error = EINVAL;
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate close_fail:
723*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
724*7c478bd9Sstevel@tonic-gate 		break;
725*7c478bd9Sstevel@tonic-gate #endif
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	default:
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 		/*
730*7c478bd9Sstevel@tonic-gate 		 * The only way in which "ttycommon_ioctl" can fail is
731*7c478bd9Sstevel@tonic-gate 		 * if the "ioctl" requires a response containing data
732*7c478bd9Sstevel@tonic-gate 		 * to be returned to the user, and no mblk could be
733*7c478bd9Sstevel@tonic-gate 		 * allocated for the data.  No such "ioctl" alters our
734*7c478bd9Sstevel@tonic-gate 		 * state.  Thus, we always go ahead and do any
735*7c478bd9Sstevel@tonic-gate 		 * state-changes the "ioctl" calls for.  If we couldn't
736*7c478bd9Sstevel@tonic-gate 		 * allocate the data, "ttycommon_ioctl" has stashed the
737*7c478bd9Sstevel@tonic-gate 		 * "ioctl" away safely, so we just call "qbufcall" to
738*7c478bd9Sstevel@tonic-gate 		 * request that we be called back when we stand a
739*7c478bd9Sstevel@tonic-gate 		 * better chance of allocating the data.
740*7c478bd9Sstevel@tonic-gate 		 */
741*7c478bd9Sstevel@tonic-gate 		datasize = ttycommon_ioctl(&wscons.wc_ttycommon, q, mp, &error);
742*7c478bd9Sstevel@tonic-gate 		if (datasize != 0) {
743*7c478bd9Sstevel@tonic-gate 			if (wscons.wc_bufcallid != 0)
744*7c478bd9Sstevel@tonic-gate 				qunbufcall(q, wscons.wc_bufcallid);
745*7c478bd9Sstevel@tonic-gate 			wscons.wc_bufcallid = qbufcall(q, datasize, BPRI_HI,
746*7c478bd9Sstevel@tonic-gate 			    wcreioctl, NULL);
747*7c478bd9Sstevel@tonic-gate 			return;
748*7c478bd9Sstevel@tonic-gate 		}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 		if (error < 0) {
751*7c478bd9Sstevel@tonic-gate 			if (iocp->ioc_cmd == TCSBRK)
752*7c478bd9Sstevel@tonic-gate 				error = 0;
753*7c478bd9Sstevel@tonic-gate 			else
754*7c478bd9Sstevel@tonic-gate 				error = EINVAL;
755*7c478bd9Sstevel@tonic-gate 		}
756*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
757*7c478bd9Sstevel@tonic-gate 			iocp->ioc_error = error;
758*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCNAK;
759*7c478bd9Sstevel@tonic-gate 		}
760*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
761*7c478bd9Sstevel@tonic-gate 		break;
762*7c478bd9Sstevel@tonic-gate 	}
763*7c478bd9Sstevel@tonic-gate }
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate /*
766*7c478bd9Sstevel@tonic-gate  * This function gets the polled I/O structures from the lower
767*7c478bd9Sstevel@tonic-gate  * keyboard driver.  If any initialization or resource allocation
768*7c478bd9Sstevel@tonic-gate  * needs to be done by the lower driver, it will be done when
769*7c478bd9Sstevel@tonic-gate  * the lower driver services this message.
770*7c478bd9Sstevel@tonic-gate  */
771*7c478bd9Sstevel@tonic-gate static void
772*7c478bd9Sstevel@tonic-gate wc_open_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
773*7c478bd9Sstevel@tonic-gate {
774*7c478bd9Sstevel@tonic-gate 	mblk_t *mp2;
775*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	DPRINTF(PRINT_L1, PRINT_MASK_ALL,
778*7c478bd9Sstevel@tonic-gate 		("wc_open_kb_polledio: sending CONSOPENPOLLEDIO\n"));
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	mp2 = mkiocb(CONSOPENPOLLEDIO);
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 	if (mp2 == NULL) {
783*7c478bd9Sstevel@tonic-gate 		/*
784*7c478bd9Sstevel@tonic-gate 		 * If we can't get an mblk, then wait for it.
785*7c478bd9Sstevel@tonic-gate 		 */
786*7c478bd9Sstevel@tonic-gate 		goto nomem;
787*7c478bd9Sstevel@tonic-gate 	}
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	mp2->b_cont = allocb(sizeof (struct cons_polledio *), BPRI_HI);
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	if (mp2->b_cont == NULL) {
792*7c478bd9Sstevel@tonic-gate 		/*
793*7c478bd9Sstevel@tonic-gate 		 * If we can't get an mblk, then wait for it, and release
794*7c478bd9Sstevel@tonic-gate 		 * the mblk that we have already allocated.
795*7c478bd9Sstevel@tonic-gate 		 */
796*7c478bd9Sstevel@tonic-gate 		freemsg(mp2);
797*7c478bd9Sstevel@tonic-gate 		goto nomem;
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp2->b_rptr;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	iocp->ioc_count = sizeof (struct cons_polledio *);
803*7c478bd9Sstevel@tonic-gate 	mp2->b_cont->b_wptr = mp2->b_cont->b_rptr +
804*7c478bd9Sstevel@tonic-gate 		sizeof (struct cons_polledio *);
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	wscons->wc_pending_link = mp;
807*7c478bd9Sstevel@tonic-gate 	wscons->wc_kb_getpolledio_id = iocp->ioc_id;
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	putnext(wscons->wc_kbdqueue, mp2);
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	return;
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate nomem:
814*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
815*7c478bd9Sstevel@tonic-gate 	iocp->ioc_error = ENOMEM;
816*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCNAK;
817*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
818*7c478bd9Sstevel@tonic-gate }
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate /*
821*7c478bd9Sstevel@tonic-gate  * This function releases the polled I/O structures from the lower
822*7c478bd9Sstevel@tonic-gate  * keyboard driver.  If any de-initialization needs to be done, or
823*7c478bd9Sstevel@tonic-gate  * any resources need to be released, it will be done when the lower
824*7c478bd9Sstevel@tonic-gate  * driver services this message.
825*7c478bd9Sstevel@tonic-gate  */
826*7c478bd9Sstevel@tonic-gate static void
827*7c478bd9Sstevel@tonic-gate wc_close_kb_polledio(struct wscons *wscons, queue_t *q, mblk_t *mp)
828*7c478bd9Sstevel@tonic-gate {
829*7c478bd9Sstevel@tonic-gate 	mblk_t *mp2;
830*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	DPRINTF(PRINT_L1, PRINT_MASK_ALL,
833*7c478bd9Sstevel@tonic-gate 		("wc_close_kb_polledio: sending CONSCLOSEPOLLEDIO\n"));
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	mp2 = mkiocb(CONSCLOSEPOLLEDIO);
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	if (mp2 == NULL) {
838*7c478bd9Sstevel@tonic-gate 		/*
839*7c478bd9Sstevel@tonic-gate 		 * If we can't get an mblk, then wait for it.
840*7c478bd9Sstevel@tonic-gate 		 */
841*7c478bd9Sstevel@tonic-gate 		goto nomem;
842*7c478bd9Sstevel@tonic-gate 	}
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	mp2->b_cont = allocb(sizeof (struct cons_polledio *), BPRI_HI);
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	if (mp2->b_cont == NULL) {
847*7c478bd9Sstevel@tonic-gate 		/*
848*7c478bd9Sstevel@tonic-gate 		 * If we can't get an mblk, then wait for it, and release
849*7c478bd9Sstevel@tonic-gate 		 * the mblk that we have already allocated.
850*7c478bd9Sstevel@tonic-gate 		 */
851*7c478bd9Sstevel@tonic-gate 		freemsg(mp2);
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 		goto nomem;
854*7c478bd9Sstevel@tonic-gate 	}
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp2->b_rptr;
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 	iocp->ioc_count = 0;
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	wscons->wc_pending_link = mp;
861*7c478bd9Sstevel@tonic-gate 	wscons->wc_kb_getpolledio_id = iocp->ioc_id;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	putnext(wscons->wc_kbdqueue, mp2);
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 	return;
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate nomem:
868*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
869*7c478bd9Sstevel@tonic-gate 	iocp->ioc_error = ENOMEM;
870*7c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCNAK;
871*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
875*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
876*7c478bd9Sstevel@tonic-gate static void
877*7c478bd9Sstevel@tonic-gate wcopoll(void *arg)
878*7c478bd9Sstevel@tonic-gate {
879*7c478bd9Sstevel@tonic-gate 	queue_t *q;
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	q = wscons.wc_ttycommon.t_writeq;
882*7c478bd9Sstevel@tonic-gate 	wscons.wc_timeoutid = 0;
883*7c478bd9Sstevel@tonic-gate 	/* See if we can continue output */
884*7c478bd9Sstevel@tonic-gate 	if ((wscons.wc_flags & WCS_BUSY) && wscons.wc_pendc != -1) {
885*7c478bd9Sstevel@tonic-gate 		if (prom_mayput((char)wscons.wc_pendc) == 0) {
886*7c478bd9Sstevel@tonic-gate 			wscons.wc_pendc = -1;
887*7c478bd9Sstevel@tonic-gate 			wscons.wc_flags &= ~WCS_BUSY;
888*7c478bd9Sstevel@tonic-gate 			if (!(wscons.wc_flags&(WCS_DELAY|WCS_STOPPED)))
889*7c478bd9Sstevel@tonic-gate 				wcstart();
890*7c478bd9Sstevel@tonic-gate 		} else
891*7c478bd9Sstevel@tonic-gate 			wscons.wc_timeoutid = qtimeout(q, wcopoll, NULL, 1);
892*7c478bd9Sstevel@tonic-gate 	}
893*7c478bd9Sstevel@tonic-gate }
894*7c478bd9Sstevel@tonic-gate #endif	/* _CONSOLE_OUTPUT_VIA_FIRMWARE */
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate /*
897*7c478bd9Sstevel@tonic-gate  * Restart output on the console after a timeout.
898*7c478bd9Sstevel@tonic-gate  */
899*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
900*7c478bd9Sstevel@tonic-gate static void
901*7c478bd9Sstevel@tonic-gate wcrstrt(void *arg)
902*7c478bd9Sstevel@tonic-gate {
903*7c478bd9Sstevel@tonic-gate 	ASSERT(wscons.wc_ttycommon.t_writeq != NULL);
904*7c478bd9Sstevel@tonic-gate 	wscons.wc_flags &= ~WCS_DELAY;
905*7c478bd9Sstevel@tonic-gate 	wcstart();
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate /*
909*7c478bd9Sstevel@tonic-gate  * Start console output
910*7c478bd9Sstevel@tonic-gate  */
911*7c478bd9Sstevel@tonic-gate static void
912*7c478bd9Sstevel@tonic-gate wcstart(void)
913*7c478bd9Sstevel@tonic-gate {
914*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
915*7c478bd9Sstevel@tonic-gate 	int c;
916*7c478bd9Sstevel@tonic-gate 	ssize_t cc;
917*7c478bd9Sstevel@tonic-gate #endif
918*7c478bd9Sstevel@tonic-gate 	queue_t *q;
919*7c478bd9Sstevel@tonic-gate 	mblk_t *bp;
920*7c478bd9Sstevel@tonic-gate 	mblk_t *nbp;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	/*
923*7c478bd9Sstevel@tonic-gate 	 * If we're waiting for something to happen (delay timeout to
924*7c478bd9Sstevel@tonic-gate 	 * expire, current transmission to finish, output to be
925*7c478bd9Sstevel@tonic-gate 	 * restarted, output to finish draining), don't grab anything
926*7c478bd9Sstevel@tonic-gate 	 * new.
927*7c478bd9Sstevel@tonic-gate 	 */
928*7c478bd9Sstevel@tonic-gate 	if (wscons.wc_flags & (WCS_DELAY|WCS_BUSY|WCS_STOPPED))
929*7c478bd9Sstevel@tonic-gate 		goto out;
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 	q = wscons.wc_ttycommon.t_writeq;
932*7c478bd9Sstevel@tonic-gate 	/*
933*7c478bd9Sstevel@tonic-gate 	 * assumes that we have been called by whoever holds the
934*7c478bd9Sstevel@tonic-gate 	 * exclusionary lock on the write-side queue (protects
935*7c478bd9Sstevel@tonic-gate 	 * wc_flags and wc_pendc).
936*7c478bd9Sstevel@tonic-gate 	 */
937*7c478bd9Sstevel@tonic-gate 	for (;;) {
938*7c478bd9Sstevel@tonic-gate 		if ((bp = getq(q)) == NULL)
939*7c478bd9Sstevel@tonic-gate 			goto out;	/* nothing to transmit */
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 		/*
942*7c478bd9Sstevel@tonic-gate 		 * We have a new message to work on.
943*7c478bd9Sstevel@tonic-gate 		 * Check whether it's a delay or an ioctl (the latter
944*7c478bd9Sstevel@tonic-gate 		 * occurs if the ioctl in question was waiting for the output
945*7c478bd9Sstevel@tonic-gate 		 * to drain).  If it's one of those, process it immediately.
946*7c478bd9Sstevel@tonic-gate 		 */
947*7c478bd9Sstevel@tonic-gate 		switch (bp->b_datap->db_type) {
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 		case M_DELAY:
950*7c478bd9Sstevel@tonic-gate 			/*
951*7c478bd9Sstevel@tonic-gate 			 * Arrange for "wcrstrt" to be called when the
952*7c478bd9Sstevel@tonic-gate 			 * delay expires; it will turn WCS_DELAY off,
953*7c478bd9Sstevel@tonic-gate 			 * and call "wcstart" to grab the next message.
954*7c478bd9Sstevel@tonic-gate 			 */
955*7c478bd9Sstevel@tonic-gate 			if (wscons.wc_timeoutid != 0)
956*7c478bd9Sstevel@tonic-gate 				(void) quntimeout(q, wscons.wc_timeoutid);
957*7c478bd9Sstevel@tonic-gate 			wscons.wc_timeoutid = qtimeout(q, wcrstrt, NULL,
958*7c478bd9Sstevel@tonic-gate 			    (clock_t)(*(unsigned char *)bp->b_rptr + 6));
959*7c478bd9Sstevel@tonic-gate 			wscons.wc_flags |= WCS_DELAY;
960*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
961*7c478bd9Sstevel@tonic-gate 			goto out;	/* wait for this to finish */
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 		case M_IOCTL:
964*7c478bd9Sstevel@tonic-gate 			/*
965*7c478bd9Sstevel@tonic-gate 			 * This ioctl was waiting for the output ahead of
966*7c478bd9Sstevel@tonic-gate 			 * it to drain; obviously, it has.  Do it, and
967*7c478bd9Sstevel@tonic-gate 			 * then grab the next message after it.
968*7c478bd9Sstevel@tonic-gate 			 */
969*7c478bd9Sstevel@tonic-gate 			wcioctl(q, bp);
970*7c478bd9Sstevel@tonic-gate 			continue;
971*7c478bd9Sstevel@tonic-gate 		}
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
974*7c478bd9Sstevel@tonic-gate 		if (wscons.wc_tem != NULL) {
975*7c478bd9Sstevel@tonic-gate 		    for (nbp = bp; nbp != NULL; nbp = nbp->b_cont) {
976*7c478bd9Sstevel@tonic-gate 			    if (nbp->b_wptr > nbp->b_rptr) {
977*7c478bd9Sstevel@tonic-gate 				    (void) tem_write(wscons.wc_tem,
978*7c478bd9Sstevel@tonic-gate 					nbp->b_rptr, nbp->b_wptr - nbp->b_rptr,
979*7c478bd9Sstevel@tonic-gate 					kcred);
980*7c478bd9Sstevel@tonic-gate 			    }
981*7c478bd9Sstevel@tonic-gate 		    }
982*7c478bd9Sstevel@tonic-gate 		}
983*7c478bd9Sstevel@tonic-gate 		freemsg(bp);
984*7c478bd9Sstevel@tonic-gate #else	/* _CONSOLE_OUTPUT_VIA_FIRMWARE */
985*7c478bd9Sstevel@tonic-gate 		if ((cc = bp->b_wptr - bp->b_rptr) == 0) {
986*7c478bd9Sstevel@tonic-gate 			freemsg(bp);
987*7c478bd9Sstevel@tonic-gate 			continue;
988*7c478bd9Sstevel@tonic-gate 		}
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 		/*
991*7c478bd9Sstevel@tonic-gate 		 * Direct output to the frame buffer if this device
992*7c478bd9Sstevel@tonic-gate 		 * is not the "hardware" console.
993*7c478bd9Sstevel@tonic-gate 		 */
994*7c478bd9Sstevel@tonic-gate 		if (wscons.wc_defer_output) {
995*7c478bd9Sstevel@tonic-gate 			/*
996*7c478bd9Sstevel@tonic-gate 			 * Never do output here;
997*7c478bd9Sstevel@tonic-gate 			 * it takes forever.
998*7c478bd9Sstevel@tonic-gate 			 */
999*7c478bd9Sstevel@tonic-gate 			wscons.wc_flags |= WCS_BUSY;
1000*7c478bd9Sstevel@tonic-gate 			wscons.wc_pendc = -1;
1001*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, bp);
1002*7c478bd9Sstevel@tonic-gate 			if (q->q_count > 128) {	/* do it soon */
1003*7c478bd9Sstevel@tonic-gate 				softcall(wconsout, NULL);
1004*7c478bd9Sstevel@tonic-gate 			} else {		/* wait a bit */
1005*7c478bd9Sstevel@tonic-gate 				if (wscons.wc_timeoutid != 0)
1006*7c478bd9Sstevel@tonic-gate 					(void) quntimeout(q,
1007*7c478bd9Sstevel@tonic-gate 					    wscons.wc_timeoutid);
1008*7c478bd9Sstevel@tonic-gate 				wscons.wc_timeoutid = qtimeout(q, wconsout,
1009*7c478bd9Sstevel@tonic-gate 				    NULL, hz / 30);
1010*7c478bd9Sstevel@tonic-gate 			}
1011*7c478bd9Sstevel@tonic-gate 			goto out;
1012*7c478bd9Sstevel@tonic-gate 		}
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 		for (;;) {
1015*7c478bd9Sstevel@tonic-gate 			c = *bp->b_rptr++;
1016*7c478bd9Sstevel@tonic-gate 			cc--;
1017*7c478bd9Sstevel@tonic-gate 			if (prom_mayput((char)c) != 0) {
1018*7c478bd9Sstevel@tonic-gate 				wscons.wc_flags |= WCS_BUSY;
1019*7c478bd9Sstevel@tonic-gate 				wscons.wc_pendc = c;
1020*7c478bd9Sstevel@tonic-gate 				if (wscons.wc_timeoutid != 0)
1021*7c478bd9Sstevel@tonic-gate 					(void) quntimeout(q,
1022*7c478bd9Sstevel@tonic-gate 					    wscons.wc_timeoutid);
1023*7c478bd9Sstevel@tonic-gate 				wscons.wc_timeoutid = qtimeout(q, wcopoll,
1024*7c478bd9Sstevel@tonic-gate 				    NULL, 1);
1025*7c478bd9Sstevel@tonic-gate 				if (bp != NULL)
1026*7c478bd9Sstevel@tonic-gate 				/* not done with this message yet */
1027*7c478bd9Sstevel@tonic-gate 					(void) putbq(q, bp);
1028*7c478bd9Sstevel@tonic-gate 				goto out;
1029*7c478bd9Sstevel@tonic-gate 			}
1030*7c478bd9Sstevel@tonic-gate 			while (cc <= 0) {
1031*7c478bd9Sstevel@tonic-gate 				nbp = bp;
1032*7c478bd9Sstevel@tonic-gate 				bp = bp->b_cont;
1033*7c478bd9Sstevel@tonic-gate 				freeb(nbp);
1034*7c478bd9Sstevel@tonic-gate 				if (bp == NULL)
1035*7c478bd9Sstevel@tonic-gate 					goto out;
1036*7c478bd9Sstevel@tonic-gate 				cc = bp->b_wptr - bp->b_rptr;
1037*7c478bd9Sstevel@tonic-gate 			}
1038*7c478bd9Sstevel@tonic-gate 		}
1039*7c478bd9Sstevel@tonic-gate #endif
1040*7c478bd9Sstevel@tonic-gate 	}
1041*7c478bd9Sstevel@tonic-gate out:
1042*7c478bd9Sstevel@tonic-gate 	;
1043*7c478bd9Sstevel@tonic-gate }
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
1046*7c478bd9Sstevel@tonic-gate /*
1047*7c478bd9Sstevel@tonic-gate  * Output to frame buffer console.
1048*7c478bd9Sstevel@tonic-gate  * It takes a long time to scroll.
1049*7c478bd9Sstevel@tonic-gate  */
1050*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1051*7c478bd9Sstevel@tonic-gate static void
1052*7c478bd9Sstevel@tonic-gate wconsout(void *dummy)
1053*7c478bd9Sstevel@tonic-gate {
1054*7c478bd9Sstevel@tonic-gate 	uchar_t *cp;
1055*7c478bd9Sstevel@tonic-gate 	ssize_t cc;
1056*7c478bd9Sstevel@tonic-gate 	queue_t *q;
1057*7c478bd9Sstevel@tonic-gate 	mblk_t *bp;
1058*7c478bd9Sstevel@tonic-gate 	mblk_t *nbp;
1059*7c478bd9Sstevel@tonic-gate 	char *current_position;
1060*7c478bd9Sstevel@tonic-gate 	ssize_t bytes_left;
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 	if ((q = wscons.wc_ttycommon.t_writeq) == NULL) {
1063*7c478bd9Sstevel@tonic-gate 		return;	/* not attached to a stream */
1064*7c478bd9Sstevel@tonic-gate 	}
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate 	/*
1067*7c478bd9Sstevel@tonic-gate 	 * Set up to copy up to MAXHIWAT bytes.
1068*7c478bd9Sstevel@tonic-gate 	 */
1069*7c478bd9Sstevel@tonic-gate 	current_position = &obuf[0];
1070*7c478bd9Sstevel@tonic-gate 	bytes_left = MAXHIWAT;
1071*7c478bd9Sstevel@tonic-gate 	while ((bp = getq(q)) != NULL) {
1072*7c478bd9Sstevel@tonic-gate 		if (bp->b_datap->db_type == M_IOCTL) {
1073*7c478bd9Sstevel@tonic-gate 			/*
1074*7c478bd9Sstevel@tonic-gate 			 * This ioctl was waiting for the output ahead of
1075*7c478bd9Sstevel@tonic-gate 			 * it to drain; obviously, it has.  Put it back
1076*7c478bd9Sstevel@tonic-gate 			 * so that "wcstart" can handle it, and transmit
1077*7c478bd9Sstevel@tonic-gate 			 * what we've got.
1078*7c478bd9Sstevel@tonic-gate 			 */
1079*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, bp);
1080*7c478bd9Sstevel@tonic-gate 			goto transmit;
1081*7c478bd9Sstevel@tonic-gate 		}
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 		do {
1084*7c478bd9Sstevel@tonic-gate 			cp = bp->b_rptr;
1085*7c478bd9Sstevel@tonic-gate 			cc = bp->b_wptr - cp;
1086*7c478bd9Sstevel@tonic-gate 			while (cc != 0) {
1087*7c478bd9Sstevel@tonic-gate 				if (bytes_left == 0) {
1088*7c478bd9Sstevel@tonic-gate 					/*
1089*7c478bd9Sstevel@tonic-gate 					 * Out of buffer space; put this
1090*7c478bd9Sstevel@tonic-gate 					 * buffer back on the queue, and
1091*7c478bd9Sstevel@tonic-gate 					 * transmit what we have.
1092*7c478bd9Sstevel@tonic-gate 					 */
1093*7c478bd9Sstevel@tonic-gate 					bp->b_rptr = cp;
1094*7c478bd9Sstevel@tonic-gate 					(void) putbq(q, bp);
1095*7c478bd9Sstevel@tonic-gate 					goto transmit;
1096*7c478bd9Sstevel@tonic-gate 				}
1097*7c478bd9Sstevel@tonic-gate 				*current_position++ = *cp++;
1098*7c478bd9Sstevel@tonic-gate 				cc--;
1099*7c478bd9Sstevel@tonic-gate 				bytes_left--;
1100*7c478bd9Sstevel@tonic-gate 			}
1101*7c478bd9Sstevel@tonic-gate 			nbp = bp;
1102*7c478bd9Sstevel@tonic-gate 			bp = bp->b_cont;
1103*7c478bd9Sstevel@tonic-gate 			freeb(nbp);
1104*7c478bd9Sstevel@tonic-gate 		} while (bp != NULL);
1105*7c478bd9Sstevel@tonic-gate 	}
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate transmit:
1108*7c478bd9Sstevel@tonic-gate 	if ((cc = MAXHIWAT - bytes_left) != 0)
1109*7c478bd9Sstevel@tonic-gate 		console_puts(obuf, cc);
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 	wscons.wc_flags &= ~WCS_BUSY;
1112*7c478bd9Sstevel@tonic-gate 	wcstart();
1113*7c478bd9Sstevel@tonic-gate }
1114*7c478bd9Sstevel@tonic-gate #endif
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate /*
1117*7c478bd9Sstevel@tonic-gate  * Put procedure for lower read queue.
1118*7c478bd9Sstevel@tonic-gate  * Pass everything up to queue above "upper half".
1119*7c478bd9Sstevel@tonic-gate  */
1120*7c478bd9Sstevel@tonic-gate static int
1121*7c478bd9Sstevel@tonic-gate wclrput(queue_t *q, mblk_t *mp)
1122*7c478bd9Sstevel@tonic-gate {
1123*7c478bd9Sstevel@tonic-gate 	queue_t *upq;
1124*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	DPRINTF(PRINT_L1, PRINT_MASK_ALL,
1127*7c478bd9Sstevel@tonic-gate 		("wclrput: wclrput type = 0x%x\n", mp->b_datap->db_type));
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
1132*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr == FLUSHW || *mp->b_rptr == FLUSHRW) {
1133*7c478bd9Sstevel@tonic-gate 			/*
1134*7c478bd9Sstevel@tonic-gate 			 * Flush our write queue.
1135*7c478bd9Sstevel@tonic-gate 			 */
1136*7c478bd9Sstevel@tonic-gate 			/* XXX doesn't flush M_DELAY */
1137*7c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
1138*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr = FLUSHR;	/* it has been flushed */
1139*7c478bd9Sstevel@tonic-gate 		}
1140*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr == FLUSHR || *mp->b_rptr == FLUSHRW) {
1141*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
1142*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr = FLUSHW;	/* it has been flushed */
1143*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);	/* give the read queues a crack at it */
1144*7c478bd9Sstevel@tonic-gate 		} else
1145*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1146*7c478bd9Sstevel@tonic-gate 		break;
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	case M_DATA:
1149*7c478bd9Sstevel@tonic-gate 		if ((upq = wscons.wc_ttycommon.t_readq) != NULL) {
1150*7c478bd9Sstevel@tonic-gate 			if (!canput(upq->q_next)) {
1151*7c478bd9Sstevel@tonic-gate 				ttycommon_qfull(&wscons.wc_ttycommon, upq);
1152*7c478bd9Sstevel@tonic-gate 				wcstart();
1153*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1154*7c478bd9Sstevel@tonic-gate 			} else
1155*7c478bd9Sstevel@tonic-gate 				putnext(upq, mp);
1156*7c478bd9Sstevel@tonic-gate 		} else
1157*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1158*7c478bd9Sstevel@tonic-gate 		break;
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 	case M_IOCACK:
1161*7c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
1162*7c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
1163*7c478bd9Sstevel@tonic-gate 		if (wscons.wc_pending_link != NULL &&
1164*7c478bd9Sstevel@tonic-gate 		    iocp->ioc_id == wscons.wc_kb_getpolledio_id) {
1165*7c478bd9Sstevel@tonic-gate 			switch (mp->b_datap->db_type) {
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 			case M_IOCACK:
1168*7c478bd9Sstevel@tonic-gate 				switch (iocp->ioc_cmd) {
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 				case CONSOPENPOLLEDIO:
1172*7c478bd9Sstevel@tonic-gate 					DPRINTF(PRINT_L1, PRINT_MASK_ALL,
1173*7c478bd9Sstevel@tonic-gate 						("wclrput: "
1174*7c478bd9Sstevel@tonic-gate 						"ACK CONSOPENPOLLEDIO\n"));
1175*7c478bd9Sstevel@tonic-gate 					wscons.wc_kb_polledio =
1176*7c478bd9Sstevel@tonic-gate 					    *(struct cons_polledio **)
1177*7c478bd9Sstevel@tonic-gate 						mp->b_cont->b_rptr;
1178*7c478bd9Sstevel@tonic-gate 					break;
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 				case CONSCLOSEPOLLEDIO:
1181*7c478bd9Sstevel@tonic-gate 					DPRINTF(PRINT_L1, PRINT_MASK_ALL,
1182*7c478bd9Sstevel@tonic-gate 						("wclrput: "
1183*7c478bd9Sstevel@tonic-gate 						"ACK CONSCLOSEPOLLEDIO\n"));
1184*7c478bd9Sstevel@tonic-gate 					wscons.wc_kb_polledio = NULL;
1185*7c478bd9Sstevel@tonic-gate 					wscons.wc_kbdqueue = NULL;
1186*7c478bd9Sstevel@tonic-gate 					break;
1187*7c478bd9Sstevel@tonic-gate 				default:
1188*7c478bd9Sstevel@tonic-gate 					DPRINTF(PRINT_L1, PRINT_MASK_ALL,
1189*7c478bd9Sstevel@tonic-gate 						("wclrput: "
1190*7c478bd9Sstevel@tonic-gate 						"ACK UNKNOWN\n"));
1191*7c478bd9Sstevel@tonic-gate 				}
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 				break;
1194*7c478bd9Sstevel@tonic-gate 			case M_IOCNAK:
1195*7c478bd9Sstevel@tonic-gate 				/*
1196*7c478bd9Sstevel@tonic-gate 				 * Keyboard may or may not support polled I/O.
1197*7c478bd9Sstevel@tonic-gate 				 * This ioctl may have been rejected because
1198*7c478bd9Sstevel@tonic-gate 				 * we only have the wc->conskbd chain built,
1199*7c478bd9Sstevel@tonic-gate 				 * and the keyboard driver has not been linked
1200*7c478bd9Sstevel@tonic-gate 				 * underneath conskbd yet.
1201*7c478bd9Sstevel@tonic-gate 				 */
1202*7c478bd9Sstevel@tonic-gate 				DPRINTF(PRINT_L1, PRINT_MASK_ALL,
1203*7c478bd9Sstevel@tonic-gate 					("wclrput: NAK\n"));
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 				switch (iocp->ioc_cmd) {
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 				case CONSCLOSEPOLLEDIO:
1208*7c478bd9Sstevel@tonic-gate 					wscons.wc_kb_polledio = NULL;
1209*7c478bd9Sstevel@tonic-gate 					wscons.wc_kbdqueue = NULL;
1210*7c478bd9Sstevel@tonic-gate 					break;
1211*7c478bd9Sstevel@tonic-gate 				}
1212*7c478bd9Sstevel@tonic-gate 				break;
1213*7c478bd9Sstevel@tonic-gate 			}
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 			/*
1216*7c478bd9Sstevel@tonic-gate 			 * Discard the response, replace it with the
1217*7c478bd9Sstevel@tonic-gate 			 * pending response to the I_PLINK, then let it
1218*7c478bd9Sstevel@tonic-gate 			 * flow upward.
1219*7c478bd9Sstevel@tonic-gate 			 */
1220*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1221*7c478bd9Sstevel@tonic-gate 			mp = wscons.wc_pending_link;
1222*7c478bd9Sstevel@tonic-gate 			wscons.wc_pending_link = NULL;
1223*7c478bd9Sstevel@tonic-gate 			wscons.wc_kb_getpolledio_id = 0;
1224*7c478bd9Sstevel@tonic-gate 		}
1225*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	default:	/* inc M_ERROR, M_HANGUP, M_IOCACK, M_IOCNAK, ... */
1228*7c478bd9Sstevel@tonic-gate 		DPRINTF(PRINT_L1, PRINT_MASK_ALL,
1229*7c478bd9Sstevel@tonic-gate 			("wclrput: Message DISCARDED\n"));
1230*7c478bd9Sstevel@tonic-gate 		if ((upq = wscons.wc_ttycommon.t_readq) != NULL) {
1231*7c478bd9Sstevel@tonic-gate 			putnext(upq, mp);
1232*7c478bd9Sstevel@tonic-gate 		} else {
1233*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1234*7c478bd9Sstevel@tonic-gate 		}
1235*7c478bd9Sstevel@tonic-gate 		break;
1236*7c478bd9Sstevel@tonic-gate 	}
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	return (0);
1239*7c478bd9Sstevel@tonic-gate }
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate /*
1242*7c478bd9Sstevel@tonic-gate  * Auxiliary routines, for allowing the workstation console to be redirected.
1243*7c478bd9Sstevel@tonic-gate  */
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate /*
1246*7c478bd9Sstevel@tonic-gate  * Given a minor device number for a wscons instance, return a held vnode for
1247*7c478bd9Sstevel@tonic-gate  * it.
1248*7c478bd9Sstevel@tonic-gate  *
1249*7c478bd9Sstevel@tonic-gate  * We currently support only one instance, for the "workstation console".
1250*7c478bd9Sstevel@tonic-gate  */
1251*7c478bd9Sstevel@tonic-gate int
1252*7c478bd9Sstevel@tonic-gate wcvnget(minor_t unit, vnode_t **vpp)
1253*7c478bd9Sstevel@tonic-gate {
1254*7c478bd9Sstevel@tonic-gate 	if (unit != 0 || rwsconsvp == NULL)
1255*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	/*
1258*7c478bd9Sstevel@tonic-gate 	 * rwsconsvp is already held, so we don't have to do it here.
1259*7c478bd9Sstevel@tonic-gate 	 */
1260*7c478bd9Sstevel@tonic-gate 	*vpp = rwsconsvp;
1261*7c478bd9Sstevel@tonic-gate 	return (0);
1262*7c478bd9Sstevel@tonic-gate }
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate /*
1265*7c478bd9Sstevel@tonic-gate  * Release the vnode that wcvnget returned.
1266*7c478bd9Sstevel@tonic-gate  */
1267*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1268*7c478bd9Sstevel@tonic-gate void
1269*7c478bd9Sstevel@tonic-gate wcvnrele(minor_t unit, vnode_t *vp)
1270*7c478bd9Sstevel@tonic-gate {
1271*7c478bd9Sstevel@tonic-gate 	/*
1272*7c478bd9Sstevel@tonic-gate 	 * Nothing to do, since we only support the workstation console
1273*7c478bd9Sstevel@tonic-gate 	 * instance that's held throughout the system's lifetime.
1274*7c478bd9Sstevel@tonic-gate 	 */
1275*7c478bd9Sstevel@tonic-gate }
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate /*
1278*7c478bd9Sstevel@tonic-gate  * The declaration and initialization of the wscons_srvnops has been
1279*7c478bd9Sstevel@tonic-gate  * moved to space.c to allow "wc" to become a loadable module.
1280*7c478bd9Sstevel@tonic-gate  */
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_SOFTWARE)
1283*7c478bd9Sstevel@tonic-gate /*
1284*7c478bd9Sstevel@tonic-gate  * This is for systems without OBP.
1285*7c478bd9Sstevel@tonic-gate  */
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate static void
1288*7c478bd9Sstevel@tonic-gate wc_putchar(struct cons_polledio_arg *arg, unsigned char c)
1289*7c478bd9Sstevel@tonic-gate {
1290*7c478bd9Sstevel@tonic-gate 	if (c == '\n')
1291*7c478bd9Sstevel@tonic-gate 		wc_putchar(arg, '\r');
1292*7c478bd9Sstevel@tonic-gate 
1293*7c478bd9Sstevel@tonic-gate 	if (wscons.wc_tem == NULL) {
1294*7c478bd9Sstevel@tonic-gate 		/*
1295*7c478bd9Sstevel@tonic-gate 		 * We have no terminal emulator configured.  We have no
1296*7c478bd9Sstevel@tonic-gate 		 * recourse but to drop the output on the floor.
1297*7c478bd9Sstevel@tonic-gate 		 */
1298*7c478bd9Sstevel@tonic-gate 		return;
1299*7c478bd9Sstevel@tonic-gate 	}
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 	/*
1302*7c478bd9Sstevel@tonic-gate 	 * We ignore the result code.  After all, what could we do?
1303*7c478bd9Sstevel@tonic-gate 	 * Write something to the console??
1304*7c478bd9Sstevel@tonic-gate 	 */
1305*7c478bd9Sstevel@tonic-gate 	(void) tem_polled_write(wscons.wc_tem, &c, 1);
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate #endif	/* _CONSOLE_OUTPUT_VIA_SOFTWARE */
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate /*
1310*7c478bd9Sstevel@tonic-gate  * These are for systems without OBP, and for devices that cannot be
1311*7c478bd9Sstevel@tonic-gate  * shared between Solaris and the OBP.
1312*7c478bd9Sstevel@tonic-gate  */
1313*7c478bd9Sstevel@tonic-gate static int
1314*7c478bd9Sstevel@tonic-gate wc_getchar(struct cons_polledio_arg *arg)
1315*7c478bd9Sstevel@tonic-gate {
1316*7c478bd9Sstevel@tonic-gate 	struct wscons *wscons = (struct wscons *)arg;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_kb_polledio == NULL) {
1319*7c478bd9Sstevel@tonic-gate 		prom_printf("wscons:  getchar with no keyboard support");
1320*7c478bd9Sstevel@tonic-gate 		prom_printf("Halted...");
1321*7c478bd9Sstevel@tonic-gate 		for (;;)
1322*7c478bd9Sstevel@tonic-gate 			/* HANG FOREVER */;
1323*7c478bd9Sstevel@tonic-gate 	}
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	return (wscons->wc_kb_polledio->cons_polledio_getchar(
1326*7c478bd9Sstevel@tonic-gate 			wscons->wc_kb_polledio->cons_polledio_argument));
1327*7c478bd9Sstevel@tonic-gate }
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate static boolean_t
1330*7c478bd9Sstevel@tonic-gate wc_ischar(struct cons_polledio_arg *arg)
1331*7c478bd9Sstevel@tonic-gate {
1332*7c478bd9Sstevel@tonic-gate 	struct wscons *wscons = (struct wscons *)arg;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_kb_polledio == NULL)
1335*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	return (wscons->wc_kb_polledio->cons_polledio_ischar(
1338*7c478bd9Sstevel@tonic-gate 			wscons->wc_kb_polledio->cons_polledio_argument));
1339*7c478bd9Sstevel@tonic-gate }
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate static void
1342*7c478bd9Sstevel@tonic-gate wc_polled_enter(struct cons_polledio_arg *arg)
1343*7c478bd9Sstevel@tonic-gate {
1344*7c478bd9Sstevel@tonic-gate 	struct wscons *wscons = (struct wscons *)arg;
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_kb_polledio == NULL)
1347*7c478bd9Sstevel@tonic-gate 		return;
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_kb_polledio->cons_polledio_enter != NULL) {
1350*7c478bd9Sstevel@tonic-gate 		wscons->wc_kb_polledio->cons_polledio_enter(
1351*7c478bd9Sstevel@tonic-gate 			wscons->wc_kb_polledio->cons_polledio_argument);
1352*7c478bd9Sstevel@tonic-gate 	}
1353*7c478bd9Sstevel@tonic-gate }
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate static void
1356*7c478bd9Sstevel@tonic-gate wc_polled_exit(struct cons_polledio_arg *arg)
1357*7c478bd9Sstevel@tonic-gate {
1358*7c478bd9Sstevel@tonic-gate 	struct wscons *wscons = (struct wscons *)arg;
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_kb_polledio == NULL)
1361*7c478bd9Sstevel@tonic-gate 		return;
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_kb_polledio->cons_polledio_exit != NULL) {
1364*7c478bd9Sstevel@tonic-gate 		wscons->wc_kb_polledio->cons_polledio_exit(
1365*7c478bd9Sstevel@tonic-gate 			wscons->wc_kb_polledio->cons_polledio_argument);
1366*7c478bd9Sstevel@tonic-gate 	}
1367*7c478bd9Sstevel@tonic-gate }
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1371*7c478bd9Sstevel@tonic-gate static void
1372*7c478bd9Sstevel@tonic-gate wc_dprintf(const char *fmt, ...)
1373*7c478bd9Sstevel@tonic-gate {
1374*7c478bd9Sstevel@tonic-gate 	char buf[256];
1375*7c478bd9Sstevel@tonic-gate 	va_list ap;
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
1378*7c478bd9Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
1379*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "wc: %s", buf);
1382*7c478bd9Sstevel@tonic-gate }
1383*7c478bd9Sstevel@tonic-gate #endif
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate #if	defined(_CONSOLE_OUTPUT_VIA_FIRMWARE)
1386*7c478bd9Sstevel@tonic-gate static int
1387*7c478bd9Sstevel@tonic-gate atou_n(char *s, int n)
1388*7c478bd9Sstevel@tonic-gate {
1389*7c478bd9Sstevel@tonic-gate 	int res;
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	res = 0;
1392*7c478bd9Sstevel@tonic-gate 	while (n > 0 && *s != '\0') {
1393*7c478bd9Sstevel@tonic-gate 		if (*s < '0' || *s > '9')
1394*7c478bd9Sstevel@tonic-gate 			return (0);
1395*7c478bd9Sstevel@tonic-gate 		res *= 10;
1396*7c478bd9Sstevel@tonic-gate 		res += *s - '0';
1397*7c478bd9Sstevel@tonic-gate 		s++;
1398*7c478bd9Sstevel@tonic-gate 		n--;
1399*7c478bd9Sstevel@tonic-gate 	}
1400*7c478bd9Sstevel@tonic-gate 	return (res);
1401*7c478bd9Sstevel@tonic-gate }
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate static int
1404*7c478bd9Sstevel@tonic-gate get_option_string_int(char *name)
1405*7c478bd9Sstevel@tonic-gate {
1406*7c478bd9Sstevel@tonic-gate 	char *data;
1407*7c478bd9Sstevel@tonic-gate 	uint_t len;
1408*7c478bd9Sstevel@tonic-gate 	int res;
1409*7c478bd9Sstevel@tonic-gate 
1410*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ddi_root_node(), 0,
1411*7c478bd9Sstevel@tonic-gate 	    name, (uchar_t **)&data, &len) != DDI_PROP_SUCCESS)
1412*7c478bd9Sstevel@tonic-gate 		return (0);
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 	res = atou_n(data, len);
1415*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(data);
1416*7c478bd9Sstevel@tonic-gate 	return (res);
1417*7c478bd9Sstevel@tonic-gate }
1418*7c478bd9Sstevel@tonic-gate #endif
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate /*
1421*7c478bd9Sstevel@tonic-gate  * Gets the number of text rows and columns and the
1422*7c478bd9Sstevel@tonic-gate  * width and height (in pixels) of the console.
1423*7c478bd9Sstevel@tonic-gate  */
1424*7c478bd9Sstevel@tonic-gate static void
1425*7c478bd9Sstevel@tonic-gate wc_get_size(struct wscons *wscons)
1426*7c478bd9Sstevel@tonic-gate {
1427*7c478bd9Sstevel@tonic-gate #if	defined _CONSOLE_OUTPUT_VIA_FIRMWARE
1428*7c478bd9Sstevel@tonic-gate 	static char *cols = "screen-#columns";
1429*7c478bd9Sstevel@tonic-gate 	static char *rows = "screen-#rows";
1430*7c478bd9Sstevel@tonic-gate 	static char *width = "screen-width";
1431*7c478bd9Sstevel@tonic-gate 	static char *height = "screen-height";
1432*7c478bd9Sstevel@tonic-gate 	struct winsize *t;
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	t = &wscons->wc_ttycommon.t_size;
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate 	/*
1437*7c478bd9Sstevel@tonic-gate 	 * Get the number of columns
1438*7c478bd9Sstevel@tonic-gate 	 */
1439*7c478bd9Sstevel@tonic-gate 	t->ws_col = (unsigned short)get_option_string_int(cols);
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate 	if (t->ws_col < MINCOLS)
1442*7c478bd9Sstevel@tonic-gate 		t->ws_col = LOSCREENCOLS;
1443*7c478bd9Sstevel@tonic-gate 	else if (t->ws_col > MAXCOLS)
1444*7c478bd9Sstevel@tonic-gate 		t->ws_col = HISCREENCOLS;
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 	/*
1447*7c478bd9Sstevel@tonic-gate 	 * Get the number of rows
1448*7c478bd9Sstevel@tonic-gate 	 */
1449*7c478bd9Sstevel@tonic-gate 	t->ws_row = (unsigned short)get_option_string_int(rows);
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate 	if (t->ws_row < MINLINES)
1452*7c478bd9Sstevel@tonic-gate 		t->ws_row = LOSCREENLINES;
1453*7c478bd9Sstevel@tonic-gate 	else if (t->ws_row > MAXLINES)
1454*7c478bd9Sstevel@tonic-gate 		t->ws_row = HISCREENLINES;
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	/*
1457*7c478bd9Sstevel@tonic-gate 	 * Get the size in pixels.
1458*7c478bd9Sstevel@tonic-gate 	 */
1459*7c478bd9Sstevel@tonic-gate 	t->ws_xpixel = (unsigned short)get_option_string_int(width);
1460*7c478bd9Sstevel@tonic-gate 	t->ws_ypixel = (unsigned short)get_option_string_int(height);
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate #else	/* _CONSOLE_OUTPUT_VIA_SOFTWARE */
1463*7c478bd9Sstevel@tonic-gate 	struct winsize *t;
1464*7c478bd9Sstevel@tonic-gate 	int r, c, x, y;
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 	t = &wscons->wc_ttycommon.t_size;
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	if (wscons->wc_tem != NULL) {
1469*7c478bd9Sstevel@tonic-gate 		tem_get_size(wscons->wc_tem, &r, &c, &x, &y);
1470*7c478bd9Sstevel@tonic-gate 		t->ws_row = (unsigned short)r;
1471*7c478bd9Sstevel@tonic-gate 		t->ws_col = (unsigned short)c;
1472*7c478bd9Sstevel@tonic-gate 		t->ws_xpixel = (unsigned short)x;
1473*7c478bd9Sstevel@tonic-gate 		t->ws_ypixel = (unsigned short)y;
1474*7c478bd9Sstevel@tonic-gate 	} else {
1475*7c478bd9Sstevel@tonic-gate 		t->ws_row = LOSCREENLINES;
1476*7c478bd9Sstevel@tonic-gate 		t->ws_col = LOSCREENCOLS;
1477*7c478bd9Sstevel@tonic-gate 		t->ws_xpixel = 0;
1478*7c478bd9Sstevel@tonic-gate 		t->ws_ypixel = 0;
1479*7c478bd9Sstevel@tonic-gate 	}
1480*7c478bd9Sstevel@tonic-gate #endif
1481*7c478bd9Sstevel@tonic-gate }
1482