xref: /netbsd-src/sys/dev/wscons/wsdisplay.c (revision a7e090f70e491979434963c9a27df4020fe0a18b)
1 /* $NetBSD: wsdisplay.c,v 1.132 2010/03/11 04:00:36 mrg Exp $ */
2 
3 /*
4  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: wsdisplay.c,v 1.132 2010/03/11 04:00:36 mrg Exp $");
35 
36 #include "opt_wsdisplay_compat.h"
37 #include "opt_wsmsgattrs.h"
38 #include "wskbd.h"
39 #include "wsmux.h"
40 #include "wsdisplay.h"
41 
42 #include <sys/param.h>
43 #include <sys/conf.h>
44 #include <sys/device.h>
45 #include <sys/ioctl.h>
46 #include <sys/poll.h>
47 #include <sys/kernel.h>
48 #include <sys/proc.h>
49 #include <sys/malloc.h>
50 #include <sys/syslog.h>
51 #include <sys/systm.h>
52 #include <sys/tty.h>
53 #include <sys/signalvar.h>
54 #include <sys/errno.h>
55 #include <sys/fcntl.h>
56 #include <sys/vnode.h>
57 #include <sys/kauth.h>
58 
59 #include <dev/wscons/wsconsio.h>
60 #include <dev/wscons/wseventvar.h>
61 #include <dev/wscons/wsmuxvar.h>
62 #include <dev/wscons/wsdisplayvar.h>
63 #include <dev/wscons/wsksymvar.h>
64 #include <dev/wscons/wsksymdef.h>
65 #include <dev/wscons/wsemulvar.h>
66 #include <dev/wscons/wscons_callbacks.h>
67 #include <dev/cons.h>
68 
69 #include "locators.h"
70 
71 struct wsscreen_internal {
72 	const struct wsdisplay_emulops *emulops;
73 	void	*emulcookie;
74 
75 	const struct wsscreen_descr *scrdata;
76 
77 	const struct wsemul_ops *wsemul;
78 	void	*wsemulcookie;
79 };
80 
81 struct wsscreen {
82 	struct wsscreen_internal *scr_dconf;
83 
84 	struct tty *scr_tty;
85 	int	scr_hold_screen;		/* hold tty output */
86 
87 	int scr_flags;
88 #define SCR_OPEN 1		/* is it open? */
89 #define SCR_WAITACTIVE 2	/* someone waiting on activation */
90 #define SCR_GRAPHICS 4		/* graphics mode, no text (emulation) output */
91 #define	SCR_DUMBFB 8		/* in use as a dumb fb (iff SCR_GRAPHICS) */
92 	const struct wscons_syncops *scr_syncops;
93 	void *scr_synccookie;
94 
95 #ifdef WSDISPLAY_COMPAT_RAWKBD
96 	int scr_rawkbd;
97 #endif
98 
99 	struct wsdisplay_softc *sc;
100 
101 #ifdef DIAGNOSTIC
102 	/* XXX this is to support a hack in emulinput, see comment below */
103 	int scr_in_ttyoutput;
104 #endif
105 };
106 
107 struct wsscreen *wsscreen_attach(struct wsdisplay_softc *, int,
108 				 const char *,
109 				 const struct wsscreen_descr *, void *,
110 				 int, int, long);
111 void wsscreen_detach(struct wsscreen *);
112 int wsdisplay_addscreen(struct wsdisplay_softc *, int, const char *, const char *);
113 static void wsdisplay_addscreen_print(struct wsdisplay_softc *, int, int);
114 static void wsdisplay_closescreen(struct wsdisplay_softc *, struct wsscreen *);
115 int wsdisplay_delscreen(struct wsdisplay_softc *, int, int);
116 
117 #define WSDISPLAY_MAXSCREEN 8
118 
119 struct wsdisplay_softc {
120 	device_t sc_dev;
121 
122 	const struct wsdisplay_accessops *sc_accessops;
123 	void	*sc_accesscookie;
124 
125 	const struct wsscreen_list *sc_scrdata;
126 #ifdef WSDISPLAY_SCROLLSUPPORT
127 	struct wsdisplay_scroll_data sc_scroll_values;
128 #endif
129 
130 	struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
131 	int sc_focusidx;	/* available only if sc_focus isn't null */
132 	struct wsscreen *sc_focus;
133 
134 	struct wseventvar evar;
135 
136 	int	sc_isconsole;
137 
138 	int sc_flags;
139 #define SC_SWITCHPENDING 1
140 #define SC_SWITCHERROR 2
141 #define SC_XATTACHED 4 /* X server active */
142 	kmutex_t sc_flagsmtx; /* for flags, might also be used for focus */
143 	kcondvar_t sc_flagscv;
144 
145 	int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */
146 
147 #if NWSKBD > 0
148 	struct wsevsrc *sc_input;
149 #ifdef WSDISPLAY_COMPAT_RAWKBD
150 	int sc_rawkbd;
151 #endif
152 #endif /* NWSKBD > 0 */
153 };
154 
155 #ifdef WSDISPLAY_SCROLLSUPPORT
156 
157 struct wsdisplay_scroll_data wsdisplay_default_scroll_values = {
158 	WSDISPLAY_SCROLL_DOALL,
159 	25,
160 	2,
161 };
162 #endif
163 
164 extern struct cfdriver wsdisplay_cd;
165 
166 /* Autoconfiguration definitions. */
167 static int wsdisplay_emul_match(device_t , cfdata_t, void *);
168 static void wsdisplay_emul_attach(device_t, device_t, void *);
169 static int wsdisplay_noemul_match(device_t, cfdata_t, void *);
170 static void wsdisplay_noemul_attach(device_t, device_t, void *);
171 static bool wsdisplay_suspend(device_t, const pmf_qual_t *);
172 
173 CFATTACH_DECL_NEW(wsdisplay_emul, sizeof (struct wsdisplay_softc),
174     wsdisplay_emul_match, wsdisplay_emul_attach, NULL, NULL);
175 
176 CFATTACH_DECL_NEW(wsdisplay_noemul, sizeof (struct wsdisplay_softc),
177     wsdisplay_noemul_match, wsdisplay_noemul_attach, NULL, NULL);
178 
179 dev_type_open(wsdisplayopen);
180 dev_type_close(wsdisplayclose);
181 dev_type_read(wsdisplayread);
182 dev_type_write(wsdisplaywrite);
183 dev_type_ioctl(wsdisplayioctl);
184 dev_type_stop(wsdisplaystop);
185 dev_type_tty(wsdisplaytty);
186 dev_type_poll(wsdisplaypoll);
187 dev_type_mmap(wsdisplaymmap);
188 dev_type_kqfilter(wsdisplaykqfilter);
189 
190 const struct cdevsw wsdisplay_cdevsw = {
191 	wsdisplayopen, wsdisplayclose, wsdisplayread, wsdisplaywrite,
192 	wsdisplayioctl, wsdisplaystop, wsdisplaytty, wsdisplaypoll,
193 	wsdisplaymmap, wsdisplaykqfilter, D_TTY
194 };
195 
196 static void wsdisplaystart(struct tty *);
197 static int wsdisplayparam(struct tty *, struct termios *);
198 
199 
200 #define	WSDISPLAYUNIT(dev)	(minor(dev) >> 8)
201 #define	WSDISPLAYSCREEN(dev)	(minor(dev) & 0xff)
202 #define ISWSDISPLAYSTAT(dev)	(WSDISPLAYSCREEN(dev) == 254)
203 #define ISWSDISPLAYCTL(dev)	(WSDISPLAYSCREEN(dev) == 255)
204 #define WSDISPLAYMINOR(unit, screen)	(((unit) << 8) | (screen))
205 
206 #define	WSSCREEN_HAS_EMULATOR(scr)	((scr)->scr_dconf->wsemul != NULL)
207 #define	WSSCREEN_HAS_TTY(scr)	((scr)->scr_tty != NULL)
208 
209 static void wsdisplay_common_attach(struct wsdisplay_softc *sc,
210 	    int console, int kbdmux, const struct wsscreen_list *,
211 	    const struct wsdisplay_accessops *accessops,
212 	    void *accesscookie);
213 
214 #ifdef WSDISPLAY_COMPAT_RAWKBD
215 int wsdisplay_update_rawkbd(struct wsdisplay_softc *,
216 				 struct wsscreen *);
217 #endif
218 
219 static int wsdisplay_console_initted;
220 static int wsdisplay_console_attached;
221 static struct wsdisplay_softc *wsdisplay_console_device;
222 static struct wsscreen_internal wsdisplay_console_conf;
223 
224 static int wsdisplay_getc_dummy(dev_t);
225 static void wsdisplay_pollc(dev_t, int);
226 
227 static int wsdisplay_cons_pollmode;
228 static void (*wsdisplay_cons_kbd_pollc)(dev_t, int);
229 
230 static struct consdev wsdisplay_cons = {
231 	NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
232 	wsdisplay_pollc, NULL, NULL, NULL, NODEV, CN_NORMAL
233 };
234 
235 #ifndef WSDISPLAY_DEFAULTSCREENS
236 # define WSDISPLAY_DEFAULTSCREENS	0
237 #endif
238 int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS;
239 
240 static int wsdisplay_switch1(device_t, int, int);
241 static void wsdisplay_switch1_cb(void *, int, int);
242 static int wsdisplay_switch2(device_t, int, int);
243 static void wsdisplay_switch2_cb(void *, int, int);
244 static int wsdisplay_switch3(device_t, int, int);
245 static void wsdisplay_switch3_cb(void *, int, int);
246 
247 int wsdisplay_clearonclose;
248 
249 struct wsscreen *
250 wsscreen_attach(struct wsdisplay_softc *sc, int console, const char *emul,
251 	const struct wsscreen_descr *type, void *cookie, int ccol,
252 	int crow, long defattr)
253 {
254 	struct wsscreen_internal *dconf;
255 	struct wsscreen *scr;
256 
257 	scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK);
258 	if (!scr)
259 		return (NULL);
260 
261 	if (console) {
262 		dconf = &wsdisplay_console_conf;
263 		/*
264 		 * If there's an emulation, tell it about the callback argument.
265 		 * The other stuff is already there.
266 		 */
267 		if (dconf->wsemul != NULL)
268 			(*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0);
269 	} else { /* not console */
270 		dconf = malloc(sizeof(struct wsscreen_internal),
271 			       M_DEVBUF, M_NOWAIT);
272 		dconf->emulops = type->textops;
273 		dconf->emulcookie = cookie;
274 		if (dconf->emulops) {
275 			dconf->wsemul = wsemul_pick(emul);
276 			if (dconf->wsemul == NULL) {
277 				free(dconf, M_DEVBUF);
278 				free(scr, M_DEVBUF);
279 				return (NULL);
280 			}
281 			dconf->wsemulcookie =
282 			  (*dconf->wsemul->attach)(0, type, cookie,
283 						   ccol, crow, scr, defattr);
284 		} else
285 			dconf->wsemul = NULL;
286 		dconf->scrdata = type;
287 	}
288 
289 	scr->scr_dconf = dconf;
290 
291 	scr->scr_tty = ttymalloc();
292 	tty_attach(scr->scr_tty);
293 	scr->scr_hold_screen = 0;
294 	if (WSSCREEN_HAS_EMULATOR(scr))
295 		scr->scr_flags = 0;
296 	else
297 		scr->scr_flags = SCR_GRAPHICS;
298 
299 	scr->scr_syncops = 0;
300 	scr->sc = sc;
301 #ifdef WSDISPLAY_COMPAT_RAWKBD
302 	scr->scr_rawkbd = 0;
303 #endif
304 	return (scr);
305 }
306 
307 void
308 wsscreen_detach(struct wsscreen *scr)
309 {
310 	u_int ccol, crow; /* XXX */
311 
312 	if (WSSCREEN_HAS_TTY(scr)) {
313 		tty_detach(scr->scr_tty);
314 		ttyfree(scr->scr_tty);
315 	}
316 	if (WSSCREEN_HAS_EMULATOR(scr)) {
317 		(*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie,
318 						  &ccol, &crow);
319 		wsemul_drop(scr->scr_dconf->wsemul);
320 	}
321 	free(scr->scr_dconf, M_DEVBUF);
322 	free(scr, M_DEVBUF);
323 }
324 
325 const struct wsscreen_descr *
326 wsdisplay_screentype_pick(const struct wsscreen_list *scrdata, const char *name)
327 {
328 	int i;
329 	const struct wsscreen_descr *scr;
330 
331 	KASSERT(scrdata->nscreens > 0);
332 
333 	if (name == NULL)
334 		return (scrdata->screens[0]);
335 
336 	for (i = 0; i < scrdata->nscreens; i++) {
337 		scr = scrdata->screens[i];
338 		if (!strcmp(name, scr->name))
339 			return (scr);
340 	}
341 
342 	return (0);
343 }
344 
345 /*
346  * print info about attached screen
347  */
348 static void
349 wsdisplay_addscreen_print(struct wsdisplay_softc *sc, int idx, int count)
350 {
351 	aprint_verbose_dev(sc->sc_dev, "screen %d", idx);
352 	if (count > 1)
353 		aprint_verbose("-%d", idx + (count-1));
354 	aprint_verbose(" added (%s", sc->sc_scr[idx]->scr_dconf->scrdata->name);
355 	if (WSSCREEN_HAS_EMULATOR(sc->sc_scr[idx])) {
356 		aprint_verbose(", %s emulation",
357 			sc->sc_scr[idx]->scr_dconf->wsemul->name);
358 	}
359 	aprint_verbose(")\n");
360 }
361 
362 int
363 wsdisplay_addscreen(struct wsdisplay_softc *sc, int idx,
364 	const char *screentype, const char *emul)
365 {
366 	const struct wsscreen_descr *scrdesc;
367 	int error;
368 	void *cookie;
369 	int ccol, crow;
370 	long defattr;
371 	struct wsscreen *scr;
372 	int s;
373 
374 	if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
375 		return (EINVAL);
376 	if (sc->sc_scr[idx] != NULL)
377 		return (EBUSY);
378 
379 	scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype);
380 	if (!scrdesc)
381 		return (ENXIO);
382 	error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie,
383 			scrdesc, &cookie, &ccol, &crow, &defattr);
384 	if (error)
385 		return (error);
386 
387 	scr = wsscreen_attach(sc, 0, emul, scrdesc,
388 			      cookie, ccol, crow, defattr);
389 	if (scr == NULL) {
390 		(*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
391 						 cookie);
392 		return (ENXIO);
393 	}
394 
395 	sc->sc_scr[idx] = scr;
396 
397 	/* if no screen has focus yet, activate the first we get */
398 	s = spltty();
399 	if (!sc->sc_focus) {
400 		(*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
401 						 scr->scr_dconf->emulcookie,
402 						 0, 0, 0);
403 		sc->sc_focusidx = idx;
404 		sc->sc_focus = scr;
405 	}
406 	splx(s);
407 	return (0);
408 }
409 
410 static void
411 wsdisplay_closescreen(struct wsdisplay_softc *sc, struct wsscreen *scr)
412 {
413 	int maj, mn, idx;
414 
415 	/* hangup */
416 	if (WSSCREEN_HAS_TTY(scr)) {
417 		struct tty *tp = scr->scr_tty;
418 		(*tp->t_linesw->l_modem)(tp, 0);
419 	}
420 
421 	/* locate the major number */
422 	maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
423 	/* locate the screen index */
424 	for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++)
425 		if (scr == sc->sc_scr[idx])
426 			break;
427 #ifdef DIAGNOSTIC
428 	if (idx == WSDISPLAY_MAXSCREEN)
429 		panic("wsdisplay_forceclose: bad screen");
430 #endif
431 
432 	/* nuke the vnodes */
433 	mn = WSDISPLAYMINOR(device_unit(sc->sc_dev), idx);
434 	vdevgone(maj, mn, mn, VCHR);
435 }
436 
437 #ifdef WSDISPLAY_SCROLLSUPPORT
438 void
439 wsdisplay_scroll(void *arg, int op)
440 {
441 	device_t dv = arg;
442 	struct wsdisplay_softc *sc = device_private(dv);
443 	struct wsscreen *scr;
444 	int lines;
445 
446 	scr = sc->sc_focus;
447 
448 	if (!scr)
449 		return;
450 
451 	if (op == WSDISPLAY_SCROLL_RESET)
452 		lines = 0;
453 	else {
454 		lines = (op & WSDISPLAY_SCROLL_LOW) ?
455 			sc->sc_scroll_values.slowlines :
456 			sc->sc_scroll_values.fastlines;
457 		if (op & WSDISPLAY_SCROLL_BACKWARD)
458 			lines = -(lines);
459 	}
460 
461 	if (sc->sc_accessops->scroll) {
462 		(*sc->sc_accessops->scroll)(sc->sc_accesscookie,
463 		    sc->sc_focus->scr_dconf->emulcookie, lines);
464 	}
465 }
466 #endif
467 
468 int
469 wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags)
470 {
471 	struct wsscreen *scr;
472 	int s;
473 	void *cookie;
474 
475 	if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
476 		return (EINVAL);
477 	if ((scr = sc->sc_scr[idx]) == NULL)
478 		return (ENXIO);
479 
480 	if (scr->scr_dconf == &wsdisplay_console_conf ||
481 	    scr->scr_syncops ||
482 	    ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE)))
483 		return(EBUSY);
484 
485 	wsdisplay_closescreen(sc, scr);
486 
487 	/*
488 	 * delete pointers, so neither device entries
489 	 * nor keyboard input can reference it anymore
490 	 */
491 	s = spltty();
492 	if (sc->sc_focus == scr) {
493 		sc->sc_focus = 0;
494 #ifdef WSDISPLAY_COMPAT_RAWKBD
495 		wsdisplay_update_rawkbd(sc, 0);
496 #endif
497 	}
498 	sc->sc_scr[idx] = 0;
499 	splx(s);
500 
501 	/*
502 	 * Wake up processes waiting for the screen to
503 	 * be activated. Sleepers must check whether
504 	 * the screen still exists.
505 	 */
506 	if (scr->scr_flags & SCR_WAITACTIVE)
507 		wakeup(scr);
508 
509 	/* save a reference to the graphics screen */
510 	cookie = scr->scr_dconf->emulcookie;
511 
512 	wsscreen_detach(scr);
513 
514 	(*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
515 					 cookie);
516 
517 	aprint_verbose_dev(sc->sc_dev, "screen %d deleted\n", idx);
518 	return (0);
519 }
520 
521 /*
522  * Autoconfiguration functions.
523  */
524 int
525 wsdisplay_emul_match(device_t parent, cfdata_t match, void *aux)
526 {
527 	struct wsemuldisplaydev_attach_args *ap = aux;
528 
529 	if (match->cf_loc[WSEMULDISPLAYDEVCF_CONSOLE] !=
530 	    WSEMULDISPLAYDEVCF_CONSOLE_DEFAULT) {
531 		/*
532 		 * If console-ness of device specified, either match
533 		 * exactly (at high priority), or fail.
534 		 */
535 		if (match->cf_loc[WSEMULDISPLAYDEVCF_CONSOLE] != 0 &&
536 		    ap->console != 0)
537 			return (10);
538 		else
539 			return (0);
540 	}
541 
542 	/* If console-ness unspecified, it wins. */
543 	return (1);
544 }
545 
546 void
547 wsdisplay_emul_attach(device_t parent, device_t self, void *aux)
548 {
549 	struct wsdisplay_softc *sc = device_private(self);
550 	struct wsemuldisplaydev_attach_args *ap = aux;
551 
552 	sc->sc_dev = self;
553 
554 	/* Don't allow more than one console to attach */
555 	if (wsdisplay_console_attached && ap->console)
556 		ap->console = 0;
557 
558 	wsdisplay_common_attach(sc, ap->console,
559 	     device_cfdata(self)->cf_loc[WSEMULDISPLAYDEVCF_KBDMUX],
560 	     ap->scrdata, ap->accessops, ap->accesscookie);
561 
562 	if (ap->console) {
563 		int maj;
564 
565 		/* locate the major number */
566 		maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
567 
568 		cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(device_unit(self),
569 					 0));
570 	}
571 }
572 
573 /* Print function (for parent devices). */
574 int
575 wsemuldisplaydevprint(void *aux, const char *pnp)
576 {
577 #if 0 /* -Wunused */
578 	struct wsemuldisplaydev_attach_args *ap = aux;
579 #endif
580 
581 	if (pnp)
582 		aprint_normal("wsdisplay at %s", pnp);
583 #if 0 /* don't bother; it's ugly */
584 	aprint_normal(" console %d", ap->console);
585 #endif
586 
587 	return (UNCONF);
588 }
589 
590 int
591 wsdisplay_noemul_match(device_t parent, cfdata_t match, void *aux)
592 {
593 #if 0 /* -Wunused */
594 	struct wsdisplaydev_attach_args *ap = aux;
595 #endif
596 
597 	/* Always match. */
598 	return (1);
599 }
600 
601 void
602 wsdisplay_noemul_attach(device_t parent, device_t self, void *aux)
603 {
604 	struct wsdisplay_softc *sc = device_private(self);
605 	struct wsdisplaydev_attach_args *ap = aux;
606 
607 	sc->sc_dev = self;
608 
609 	wsdisplay_common_attach(sc, 0,
610 	    device_cfdata(self)->cf_loc[WSDISPLAYDEVCF_KBDMUX], NULL,
611 	    ap->accessops, ap->accesscookie);
612 }
613 
614 static void
615 wsdisplay_swdone_cb(void *arg, int error, int waitok)
616 {
617 	struct wsdisplay_softc *sc = arg;
618 
619 	mutex_enter(&sc->sc_flagsmtx);
620 	KASSERT(sc->sc_flags & SC_SWITCHPENDING);
621 	if (error)
622 		sc->sc_flags |= SC_SWITCHERROR;
623 	sc->sc_flags &= ~SC_SWITCHPENDING;
624 	cv_signal(&sc->sc_flagscv);
625 	mutex_exit(&sc->sc_flagsmtx);
626 }
627 
628 static int
629 wsdisplay_dosync(struct wsdisplay_softc *sc, int attach)
630 {
631 	struct wsscreen *scr;
632 	int (*op)(void *, int, void (*)(void *, int, int), void *);
633 	int res;
634 
635 	scr = sc->sc_focus;
636 	if (!scr || !scr->scr_syncops)
637 		return 0; /* XXX check SCR_GRAPHICS? */
638 
639 	sc->sc_flags |= SC_SWITCHPENDING;
640 	sc->sc_flags &= ~SC_SWITCHERROR;
641 	if (attach)
642 		op = scr->scr_syncops->attach;
643 	else
644 		op = scr->scr_syncops->detach;
645 	res = (*op)(scr->scr_synccookie, 1, wsdisplay_swdone_cb, sc);
646 	if (res == EAGAIN) {
647 		/* wait for callback */
648 		mutex_enter(&sc->sc_flagsmtx);
649 		while (sc->sc_flags & SC_SWITCHPENDING)
650 			cv_wait_sig(&sc->sc_flagscv, &sc->sc_flagsmtx);
651 		mutex_exit(&sc->sc_flagsmtx);
652 		if (sc->sc_flags & SC_SWITCHERROR)
653 			return (EIO); /* XXX pass real error */
654 	} else {
655 		sc->sc_flags &= ~SC_SWITCHPENDING;
656 		if (res)
657 			return (res);
658 	}
659 	if (attach)
660 		sc->sc_flags |= SC_XATTACHED;
661 	else
662 		sc->sc_flags &= ~SC_XATTACHED;
663 	return 0;
664 }
665 
666 int
667 wsdisplay_handlex(int resume)
668 {
669 	int i, res;
670 	device_t dv;
671 
672 	for (i = 0; i < wsdisplay_cd.cd_ndevs; i++) {
673 		dv = device_lookup(&wsdisplay_cd, i);
674 		if (!dv)
675 			continue;
676 		res = wsdisplay_dosync(device_private(dv), resume);
677 		if (res)
678 			return (res);
679 	}
680 	return (0);
681 }
682 
683 static bool
684 wsdisplay_suspend(device_t dv, const pmf_qual_t *qual)
685 {
686 	struct wsdisplay_softc *sc = device_private(dv);
687 #ifdef DIAGNOSTIC
688 	struct wsscreen *scr = sc->sc_focus;
689 	if (sc->sc_flags & SC_XATTACHED) {
690 		KASSERT(scr && scr->scr_syncops);
691 	}
692 #endif
693 #if 1
694 	/*
695 	 * XXX X servers should have been detached earlier.
696 	 * pmf currently ignores our return value and suspends the system
697 	 * after device suspend failures. We try to avoid bigger damage
698 	 * and try to detach the X server here. This is not safe because
699 	 * other parts of the system which the X server deals with
700 	 * might already be suspended.
701 	 */
702 	if (sc->sc_flags & SC_XATTACHED) {
703 		printf("%s: emergency X server detach\n", device_xname(dv));
704 		wsdisplay_dosync(sc, 0);
705 	}
706 #endif
707 	return (!(sc->sc_flags & SC_XATTACHED));
708 }
709 
710 /* Print function (for parent devices). */
711 int
712 wsdisplaydevprint(void *aux, const char *pnp)
713 {
714 #if 0 /* -Wunused */
715 	struct wsdisplaydev_attach_args *ap = aux;
716 #endif
717 
718 	if (pnp)
719 		aprint_normal("wsdisplay at %s", pnp);
720 
721 	return (UNCONF);
722 }
723 
724 static void
725 wsdisplay_common_attach(struct wsdisplay_softc *sc, int console, int kbdmux,
726 	const struct wsscreen_list *scrdata,
727 	const struct wsdisplay_accessops *accessops,
728 	void *accesscookie)
729 {
730 	int i, start=0;
731 #if NWSKBD > 0
732 	struct wsevsrc *kme;
733 #if NWSMUX > 0
734 	struct wsmux_softc *mux;
735 
736 	if (kbdmux >= 0)
737 		mux = wsmux_getmux(kbdmux);
738 	else
739 		mux = wsmux_create("dmux", device_unit(sc->sc_dev));
740 	/* XXX panic()ing isn't nice, but attach cannot fail */
741 	if (mux == NULL)
742 		panic("wsdisplay_common_attach: no memory");
743 	sc->sc_input = &mux->sc_base;
744 	mux->sc_base.me_dispdv = sc->sc_dev;
745 	aprint_normal(" kbdmux %d", kbdmux);
746 #else
747 	if (kbdmux >= 0)
748 		aprint_normal(" (kbdmux ignored)");
749 #endif
750 #endif
751 
752 	sc->sc_isconsole = console;
753 
754 	if (console) {
755 		KASSERT(wsdisplay_console_initted);
756 		KASSERT(wsdisplay_console_device == NULL);
757 
758 		sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
759 		wsdisplay_console_device = sc;
760 
761 		aprint_normal(": console (%s, %s emulation)",
762 		       wsdisplay_console_conf.scrdata->name,
763 		       wsdisplay_console_conf.wsemul->name);
764 
765 #if NWSKBD > 0
766 		kme = wskbd_set_console_display(sc->sc_dev, sc->sc_input);
767 		if (kme != NULL)
768 			aprint_normal(", using %s", device_xname(kme->me_dv));
769 #if NWSMUX == 0
770 		sc->sc_input = kme;
771 #endif
772 #endif
773 
774 		sc->sc_focusidx = 0;
775 		sc->sc_focus = sc->sc_scr[0];
776 		start = 1;
777 
778 		wsdisplay_console_attached = 1;
779 	}
780 	aprint_normal("\n");
781 	aprint_naive("\n");
782 
783 #if NWSKBD > 0 && NWSMUX > 0
784 	wsmux_set_display(mux, sc->sc_dev);
785 #endif
786 
787 	mutex_init(&sc->sc_flagsmtx, MUTEX_DEFAULT, IPL_NONE);
788 	cv_init(&sc->sc_flagscv, "wssw");
789 
790 	sc->sc_accessops = accessops;
791 	sc->sc_accesscookie = accesscookie;
792 	sc->sc_scrdata = scrdata;
793 
794 #ifdef WSDISPLAY_SCROLLSUPPORT
795 	sc->sc_scroll_values = wsdisplay_default_scroll_values;
796 #endif
797 
798 	/*
799 	 * Set up a number of virtual screens if wanted. The
800 	 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
801 	 * is for special cases like installation kernels.
802 	 */
803 	for (i = start; i < wsdisplay_defaultscreens; i++) {
804 		if (wsdisplay_addscreen(sc, i, 0, 0))
805 			break;
806 	}
807 
808 	if (i > start)
809 		wsdisplay_addscreen_print(sc, start, i-start);
810 
811 	if (!pmf_device_register(sc->sc_dev, wsdisplay_suspend, NULL))
812 		aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n");
813 }
814 
815 void
816 wsdisplay_cnattach(const struct wsscreen_descr *type, void *cookie,
817 	int ccol, int crow, long defattr)
818 {
819 	const struct wsemul_ops *wsemul;
820 
821 	KASSERT(wsdisplay_console_initted < 2);
822 	KASSERT(type->nrows > 0);
823 	KASSERT(type->ncols > 0);
824 	KASSERT(crow < type->nrows);
825 	KASSERT(ccol < type->ncols);
826 
827 	wsdisplay_console_conf.emulops = type->textops;
828 	wsdisplay_console_conf.emulcookie = cookie;
829 	wsdisplay_console_conf.scrdata = type;
830 
831 	wsemul = wsemul_pick(0); /* default */
832 	wsdisplay_console_conf.wsemul = wsemul;
833 	wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
834 								  ccol, crow,
835 								  defattr);
836 
837 	cn_tab = &wsdisplay_cons;
838 	wsdisplay_console_initted = 2;
839 }
840 
841 void
842 wsdisplay_preattach(const struct wsscreen_descr *type, void *cookie,
843 	int ccol, int crow, long defattr)
844 {
845 	const struct wsemul_ops *wsemul;
846 
847 	KASSERT(!wsdisplay_console_initted);
848 	KASSERT(type->nrows > 0);
849 	KASSERT(type->ncols > 0);
850 	KASSERT(crow < type->nrows);
851 	KASSERT(ccol < type->ncols);
852 
853 	wsdisplay_console_conf.emulops = type->textops;
854 	wsdisplay_console_conf.emulcookie = cookie;
855 	wsdisplay_console_conf.scrdata = type;
856 
857 	wsemul = wsemul_pick(0); /* default */
858 	wsdisplay_console_conf.wsemul = wsemul;
859 	wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
860 								  ccol, crow,
861 								  defattr);
862 
863 	cn_tab = &wsdisplay_cons;
864 	wsdisplay_console_initted = 1;
865 }
866 
867 /*
868  * Tty and cdevsw functions.
869  */
870 int
871 wsdisplayopen(dev_t dev, int flag, int mode, struct lwp *l)
872 {
873 	struct wsdisplay_softc *sc;
874 	struct tty *tp;
875 	int newopen, error;
876 	struct wsscreen *scr;
877 
878 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
879 	if (sc == NULL)			/* make sure it was attached */
880 		return (ENXIO);
881 
882 	if (ISWSDISPLAYSTAT(dev)) {
883 		wsevent_init(&sc->evar, l->l_proc);
884 		return (0);
885 	}
886 
887 	if (ISWSDISPLAYCTL(dev))
888 		return (0);
889 
890 	if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
891 		return (ENXIO);
892 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
893 		return (ENXIO);
894 
895 	if (WSSCREEN_HAS_TTY(scr)) {
896 		tp = scr->scr_tty;
897 		tp->t_oproc = wsdisplaystart;
898 		tp->t_param = wsdisplayparam;
899 		tp->t_dev = dev;
900 		newopen = (tp->t_state & TS_ISOPEN) == 0;
901 
902 		if (kauth_authorize_device_tty(l->l_cred,
903 			KAUTH_DEVICE_TTY_OPEN, tp))
904 			return (EBUSY);
905 
906 		if (newopen) {
907 			ttychars(tp);
908 			tp->t_iflag = TTYDEF_IFLAG;
909 			tp->t_oflag = TTYDEF_OFLAG;
910 			tp->t_cflag = TTYDEF_CFLAG;
911 			tp->t_lflag = TTYDEF_LFLAG;
912 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
913 			wsdisplayparam(tp, &tp->t_termios);
914 			ttsetwater(tp);
915 		}
916 		tp->t_state |= TS_CARR_ON;
917 
918 		error = ((*tp->t_linesw->l_open)(dev, tp));
919 		if (error)
920 			return (error);
921 
922 		if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
923 			/* set window sizes as appropriate, and reset
924 			 the emulation */
925 			tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
926 			tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
927 
928 			/* wsdisplay_set_emulation() */
929 		}
930 	}
931 
932 	scr->scr_flags |= SCR_OPEN;
933 	return (0);
934 }
935 
936 int
937 wsdisplayclose(dev_t dev, int flag, int mode, struct lwp *l)
938 {
939 	device_t dv;
940 	struct wsdisplay_softc *sc;
941 	struct tty *tp;
942 	struct wsscreen *scr;
943 
944 	dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
945 	sc = device_private(dv);
946 
947 	if (ISWSDISPLAYSTAT(dev)) {
948 		wsevent_fini(&sc->evar);
949 		return (0);
950 	}
951 
952 	if (ISWSDISPLAYCTL(dev))
953 		return (0);
954 
955 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
956 		return (0);
957 
958 	if (WSSCREEN_HAS_TTY(scr)) {
959 		if (scr->scr_hold_screen) {
960 			int s;
961 
962 			/* XXX RESET KEYBOARD LEDS, etc. */
963 			s = spltty();	/* avoid conflict with keyboard */
964 			wsdisplay_kbdholdscreen(dv, 0);
965 			splx(s);
966 		}
967 		tp = scr->scr_tty;
968 		(*tp->t_linesw->l_close)(tp, flag);
969 		ttyclose(tp);
970 	}
971 
972 	if (scr->scr_syncops)
973 		(*scr->scr_syncops->destroy)(scr->scr_synccookie);
974 
975 	if (WSSCREEN_HAS_EMULATOR(scr)) {
976 		scr->scr_flags &= ~SCR_GRAPHICS;
977 		(*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
978 						 WSEMUL_RESET);
979 		if (wsdisplay_clearonclose)
980 			(*scr->scr_dconf->wsemul->reset)
981 				(scr->scr_dconf->wsemulcookie,
982 				 WSEMUL_CLEARSCREEN);
983 	}
984 
985 #ifdef WSDISPLAY_COMPAT_RAWKBD
986 	if (scr->scr_rawkbd) {
987 		int kbmode = WSKBD_TRANSLATED;
988 		(void)wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
989 					       (void *)&kbmode, 0, l);
990 	}
991 #endif
992 
993 	scr->scr_flags &= ~SCR_OPEN;
994 
995 	return (0);
996 }
997 
998 int
999 wsdisplayread(dev_t dev, struct uio *uio, int flag)
1000 {
1001 	struct wsdisplay_softc *sc;
1002 	struct tty *tp;
1003 	struct wsscreen *scr;
1004 	int error;
1005 
1006 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1007 
1008 	if (ISWSDISPLAYSTAT(dev)) {
1009 		error = wsevent_read(&sc->evar, uio, flag);
1010 		return (error);
1011 	}
1012 
1013 	if (ISWSDISPLAYCTL(dev))
1014 		return (0);
1015 
1016 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1017 		return (ENXIO);
1018 
1019 	if (!WSSCREEN_HAS_TTY(scr))
1020 		return (ENODEV);
1021 
1022 	tp = scr->scr_tty;
1023 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
1024 }
1025 
1026 int
1027 wsdisplaywrite(dev_t dev, struct uio *uio, int flag)
1028 {
1029 	struct wsdisplay_softc *sc;
1030 	struct tty *tp;
1031 	struct wsscreen *scr;
1032 
1033 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1034 
1035 	if (ISWSDISPLAYSTAT(dev)) {
1036 		return (0);
1037 	}
1038 
1039 	if (ISWSDISPLAYCTL(dev))
1040 		return (0);
1041 
1042 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1043 		return (ENXIO);
1044 
1045 	if (!WSSCREEN_HAS_TTY(scr))
1046 		return (ENODEV);
1047 
1048 	tp = scr->scr_tty;
1049 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
1050 }
1051 
1052 int
1053 wsdisplaypoll(dev_t dev, int events, struct lwp *l)
1054 {
1055 	struct wsdisplay_softc *sc;
1056 	struct tty *tp;
1057 	struct wsscreen *scr;
1058 
1059 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1060 
1061 	if (ISWSDISPLAYSTAT(dev))
1062 		return (wsevent_poll(&sc->evar, events, l));
1063 
1064 	if (ISWSDISPLAYCTL(dev))
1065 		return (0);
1066 
1067 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1068 		return (POLLHUP);
1069 
1070 	if (!WSSCREEN_HAS_TTY(scr))
1071 		return (POLLERR);
1072 
1073 	tp = scr->scr_tty;
1074 	return ((*tp->t_linesw->l_poll)(tp, events, l));
1075 }
1076 
1077 int
1078 wsdisplaykqfilter(dev_t dev, struct knote *kn)
1079 {
1080 	struct wsdisplay_softc *sc;
1081 	struct wsscreen *scr;
1082 
1083 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1084 
1085 	if (ISWSDISPLAYCTL(dev))
1086 		return (1);
1087 
1088 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1089 		return (1);
1090 
1091 
1092 	if (WSSCREEN_HAS_TTY(scr))
1093 		return (ttykqfilter(dev, kn));
1094 	else
1095 		return (1);
1096 }
1097 
1098 struct tty *
1099 wsdisplaytty(dev_t dev)
1100 {
1101 	struct wsdisplay_softc *sc;
1102 	struct wsscreen *scr;
1103 
1104 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1105 
1106 	if (ISWSDISPLAYSTAT(dev))
1107 		panic("wsdisplaytty() on status device");
1108 
1109 	if (ISWSDISPLAYCTL(dev))
1110 		panic("wsdisplaytty() on ctl device");
1111 
1112 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1113 		return NULL;
1114 
1115 	return (scr->scr_tty);
1116 }
1117 
1118 int
1119 wsdisplayioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1120 {
1121 	device_t dv;
1122 	struct wsdisplay_softc *sc;
1123 	struct tty *tp;
1124 	int error;
1125 	struct wsscreen *scr;
1126 
1127 	dv = device_lookup(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1128 	sc = device_private(dv);
1129 
1130 #ifdef WSDISPLAY_COMPAT_USL
1131 	error = wsdisplay_usl_ioctl1(dv, cmd, data, flag, l);
1132 	if (error != EPASSTHROUGH)
1133 		return (error);
1134 #endif
1135 
1136 	if (ISWSDISPLAYSTAT(dev))
1137 		return (wsdisplay_stat_ioctl(sc, cmd, data, flag, l));
1138 
1139 	if (ISWSDISPLAYCTL(dev))
1140 		return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, l));
1141 
1142 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1143 		return (ENXIO);
1144 
1145 	if (WSSCREEN_HAS_TTY(scr)) {
1146 		tp = scr->scr_tty;
1147 
1148 /* printf("disc\n"); */
1149 		/* do the line discipline ioctls first */
1150 		error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
1151 		if (error != EPASSTHROUGH)
1152 			return (error);
1153 
1154 /* printf("tty\n"); */
1155 		/* then the tty ioctls */
1156 		error = ttioctl(tp, cmd, data, flag, l);
1157 		if (error != EPASSTHROUGH)
1158 			return (error);
1159 	}
1160 
1161 #ifdef WSDISPLAY_COMPAT_USL
1162 	error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, l);
1163 	if (error != EPASSTHROUGH)
1164 		return (error);
1165 #endif
1166 
1167 	return (wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, l));
1168 }
1169 
1170 int
1171 wsdisplay_param(device_t dv, u_long cmd, struct wsdisplay_param *dp)
1172 {
1173 	struct wsdisplay_softc *sc = device_private(dv);
1174 	return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1175 					   sc->sc_focus->scr_dconf->emulcookie,
1176 					   cmd, (void *)dp, 0, NULL));
1177 }
1178 
1179 int
1180 wsdisplay_internal_ioctl(struct wsdisplay_softc *sc, struct wsscreen *scr,
1181 	u_long cmd, void *data, int flag, struct lwp *l)
1182 {
1183 	int error;
1184 	char namebuf[16];
1185 	struct wsdisplay_font fd;
1186 #ifdef WSDISPLAY_SCROLLSUPPORT
1187 	struct wsdisplay_scroll_data *ksdp, *usdp;
1188 #endif
1189 
1190 #if NWSKBD > 0
1191 	struct wsevsrc *inp;
1192 
1193 #ifdef WSDISPLAY_COMPAT_RAWKBD
1194 	switch (cmd) {
1195 	case WSKBDIO_SETMODE:
1196 		scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
1197 		return (wsdisplay_update_rawkbd(sc, scr));
1198 	case WSKBDIO_GETMODE:
1199 		*(int *)data = (scr->scr_rawkbd ?
1200 				WSKBD_RAW : WSKBD_TRANSLATED);
1201 		return (0);
1202 	}
1203 #endif
1204 	inp = sc->sc_input;
1205 	if (inp == NULL)
1206 		return (ENXIO);
1207 	error = wsevsrc_display_ioctl(inp, cmd, data, flag, l);
1208 	if (error != EPASSTHROUGH)
1209 		return (error);
1210 #endif /* NWSKBD > 0 */
1211 
1212 	switch (cmd) {
1213 	case WSDISPLAYIO_GMODE:
1214 		if (scr->scr_flags & SCR_GRAPHICS) {
1215 			if (scr->scr_flags & SCR_DUMBFB)
1216 				*(u_int *)data = WSDISPLAYIO_MODE_DUMBFB;
1217 			else
1218 				*(u_int *)data = WSDISPLAYIO_MODE_MAPPED;
1219 		} else
1220 			*(u_int *)data = WSDISPLAYIO_MODE_EMUL;
1221 		return (0);
1222 
1223 	case WSDISPLAYIO_SMODE:
1224 #define d (*(int *)data)
1225 		if (d != WSDISPLAYIO_MODE_EMUL &&
1226 		    d != WSDISPLAYIO_MODE_MAPPED &&
1227 		    d != WSDISPLAYIO_MODE_DUMBFB)
1228 			return (EINVAL);
1229 
1230 	    if (WSSCREEN_HAS_EMULATOR(scr)) {
1231 		    scr->scr_flags &= ~SCR_GRAPHICS;
1232 		    if (d == WSDISPLAYIO_MODE_MAPPED ||
1233 			d == WSDISPLAYIO_MODE_DUMBFB)
1234 			    scr->scr_flags |= SCR_GRAPHICS |
1235 				    ((d == WSDISPLAYIO_MODE_DUMBFB) ? SCR_DUMBFB : 0);
1236 	    } else if (d == WSDISPLAYIO_MODE_EMUL)
1237 		    return (EINVAL);
1238 
1239 	    (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1240 	        scr->scr_dconf->emulcookie, cmd, data, flag, l);
1241 
1242 	    return (0);
1243 #undef d
1244 
1245 #ifdef WSDISPLAY_SCROLLSUPPORT
1246 #define	SETSCROLLLINES(dstp, srcp, dfltp)				\
1247     do {								\
1248 	(dstp)->fastlines = ((srcp)->which &				\
1249 			     WSDISPLAY_SCROLL_DOFASTLINES) ?		\
1250 			     (srcp)->fastlines : (dfltp)->fastlines;	\
1251 	(dstp)->slowlines = ((srcp)->which &				\
1252 			     WSDISPLAY_SCROLL_DOSLOWLINES) ?		\
1253 			     (srcp)->slowlines : (dfltp)->slowlines;	\
1254 	(dstp)->which = WSDISPLAY_SCROLL_DOALL;				\
1255     } while (0)
1256 
1257 
1258 	case WSDISPLAYIO_DSSCROLL:
1259 		usdp = (struct wsdisplay_scroll_data *)data;
1260 		ksdp = &sc->sc_scroll_values;
1261 		SETSCROLLLINES(ksdp, usdp, ksdp);
1262 		return (0);
1263 
1264 	case WSDISPLAYIO_DGSCROLL:
1265 		usdp = (struct wsdisplay_scroll_data *)data;
1266 		ksdp = &sc->sc_scroll_values;
1267 		SETSCROLLLINES(usdp, ksdp, ksdp);
1268 		return (0);
1269 #else
1270 	case WSDISPLAYIO_DSSCROLL:
1271 	case WSDISPLAYIO_DGSCROLL:
1272 		return ENODEV;
1273 #endif
1274 
1275 	case WSDISPLAYIO_SFONT:
1276 #define d ((struct wsdisplay_usefontdata *)data)
1277 		if (!sc->sc_accessops->load_font)
1278 			return (EINVAL);
1279 		if (d->name) {
1280 			error = copyinstr(d->name, namebuf, sizeof(namebuf), 0);
1281 			if (error)
1282 				return (error);
1283 			fd.name = namebuf;
1284 		} else
1285 			fd.name = 0;
1286 		fd.data = 0;
1287 		error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
1288 					scr->scr_dconf->emulcookie, &fd);
1289 		if (!error && WSSCREEN_HAS_EMULATOR(scr))
1290 			(*scr->scr_dconf->wsemul->reset)
1291 				(scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
1292 		return (error);
1293 #undef d
1294 
1295 #ifdef WSDISPLAY_CUSTOM_OUTPUT
1296 	case WSDISPLAYIO_GMSGATTRS:
1297 #define d ((struct wsdisplay_msgattrs *)data)
1298 		(*scr->scr_dconf->wsemul->getmsgattrs)
1299 		    (scr->scr_dconf->wsemulcookie, d);
1300 		return (0);
1301 #undef d
1302 
1303 	case WSDISPLAYIO_SMSGATTRS: {
1304 #define d ((struct wsdisplay_msgattrs *)data)
1305 		int i;
1306 		for (i = 0; i < WSDISPLAY_MAXSCREEN; i++)
1307 			if (sc->sc_scr[i] != NULL)
1308 				(*sc->sc_scr[i]->scr_dconf->wsemul->setmsgattrs)
1309 				    (sc->sc_scr[i]->scr_dconf->wsemulcookie,
1310 				     sc->sc_scr[i]->scr_dconf->scrdata,
1311 				     d);
1312 		}
1313 		return (0);
1314 #undef d
1315 #else
1316 	case WSDISPLAYIO_GMSGATTRS:
1317 	case WSDISPLAYIO_SMSGATTRS:
1318 		return (ENODEV);
1319 #endif
1320 	case WSDISPLAYIO_SETVERSION:
1321 		return wsevent_setversion(&sc->evar, *(int *)data);
1322 	}
1323 
1324 	/* check ioctls for display */
1325 	return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
1326 	    scr->scr_dconf->emulcookie, cmd, data, flag, l));
1327 }
1328 
1329 int
1330 wsdisplay_stat_ioctl(struct wsdisplay_softc *sc, u_long cmd, void *data,
1331 	int flag, struct lwp *l)
1332 {
1333 	switch (cmd) {
1334 	case WSDISPLAYIO_GETACTIVESCREEN:
1335 		*(int*)data = wsdisplay_getactivescreen(sc);
1336 		return (0);
1337 	}
1338 
1339 	return (EPASSTHROUGH);
1340 }
1341 
1342 int
1343 wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, void *data,
1344 	int flag, struct lwp *l)
1345 {
1346 	int error;
1347 	char *type, typebuf[16], *emul, emulbuf[16];
1348 	void *tbuf;
1349 	u_int fontsz;
1350 #if defined(COMPAT_14) && NWSKBD > 0
1351 	struct wsmux_device wsmuxdata;
1352 #endif
1353 #if NWSKBD > 0
1354 	struct wsevsrc *inp;
1355 #endif
1356 
1357 	switch (cmd) {
1358 	case WSDISPLAYIO_ADDSCREEN:
1359 #define d ((struct wsdisplay_addscreendata *)data)
1360 		if (d->screentype) {
1361 			error = copyinstr(d->screentype, typebuf,
1362 					  sizeof(typebuf), 0);
1363 			if (error)
1364 				return (error);
1365 			type = typebuf;
1366 		} else
1367 			type = 0;
1368 		if (d->emul) {
1369 			error = copyinstr(d->emul, emulbuf, sizeof(emulbuf),0);
1370 			if (error)
1371 				return (error);
1372 			emul = emulbuf;
1373 		} else
1374 			emul = 0;
1375 
1376 		if ((error = wsdisplay_addscreen(sc, d->idx, type, emul)) == 0)
1377 			wsdisplay_addscreen_print(sc, d->idx, 0);
1378 		return (error);
1379 #undef d
1380 	case WSDISPLAYIO_DELSCREEN:
1381 #define d ((struct wsdisplay_delscreendata *)data)
1382 		return (wsdisplay_delscreen(sc, d->idx, d->flags));
1383 #undef d
1384 	case WSDISPLAYIO_LDFONT:
1385 #define d ((struct wsdisplay_font *)data)
1386 		if (!sc->sc_accessops->load_font)
1387 			return (EINVAL);
1388 		if (d->name) {
1389 			error = copyinstr(d->name, typebuf, sizeof(typebuf), 0);
1390 			if (error)
1391 				return (error);
1392 			d->name = typebuf;
1393 		} else
1394 			d->name = "loaded"; /* ??? */
1395 		fontsz = d->fontheight * d->stride * d->numchars;
1396 		if (fontsz > WSDISPLAY_MAXFONTSZ)
1397 			return (EINVAL);
1398 
1399 		tbuf = malloc(fontsz, M_DEVBUF, M_WAITOK);
1400 		error = copyin(d->data, tbuf, fontsz);
1401 		if (error) {
1402 			free(tbuf, M_DEVBUF);
1403 			return (error);
1404 		}
1405 		d->data = tbuf;
1406 		error =
1407 		  (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
1408 		free(tbuf, M_DEVBUF);
1409 #undef d
1410 		return (error);
1411 
1412 #if NWSKBD > 0
1413 #ifdef COMPAT_14
1414 	case _O_WSDISPLAYIO_SETKEYBOARD:
1415 #define d ((struct wsdisplay_kbddata *)data)
1416 		inp = sc->sc_input;
1417 		if (inp == NULL)
1418 			return (ENXIO);
1419 		switch (d->op) {
1420 		case _O_WSDISPLAY_KBD_ADD:
1421 			if (d->idx == -1) {
1422 				d->idx = wskbd_pickfree();
1423 				if (d->idx == -1)
1424 					return (ENXIO);
1425 			}
1426 			wsmuxdata.type = WSMUX_KBD;
1427 			wsmuxdata.idx = d->idx;
1428 			return (wsevsrc_ioctl(inp, WSMUX_ADD_DEVICE,
1429 					      &wsmuxdata, flag, l));
1430 		case _O_WSDISPLAY_KBD_DEL:
1431 			wsmuxdata.type = WSMUX_KBD;
1432 			wsmuxdata.idx = d->idx;
1433 			return (wsevsrc_ioctl(inp, WSMUX_REMOVE_DEVICE,
1434 					      &wsmuxdata, flag, l));
1435 		default:
1436 			return (EINVAL);
1437 		}
1438 #undef d
1439 #endif
1440 
1441 	case WSMUXIO_ADD_DEVICE:
1442 #define d ((struct wsmux_device *)data)
1443 		if (d->idx == -1 && d->type == WSMUX_KBD)
1444 			d->idx = wskbd_pickfree();
1445 #undef d
1446 		/* fall into */
1447 	case WSMUXIO_INJECTEVENT:
1448 	case WSMUXIO_REMOVE_DEVICE:
1449 	case WSMUXIO_LIST_DEVICES:
1450 		inp = sc->sc_input;
1451 		if (inp == NULL)
1452 			return (ENXIO);
1453 		return (wsevsrc_ioctl(inp, cmd, data, flag, l));
1454 #endif /* NWSKBD > 0 */
1455 
1456 	}
1457 	return (EPASSTHROUGH);
1458 }
1459 
1460 int
1461 wsdisplay_stat_inject(device_t dv, u_int type, int value)
1462 {
1463 	struct wsdisplay_softc *sc = device_private(dv);
1464 	struct wseventvar *evar;
1465 	struct wscons_event event;
1466 
1467 	evar = &sc->evar;
1468 
1469 	if (evar == NULL)
1470 		return (0);
1471 
1472 	if (evar->q == NULL)
1473 		return (1);
1474 
1475 	event.type = type;
1476 	event.value = value;
1477 	if (wsevent_inject(evar, &event, 1) != 0) {
1478 		log(LOG_WARNING, "wsdisplay: event queue overflow\n");
1479 		return (1);
1480 	}
1481 
1482 	return (0);
1483 }
1484 
1485 paddr_t
1486 wsdisplaymmap(dev_t dev, off_t offset, int prot)
1487 {
1488 	struct wsdisplay_softc *sc;
1489 	struct wsscreen *scr;
1490 
1491 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(dev));
1492 
1493 	if (ISWSDISPLAYSTAT(dev))
1494 		return (-1);
1495 
1496 	if (ISWSDISPLAYCTL(dev))
1497 		return (-1);
1498 
1499 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(dev)]) == NULL)
1500 		return (-1);
1501 
1502 	if (!(scr->scr_flags & SCR_GRAPHICS))
1503 		return (-1);
1504 
1505 	/* pass mmap to display */
1506 	return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie,
1507 	    scr->scr_dconf->emulcookie, offset, prot));
1508 }
1509 
1510 void
1511 wsdisplaystart(struct tty *tp)
1512 {
1513 	struct wsdisplay_softc *sc;
1514 	struct wsscreen *scr;
1515 	int s, n;
1516 	u_char *tbuf;
1517 
1518 	s = spltty();
1519 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
1520 		splx(s);
1521 		return;
1522 	}
1523 	sc = device_lookup_private(&wsdisplay_cd, WSDISPLAYUNIT(tp->t_dev));
1524 	if ((scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)]) == NULL) {
1525 		splx(s);
1526 		return;
1527 	}
1528 
1529 	if (scr->scr_hold_screen) {
1530 		tp->t_state |= TS_TIMEOUT;
1531 		splx(s);
1532 		return;
1533 	}
1534 	tp->t_state |= TS_BUSY;
1535 	splx(s);
1536 
1537 #ifdef DIAGNOSTIC
1538 	scr->scr_in_ttyoutput = 1;
1539 #endif
1540 
1541 	/*
1542 	 * Drain output from ring buffer.
1543 	 * The output will normally be in one contiguous chunk, but when the
1544 	 * ring wraps, it will be in two pieces.. one at the end of the ring,
1545 	 * the other at the start.  For performance, rather than loop here,
1546 	 * we output one chunk, see if there's another one, and if so, output
1547 	 * it too.
1548 	 */
1549 
1550 	n = ndqb(&tp->t_outq, 0);
1551 	tbuf = tp->t_outq.c_cf;
1552 
1553 	if (!(scr->scr_flags & SCR_GRAPHICS)) {
1554 		KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1555 		(*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1556 						  tbuf, n, 0);
1557 	}
1558 	ndflush(&tp->t_outq, n);
1559 
1560 	if ((n = ndqb(&tp->t_outq, 0)) > 0) {
1561 		tbuf = tp->t_outq.c_cf;
1562 
1563 		if (!(scr->scr_flags & SCR_GRAPHICS)) {
1564 			KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1565 			(*scr->scr_dconf->wsemul->output)
1566 			    (scr->scr_dconf->wsemulcookie, tbuf, n, 0);
1567 		}
1568 		ndflush(&tp->t_outq, n);
1569 	}
1570 
1571 #ifdef DIAGNOSTIC
1572 	scr->scr_in_ttyoutput = 0;
1573 #endif
1574 
1575 	s = spltty();
1576 	tp->t_state &= ~TS_BUSY;
1577 	/* Come back if there's more to do */
1578 	if (ttypull(tp)) {
1579 		tp->t_state |= TS_TIMEOUT;
1580 		callout_schedule(&tp->t_rstrt_ch, (hz > 128) ? (hz / 128) : 1);
1581 	}
1582 	splx(s);
1583 }
1584 
1585 void
1586 wsdisplaystop(struct tty *tp, int flag)
1587 {
1588 	int s;
1589 
1590 	s = spltty();
1591 	if (ISSET(tp->t_state, TS_BUSY))
1592 		if (!ISSET(tp->t_state, TS_TTSTOP))
1593 			SET(tp->t_state, TS_FLUSH);
1594 	splx(s);
1595 }
1596 
1597 /* Set line parameters. */
1598 int
1599 wsdisplayparam(struct tty *tp, struct termios *t)
1600 {
1601 
1602 	tp->t_ispeed = t->c_ispeed;
1603 	tp->t_ospeed = t->c_ospeed;
1604 	tp->t_cflag = t->c_cflag;
1605 	return 0;
1606 }
1607 
1608 /*
1609  * Callbacks for the emulation code.
1610  */
1611 void
1612 wsdisplay_emulbell(void *v)
1613 {
1614 	struct wsscreen *scr = v;
1615 
1616 	if (scr == NULL)		/* console, before real attach */
1617 		return;
1618 
1619 	if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */
1620 		return;
1621 
1622 	(void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
1623 					FWRITE, NULL);
1624 }
1625 
1626 void
1627 wsdisplay_emulinput(void *v, const u_char *data, u_int count)
1628 {
1629 	struct wsscreen *scr = v;
1630 	struct tty *tp;
1631 	int (*ifcn)(int, struct tty *);
1632 
1633 	if (v == NULL)			/* console, before real attach */
1634 		return;
1635 
1636 	if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */
1637 		return;
1638 	if (!WSSCREEN_HAS_TTY(scr))
1639 		return;
1640 
1641 	tp = scr->scr_tty;
1642 
1643 	/*
1644 	 * XXX bad hack to work around locking problems in tty.c:
1645 	 * ttyinput() will try to lock again, causing deadlock.
1646 	 * We assume that wsdisplay_emulinput() can only be called
1647 	 * from within wsdisplaystart(), and thus the tty lock
1648 	 * is already held. Use an entry point which doesn't lock.
1649 	 */
1650 	KASSERT(scr->scr_in_ttyoutput);
1651 	ifcn = tp->t_linesw->l_rint;
1652 	if (ifcn == ttyinput)
1653 		ifcn = ttyinput_wlock;
1654 
1655 	while (count-- > 0)
1656 		(*ifcn)(*data++, tp);
1657 }
1658 
1659 /*
1660  * Calls from the keyboard interface.
1661  */
1662 void
1663 wsdisplay_kbdinput(device_t dv, keysym_t ks)
1664 {
1665 	struct wsdisplay_softc *sc = device_private(dv);
1666 	struct wsscreen *scr;
1667 	const char *dp;
1668 	int count;
1669 	struct tty *tp;
1670 
1671 	KASSERT(sc != NULL);
1672 
1673 	scr = sc->sc_focus;
1674 
1675 	if (!scr || !WSSCREEN_HAS_TTY(scr))
1676 		return;
1677 
1678 	tp = scr->scr_tty;
1679 
1680 	if (KS_GROUP(ks) == KS_GROUP_Plain && KS_VALUE(ks) <= 0x7f)
1681 		(*tp->t_linesw->l_rint)(KS_VALUE(ks), tp);
1682 	else if (WSSCREEN_HAS_EMULATOR(scr)) {
1683 		count = (*scr->scr_dconf->wsemul->translate)
1684 		    (scr->scr_dconf->wsemulcookie, ks, &dp);
1685 		while (count-- > 0)
1686 			(*tp->t_linesw->l_rint)((unsigned char)(*dp++), tp);
1687 	}
1688 }
1689 
1690 #if defined(WSDISPLAY_COMPAT_RAWKBD)
1691 int
1692 wsdisplay_update_rawkbd(struct wsdisplay_softc *sc, struct wsscreen *scr)
1693 {
1694 #if NWSKBD > 0
1695 	int s, raw, data, error;
1696 	struct wsevsrc *inp;
1697 
1698 	s = spltty();
1699 
1700 	raw = (scr ? scr->scr_rawkbd : 0);
1701 
1702 	if (scr != sc->sc_focus ||
1703 	    sc->sc_rawkbd == raw) {
1704 		splx(s);
1705 		return (0);
1706 	}
1707 
1708 	data = raw ? WSKBD_RAW : WSKBD_TRANSLATED;
1709 	inp = sc->sc_input;
1710 	if (inp == NULL) {
1711 		splx(s);
1712 		return (ENXIO);
1713 	}
1714 	error = wsevsrc_display_ioctl(inp, WSKBDIO_SETMODE, &data, 0, 0);
1715 	if (!error)
1716 		sc->sc_rawkbd = raw;
1717 	splx(s);
1718 	return (error);
1719 #else
1720 	return (0);
1721 #endif
1722 }
1723 #endif
1724 
1725 static void
1726 wsdisplay_switch3_cb(void *arg, int error, int waitok)
1727 {
1728 	device_t dv = arg;
1729 
1730 	wsdisplay_switch3(dv, error, waitok);
1731 }
1732 
1733 static int
1734 wsdisplay_switch3(device_t dv, int error, int waitok)
1735 {
1736 	struct wsdisplay_softc *sc = device_private(dv);
1737 	int no;
1738 	struct wsscreen *scr;
1739 
1740 	if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1741 		aprint_error_dev(dv, "wsdisplay_switch3: not switching\n");
1742 		return (EINVAL);
1743 	}
1744 
1745 	no = sc->sc_screenwanted;
1746 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1747 		panic("wsdisplay_switch3: invalid screen %d", no);
1748 	scr = sc->sc_scr[no];
1749 	if (!scr) {
1750 		aprint_error_dev(dv,
1751 		    "wsdisplay_switch3: screen %d disappeared\n", no);
1752 		error = ENXIO;
1753 	}
1754 
1755 	if (error) {
1756 		/* try to recover, avoid recursion */
1757 
1758 		if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
1759 			aprint_error_dev(dv, "wsdisplay_switch3: giving up\n");
1760 			sc->sc_focus = 0;
1761 #ifdef WSDISPLAY_COMPAT_RAWKBD
1762 			wsdisplay_update_rawkbd(sc, 0);
1763 #endif
1764 			sc->sc_flags &= ~SC_SWITCHPENDING;
1765 			return (error);
1766 		}
1767 
1768 		sc->sc_screenwanted = sc->sc_oldscreen;
1769 		sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1770 		return (wsdisplay_switch1(dv, 0, waitok));
1771 	}
1772 
1773 	if (scr->scr_syncops && !error)
1774 		sc->sc_flags |= SC_XATTACHED;
1775 
1776 	sc->sc_flags &= ~SC_SWITCHPENDING;
1777 
1778 	if (!error && (scr->scr_flags & SCR_WAITACTIVE))
1779 		wakeup(scr);
1780 	return (error);
1781 }
1782 
1783 static void
1784 wsdisplay_switch2_cb(void *arg, int error, int waitok)
1785 {
1786 	device_t dv = arg;
1787 
1788 	wsdisplay_switch2(dv, error, waitok);
1789 }
1790 
1791 static int
1792 wsdisplay_switch2(device_t dv, int error, int waitok)
1793 {
1794 	struct wsdisplay_softc *sc = device_private(dv);
1795 	int no;
1796 	struct wsscreen *scr;
1797 
1798 	if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1799 		aprint_error_dev(dv, "wsdisplay_switch2: not switching\n");
1800 		return (EINVAL);
1801 	}
1802 
1803 	no = sc->sc_screenwanted;
1804 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1805 		panic("wsdisplay_switch2: invalid screen %d", no);
1806 	scr = sc->sc_scr[no];
1807 	if (!scr) {
1808 		aprint_error_dev(dv,
1809 		    "wsdisplay_switch2: screen %d disappeared\n", no);
1810 		error = ENXIO;
1811 	}
1812 
1813 	if (error) {
1814 		/* try to recover, avoid recursion */
1815 
1816 		if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
1817 			aprint_error_dev(dv, "wsdisplay_switch2: giving up\n");
1818 			sc->sc_focus = 0;
1819 			sc->sc_flags &= ~SC_SWITCHPENDING;
1820 			return (error);
1821 		}
1822 
1823 		sc->sc_screenwanted = sc->sc_oldscreen;
1824 		sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1825 		return (wsdisplay_switch1(dv, 0, waitok));
1826 	}
1827 
1828 	sc->sc_focusidx = no;
1829 	sc->sc_focus = scr;
1830 
1831 #ifdef WSDISPLAY_COMPAT_RAWKBD
1832 	(void) wsdisplay_update_rawkbd(sc, scr);
1833 #endif
1834 	/* keyboard map??? */
1835 
1836 	if (scr->scr_syncops &&
1837 	    !(sc->sc_isconsole && wsdisplay_cons_pollmode)) {
1838 		error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok,
1839 						    wsdisplay_switch3_cb, dv);
1840 		if (error == EAGAIN) {
1841 			/* switch will be done asynchronously */
1842 			return (0);
1843 		}
1844 	}
1845 
1846 	return (wsdisplay_switch3(dv, error, waitok));
1847 }
1848 
1849 static void
1850 wsdisplay_switch1_cb(void *arg, int error, int waitok)
1851 {
1852 	device_t dv = arg;
1853 
1854 	wsdisplay_switch1(dv, error, waitok);
1855 }
1856 
1857 static int
1858 wsdisplay_switch1(device_t dv, int error, int waitok)
1859 {
1860 	struct wsdisplay_softc *sc = device_private(dv);
1861 	int no;
1862 	struct wsscreen *scr;
1863 
1864 	if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1865 		aprint_error_dev(dv, "wsdisplay_switch1: not switching\n");
1866 		return (EINVAL);
1867 	}
1868 
1869 	no = sc->sc_screenwanted;
1870 	if (no == WSDISPLAY_NULLSCREEN) {
1871 		sc->sc_flags &= ~SC_SWITCHPENDING;
1872 		if (!error) {
1873 			sc->sc_flags &= ~SC_XATTACHED;
1874 			sc->sc_focus = 0;
1875 		}
1876 		wakeup(sc);
1877 		return (error);
1878 	}
1879 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1880 		panic("wsdisplay_switch1: invalid screen %d", no);
1881 	scr = sc->sc_scr[no];
1882 	if (!scr) {
1883 		aprint_error_dev(dv, "wsdisplay_switch1: screen %d disappeared\n", no);
1884 		error = ENXIO;
1885 	}
1886 
1887 	if (error) {
1888 		sc->sc_flags &= ~SC_SWITCHPENDING;
1889 		return (error);
1890 	}
1891 
1892 	sc->sc_flags &= ~SC_XATTACHED;
1893 
1894 	error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
1895 						 scr->scr_dconf->emulcookie,
1896 						 waitok,
1897 	  sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsdisplay_switch2_cb, dv);
1898 	if (error == EAGAIN) {
1899 		/* switch will be done asynchronously */
1900 		return (0);
1901 	}
1902 
1903 	return (wsdisplay_switch2(dv, error, waitok));
1904 }
1905 
1906 int
1907 wsdisplay_switch(device_t dv, int no, int waitok)
1908 {
1909 	struct wsdisplay_softc *sc = device_private(dv);
1910 	int s, res = 0;
1911 	struct wsscreen *scr;
1912 
1913 	if (no != WSDISPLAY_NULLSCREEN) {
1914 		if ((no < 0 || no >= WSDISPLAY_MAXSCREEN))
1915 			return (EINVAL);
1916 		if (sc->sc_scr[no] == NULL)
1917 			return (ENXIO);
1918 	}
1919 
1920 	wsdisplay_stat_inject(dv, WSCONS_EVENT_SCREEN_SWITCH, no);
1921 
1922 	s = spltty();
1923 
1924 	if ((sc->sc_focus && no == sc->sc_focusidx) ||
1925 	    (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) {
1926 		splx(s);
1927 		return (0);
1928 	}
1929 
1930 	if (sc->sc_flags & SC_SWITCHPENDING) {
1931 		splx(s);
1932 		return (EBUSY);
1933 	}
1934 
1935 	sc->sc_flags |= SC_SWITCHPENDING;
1936 	sc->sc_screenwanted = no;
1937 
1938 	splx(s);
1939 
1940 	scr = sc->sc_focus;
1941 	if (!scr) {
1942 		sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1943 		return (wsdisplay_switch1(dv, 0, waitok));
1944 	} else
1945 		sc->sc_oldscreen = sc->sc_focusidx;
1946 
1947 	if (scr->scr_syncops) {
1948 		if (!(sc->sc_flags & SC_XATTACHED) ||
1949 		    (sc->sc_isconsole && wsdisplay_cons_pollmode)) {
1950 			/* nothing to do here */
1951 			return (wsdisplay_switch1(dv, 0, waitok));
1952 		}
1953 		res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok,
1954 						  wsdisplay_switch1_cb, dv);
1955 		if (res == EAGAIN) {
1956 			/* switch will be done asynchronously */
1957 			return (0);
1958 		}
1959 	} else if (scr->scr_flags & SCR_GRAPHICS) {
1960 		/* no way to save state */
1961 		res = EBUSY;
1962 	}
1963 
1964 	return (wsdisplay_switch1(dv, res, waitok));
1965 }
1966 
1967 void
1968 wsdisplay_reset(device_t dv, enum wsdisplay_resetops op)
1969 {
1970 	struct wsdisplay_softc *sc = device_private(dv);
1971 	struct wsscreen *scr;
1972 
1973 	KASSERT(sc != NULL);
1974 	scr = sc->sc_focus;
1975 
1976 	if (!scr)
1977 		return;
1978 
1979 	switch (op) {
1980 	case WSDISPLAY_RESETEMUL:
1981 		if (!WSSCREEN_HAS_EMULATOR(scr))
1982 			break;
1983 		(*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
1984 						 WSEMUL_RESET);
1985 		break;
1986 	case WSDISPLAY_RESETCLOSE:
1987 		wsdisplay_closescreen(sc, scr);
1988 		break;
1989 	}
1990 }
1991 
1992 /*
1993  * Interface for (external) VT switch / process synchronization code
1994  */
1995 int
1996 wsscreen_attach_sync(struct wsscreen *scr, const struct wscons_syncops *ops,
1997 	void *cookie)
1998 {
1999 	if (scr->scr_syncops) {
2000 		/*
2001 		 * The screen is already claimed.
2002 		 * Check if the owner is still alive.
2003 		 */
2004 		if ((*scr->scr_syncops->check)(scr->scr_synccookie))
2005 			return (EBUSY);
2006 	}
2007 	scr->scr_syncops = ops;
2008 	scr->scr_synccookie = cookie;
2009 	if (scr == scr->sc->sc_focus)
2010 		scr->sc->sc_flags |= SC_XATTACHED;
2011 	return (0);
2012 }
2013 
2014 int
2015 wsscreen_detach_sync(struct wsscreen *scr)
2016 {
2017 	if (!scr->scr_syncops)
2018 		return (EINVAL);
2019 	scr->scr_syncops = 0;
2020 	if (scr == scr->sc->sc_focus)
2021 		scr->sc->sc_flags &= ~SC_XATTACHED;
2022 	return (0);
2023 }
2024 
2025 int
2026 wsscreen_lookup_sync(struct wsscreen *scr,
2027 	const struct wscons_syncops *ops, /* used as ID */
2028 	void **cookiep)
2029 {
2030 	if (!scr->scr_syncops || ops != scr->scr_syncops)
2031 		return (EINVAL);
2032 	*cookiep = scr->scr_synccookie;
2033 	return (0);
2034 }
2035 
2036 /*
2037  * Interface to virtual screen stuff
2038  */
2039 int
2040 wsdisplay_maxscreenidx(struct wsdisplay_softc *sc)
2041 {
2042 	return (WSDISPLAY_MAXSCREEN - 1);
2043 }
2044 
2045 int
2046 wsdisplay_screenstate(struct wsdisplay_softc *sc, int idx)
2047 {
2048 	if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
2049 		return (EINVAL);
2050 	if (!sc->sc_scr[idx])
2051 		return (ENXIO);
2052 	return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0);
2053 }
2054 
2055 int
2056 wsdisplay_getactivescreen(struct wsdisplay_softc *sc)
2057 {
2058 	return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN);
2059 }
2060 
2061 int
2062 wsscreen_switchwait(struct wsdisplay_softc *sc, int no)
2063 {
2064 	struct wsscreen *scr;
2065 	int s, res = 0;
2066 
2067 	if (no == WSDISPLAY_NULLSCREEN) {
2068 		s = spltty();
2069 		while (sc->sc_focus && res == 0) {
2070 			res = tsleep(sc, PCATCH, "wswait", 0);
2071 		}
2072 		splx(s);
2073 		return (res);
2074 	}
2075 
2076 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
2077 		return (ENXIO);
2078 	scr = sc->sc_scr[no];
2079 	if (!scr)
2080 		return (ENXIO);
2081 
2082 	s = spltty();
2083 	if (scr != sc->sc_focus) {
2084 		scr->scr_flags |= SCR_WAITACTIVE;
2085 		res = tsleep(scr, PCATCH, "wswait", 0);
2086 		if (scr != sc->sc_scr[no])
2087 			res = ENXIO; /* disappeared in the meantime */
2088 		else
2089 			scr->scr_flags &= ~SCR_WAITACTIVE;
2090 	}
2091 	splx(s);
2092 	return (res);
2093 }
2094 
2095 void
2096 wsdisplay_kbdholdscreen(device_t dv, int hold)
2097 {
2098 	struct wsdisplay_softc *sc = device_private(dv);
2099 	struct wsscreen *scr;
2100 
2101 	scr = sc->sc_focus;
2102 
2103 	if (!scr)
2104 		return;
2105 
2106 	if (hold)
2107 		scr->scr_hold_screen = 1;
2108 	else {
2109 		scr->scr_hold_screen = 0;
2110 		callout_schedule(&scr->scr_tty->t_rstrt_ch, 0);
2111 	}
2112 }
2113 
2114 #if NWSKBD > 0
2115 void
2116 wsdisplay_set_console_kbd(struct wsevsrc *src)
2117 {
2118 	if (wsdisplay_console_device == NULL) {
2119 		src->me_dispdv = NULL;
2120 		return;
2121 	}
2122 #if NWSMUX > 0
2123 	if (wsmux_attach_sc((struct wsmux_softc *)
2124 			    wsdisplay_console_device->sc_input, src)) {
2125 		src->me_dispdv = NULL;
2126 		return;
2127 	}
2128 #else
2129 	wsdisplay_console_device->sc_input = src;
2130 #endif
2131 	src->me_dispdv = wsdisplay_console_device->sc_dev;
2132 }
2133 #endif /* NWSKBD > 0 */
2134 
2135 /*
2136  * Console interface.
2137  */
2138 void
2139 wsdisplay_cnputc(dev_t dev, int i)
2140 {
2141 	struct wsscreen_internal *dc;
2142 	u_char c = i;
2143 
2144 	if (!wsdisplay_console_initted)
2145 		return;
2146 
2147 	if ((wsdisplay_console_device != NULL) &&
2148 	    (wsdisplay_console_device->sc_scr[0] != NULL) &&
2149 	    (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
2150 		return;
2151 
2152 	dc = &wsdisplay_console_conf;
2153 	(*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
2154 }
2155 
2156 static int
2157 wsdisplay_getc_dummy(dev_t dev)
2158 {
2159 	/* panic? */
2160 	return (0);
2161 }
2162 
2163 static void
2164 wsdisplay_pollc(dev_t dev, int on)
2165 {
2166 
2167 	wsdisplay_cons_pollmode = on;
2168 
2169 	/* notify to fb drivers */
2170 	if (wsdisplay_console_device != NULL &&
2171 	    wsdisplay_console_device->sc_accessops->pollc != NULL)
2172 		(*wsdisplay_console_device->sc_accessops->pollc)
2173 			(wsdisplay_console_device->sc_accesscookie, on);
2174 
2175 	/* notify to kbd drivers */
2176 	if (wsdisplay_cons_kbd_pollc)
2177 		(*wsdisplay_cons_kbd_pollc)(NODEV, on);
2178 }
2179 
2180 void
2181 wsdisplay_set_cons_kbd(int (*get)(dev_t), void (*poll)(dev_t, int),
2182 	void (*bell)(dev_t, u_int, u_int, u_int))
2183 {
2184 	wsdisplay_cons.cn_getc = get;
2185 	wsdisplay_cons.cn_bell = bell;
2186 	wsdisplay_cons_kbd_pollc = poll;
2187 }
2188 
2189 void
2190 wsdisplay_unset_cons_kbd(void)
2191 {
2192 	wsdisplay_cons.cn_getc = wsdisplay_getc_dummy;
2193 	wsdisplay_cons.cn_bell = NULL;
2194 	wsdisplay_cons_kbd_pollc = 0;
2195 }
2196