xref: /openbsd-src/sys/dev/wscons/wsdisplay.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /* $OpenBSD: wsdisplay.c,v 1.36 2001/11/26 16:02:30 mickey Exp $ */
2 /* $NetBSD: wsdisplay.c,v 1.37.4.1 2000/06/30 16:27:53 simonb Exp $ */
3 
4 /*
5  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Christopher G. Demetriou
18  *	for the NetBSD Project.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 
36 #include <sys/param.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/ioctl.h>
40 #include <sys/kernel.h>
41 #include <sys/proc.h>
42 #include <sys/malloc.h>
43 #include <sys/syslog.h>
44 #include <sys/systm.h>
45 #include <sys/tty.h>
46 #include <sys/signalvar.h>
47 #include <sys/errno.h>
48 #include <sys/fcntl.h>
49 #include <sys/vnode.h>
50 #include <sys/timeout.h>
51 
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wsdisplayvar.h>
54 #include <dev/wscons/wsksymvar.h>
55 #include <dev/wscons/wsksymdef.h>
56 #include <dev/wscons/wsemulvar.h>
57 #include <dev/wscons/wscons_callbacks.h>
58 #include <dev/cons.h>
59 
60 #include <dev/ic/pcdisplay.h>
61 
62 #include "wskbd.h"
63 #include "wsmux.h"
64 
65 #if NWSKBD > 0
66 #include <dev/wscons/wseventvar.h>
67 #include <dev/wscons/wsmuxvar.h>
68 #endif
69 
70 #include "wsmoused.h"
71 
72 struct wsscreen_internal {
73 	const struct wsdisplay_emulops *emulops;
74 	void	*emulcookie;
75 
76 	const struct wsscreen_descr *scrdata;
77 
78 	const struct wsemul_ops *wsemul;
79 	void	*wsemulcookie;
80 };
81 
82 struct wsscreen {
83 	struct wsscreen_internal *scr_dconf;
84 
85 	struct tty *scr_tty;
86 	int	scr_hold_screen;		/* hold tty output */
87 
88 	int scr_flags;
89 #define SCR_OPEN 1		/* is it open? */
90 #define SCR_WAITACTIVE 2	/* someone waiting on activation */
91 #define SCR_GRAPHICS 4		/* graphics mode, no text (emulation) output */
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 	/* mouse console support via wsmoused(8) */
102 	unsigned short mouse; 		/* mouse cursor position */
103 	unsigned short cursor;		/* selection cursor position (if
104 					different from mouse cursor pos) */
105 	unsigned short cpy_start; 	/* position of the copy start mark*/
106 	unsigned short cpy_end;		/* position of the copy end mark */
107 	unsigned short orig_start;	/* position of the original sel. start*/
108 	unsigned short orig_end;	/* position of the original sel. end */
109 #define MOUSE_VISIBLE 	(1 << 0)	/* flag, the mouse cursor is visible */
110 #define SEL_EXISTS 	(1 << 1)	/* flag, a selection exists */
111 #define SEL_IN_PROGRESS (1 << 2)	/* flag, a selection is in progress */
112 #define SEL_EXT_AFTER 	(1 << 3)	/* flag, selection is extended after */
113 #define BLANK_TO_EOL	(1 << 4)	/* flag, there are only blanks
114 					   characters to eol */
115 #define SEL_BY_CHAR	(1 << 5)	/* flag, select character by character*/
116 #define SEL_BY_WORD	(1 << 6)	/* flag, select word by word */
117 #define SEL_BY_LINE	(1 << 7)	/* flag, select line by line */
118 
119 #define IS_MOUSE_VISIBLE(ws) ((ws)->mouse_flags & MOUSE_VISIBLE)
120 #define IS_SEL_EXISTS(ws) ((ws)->mouse_flags & SEL_EXISTS)
121 #define IS_SEL_IN_PROGRESS(ws) ((ws)->mouse_flags & SEL_IN_PROGRESS)
122 #define IS_SEL_EXT_AFTER(ws) ((ws)->mouse_flags & SEL_EXT_AFTER)
123 #define IS_BLANK_TO_EOL(ws) ((ws)->mouse_flags & BLANK_TO_EOL)
124 #define IS_SEL_BY_CHAR(ws) ((ws)->mouse_flags & SEL_BY_CHAR)
125 #define IS_SEL_BY_WORD(ws) ((ws)->mouse_flags & SEL_BY_WORD)
126 #define IS_SEL_BY_LINE(ws) ((ws)->mouse_flags & SEL_BY_LINE)
127 	unsigned char mouse_flags;	/* flags, status of the mouse */
128 };
129 
130 struct wsscreen *wsscreen_attach __P((struct wsdisplay_softc *, int,
131 	const char *, const struct wsscreen_descr *, void *, int, int, long));
132 void wsscreen_detach __P((struct wsscreen *));
133 int wsdisplay_addscreen __P((struct wsdisplay_softc *, int, const char *, const char *));
134 int wsdisplay_getscreen __P((struct wsdisplay_softc *, struct wsdisplay_addscreendata *));
135 void wsdisplay_shutdownhook __P((void *));
136 void wsdisplay_addscreen_print __P((struct wsdisplay_softc *, int, int));
137 void wsdisplay_closescreen __P((struct wsdisplay_softc *, struct wsscreen *));
138 int wsdisplay_delscreen __P((struct wsdisplay_softc *, int, int));
139 void wsdisplay_burner __P((void *v));
140 
141 #define WSDISPLAY_MAXSCREEN	12
142 #define WSDISPLAY_MAXFONT	8
143 
144 struct wsdisplay_softc {
145 	struct device sc_dv;
146 
147 	const struct wsdisplay_accessops *sc_accessops;
148 	void	*sc_accesscookie;
149 
150 	const struct wsscreen_list *sc_scrdata;
151 
152 	struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
153 	int sc_focusidx;	/* available only if sc_focus isn't null */
154 	struct wsscreen *sc_focus;
155 
156 	struct timeout sc_burner;
157 	int	sc_burnoutintvl;
158 	int	sc_burninintvl;
159 	int	sc_burnout;
160 	int	sc_burnman;
161 	int	sc_burnflags;
162 
163 	struct wsdisplay_font sc_fonts[WSDISPLAY_MAXFONT];
164 
165 	int	sc_isconsole;
166 
167 	int sc_flags;
168 #define SC_SWITCHPENDING 1
169 	int sc_screenwanted, sc_oldscreen; /* valid with SC_SWITCHPENDING */
170 
171 #if NWSKBD > 0
172 	struct wsmux_softc *sc_muxdv;
173 #ifdef WSDISPLAY_COMPAT_RAWKBD
174 	int sc_rawkbd;
175 #endif
176 #endif /* NWSKBD > 0 */
177 };
178 
179 extern struct cfdriver wsdisplay_cd;
180 
181 /* Autoconfiguration definitions. */
182 int wsdisplay_emul_match __P((struct device *, void *, void *));
183 void wsdisplay_emul_attach __P((struct device *, struct device *, void *));
184 int wsdisplay_noemul_match __P((struct device *, void *, void *));
185 void wsdisplay_noemul_attach __P((struct device *, struct device *, void *));
186 
187 struct cfdriver wsdisplay_cd = {
188 	NULL, "wsdisplay", DV_TTY
189 };
190 
191 struct cfattach wsdisplay_emul_ca = {
192 	sizeof(struct wsdisplay_softc), wsdisplay_emul_match,
193 	    wsdisplay_emul_attach,
194 };
195 
196 struct cfattach wsdisplay_noemul_ca = {
197 	sizeof(struct wsdisplay_softc), wsdisplay_noemul_match,
198 	    wsdisplay_noemul_attach,
199 };
200 
201 /* Exported tty- and cdevsw-related functions. */
202 cdev_decl(wsdisplay);
203 
204 void wsdisplaystart __P((struct tty *));
205 int wsdisplayparam __P((struct tty *, struct termios *));
206 
207 
208 /* Internal macros, functions, and variables. */
209 #define	SET(t, f)	(t) |= (f)
210 #define	CLR(t, f)	(t) &= ~(f)
211 #define	ISSET(t, f)	((t) & (f))
212 
213 #define	WSDISPLAYUNIT(dev)		(minor(dev) >> 8)
214 #define	WSDISPLAYSCREEN(dev)		(minor(dev) & 0xff)
215 #define ISWSDISPLAYCTL(dev)		(WSDISPLAYSCREEN(dev) == 255)
216 #define WSDISPLAYMINOR(unit, screen)	(((unit) << 8) | (screen))
217 
218 #define	WSSCREEN_HAS_EMULATOR(scr)	((scr)->scr_dconf->wsemul != NULL)
219 #define	WSSCREEN_HAS_TTY(scr)		((scr)->scr_tty != NULL)
220 
221 void wsdisplay_common_attach __P((struct wsdisplay_softc *sc,
222 	    int console, const struct wsscreen_list *,
223 	    const struct wsdisplay_accessops *accessops,
224 	    void *accesscookie));
225 
226 #ifdef WSDISPLAY_COMPAT_RAWKBD
227 int wsdisplay_update_rawkbd __P((struct wsdisplay_softc *, struct wsscreen *));
228 #endif
229 
230 int wsdisplay_console_initted;
231 struct wsdisplay_softc *wsdisplay_console_device;
232 struct wsscreen_internal wsdisplay_console_conf;
233 
234 int wsdisplay_getc_dummy __P((dev_t));
235 void wsdisplay_pollc __P((dev_t, int));
236 
237 int wsdisplay_cons_pollmode;
238 void (*wsdisplay_cons_kbd_pollc) __P((dev_t, int));
239 
240 struct consdev wsdisplay_cons = {
241 	NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
242 	    wsdisplay_pollc, NULL, NODEV, CN_NORMAL
243 };
244 
245 #ifndef WSDISPLAY_DEFAULTSCREENS
246 # define WSDISPLAY_DEFAULTSCREENS	0
247 #endif
248 int wsdisplay_defaultscreens = WSDISPLAY_DEFAULTSCREENS;
249 
250 int wsdisplay_switch1 __P((void *, int, int));
251 int wsdisplay_switch2 __P((void *, int, int));
252 int wsdisplay_switch3 __P((void *, int, int));
253 
254 int wsdisplay_clearonclose;
255 
256 struct wsscreen *
257 wsscreen_attach(sc, console, emul, type, cookie, ccol, crow, defattr)
258 	struct wsdisplay_softc *sc;
259 	int console;
260 	const char *emul;
261 	const struct wsscreen_descr *type;
262 	void *cookie;
263 	int ccol, crow;
264 	long defattr;
265 {
266 	struct wsscreen_internal *dconf;
267 	struct wsscreen *scr;
268 
269 	scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_NOWAIT);
270 	if (!scr)
271 		return (scr);
272 
273 	if (console) {
274 		dconf = &wsdisplay_console_conf;
275 		/*
276 		 * If there's an emulation, tell it about the callback argument.
277 		 * The other stuff is already there.
278 		 */
279 		if (dconf->wsemul != NULL)
280 			(*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0);
281 	} else { /* not console */
282 		dconf = malloc(sizeof(struct wsscreen_internal),
283 			       M_DEVBUF, M_NOWAIT);
284 		if (dconf == NULL) {
285 			free(scr, M_DEVBUF);
286 			return (NULL);
287 		}
288 		dconf->emulops = type->textops;
289 		dconf->emulcookie = cookie;
290 		if (dconf->emulops) {
291 			dconf->wsemul = wsemul_pick(emul);
292 			if (dconf->wsemul == NULL) {
293 				free(dconf, M_DEVBUF);
294 				free(scr, M_DEVBUF);
295 				return (NULL);
296 			}
297 			dconf->wsemulcookie =
298 			  (*dconf->wsemul->attach)(0, type, cookie,
299 						   ccol, crow, scr, defattr);
300 		} else
301 			dconf->wsemul = NULL;
302 		dconf->scrdata = type;
303 	}
304 
305 	scr->scr_dconf = dconf;
306 
307 	scr->scr_tty = ttymalloc();
308 	tty_attach(scr->scr_tty);
309 	scr->scr_hold_screen = 0;
310 	if (WSSCREEN_HAS_EMULATOR(scr))
311 		scr->scr_flags = 0;
312 	else
313 		scr->scr_flags = SCR_GRAPHICS;
314 
315 	scr->scr_syncops = 0;
316 	scr->sc = sc;
317 	scr->mouse_flags = 0;
318 #ifdef WSDISPLAY_COMPAT_RAWKBD
319 	scr->scr_rawkbd = 0;
320 #endif
321 	return (scr);
322 }
323 
324 void
325 wsscreen_detach(scr)
326 	struct wsscreen *scr;
327 {
328 	int ccol, crow; /* XXX */
329 
330 	if (WSSCREEN_HAS_TTY(scr)) {
331 		timeout_del(&scr->scr_tty->t_rstrt_to);
332 		tty_detach(scr->scr_tty);
333 		ttyfree(scr->scr_tty);
334 	}
335 	if (WSSCREEN_HAS_EMULATOR(scr))
336 		(*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie,
337 						  &ccol, &crow);
338 	free(scr->scr_dconf, M_DEVBUF);
339 	free(scr, M_DEVBUF);
340 }
341 
342 const struct wsscreen_descr *
343 wsdisplay_screentype_pick(scrdata, name)
344 	const struct wsscreen_list *scrdata;
345 	const char *name;
346 {
347 	int i;
348 	const struct wsscreen_descr *scr;
349 
350 	KASSERT(scrdata->nscreens > 0);
351 
352 	if (name == NULL || *name == '\0')
353 		return (scrdata->screens[0]);
354 
355 	for (i = 0; i < scrdata->nscreens; i++) {
356 		scr = scrdata->screens[i];
357 		if (!strncmp(name, scr->name, WSSCREEN_NAME_SIZE))
358 			return (scr);
359 	}
360 
361 	return (0);
362 }
363 
364 /*
365  * print info about attached screen
366  */
367 void
368 wsdisplay_addscreen_print(sc, idx, count)
369 	struct wsdisplay_softc *sc;
370 	int idx, count;
371 {
372 	printf("%s: screen %d", sc->sc_dv.dv_xname, idx);
373 	if (count > 1)
374 		printf("-%d", idx + (count-1));
375 	printf(" added (%s", sc->sc_scr[idx]->scr_dconf->scrdata->name);
376 	if (WSSCREEN_HAS_EMULATOR(sc->sc_scr[idx])) {
377 		printf(", %s emulation",
378 			sc->sc_scr[idx]->scr_dconf->wsemul->name);
379 	}
380 	printf(")\n");
381 }
382 
383 int
384 wsdisplay_addscreen(sc, idx, screentype, emul)
385 	struct wsdisplay_softc *sc;
386 	int idx;
387 	const char *screentype, *emul;
388 {
389 	const struct wsscreen_descr *scrdesc;
390 	int error;
391 	void *cookie;
392 	int ccol, crow;
393 	long defattr;
394 	struct wsscreen *scr;
395 	int s;
396 
397 	if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
398 		return (EINVAL);
399 	if (sc->sc_scr[idx] != NULL)
400 		return (EBUSY);
401 
402 	scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype);
403 	if (!scrdesc)
404 		return (ENXIO);
405 	error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie,
406 			scrdesc, &cookie, &ccol, &crow, &defattr);
407 	if (error)
408 		return (error);
409 
410 	scr = wsscreen_attach(sc, 0, emul, scrdesc,
411 			      cookie, ccol, crow, defattr);
412 	if (scr == NULL) {
413 		(*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
414 						 cookie);
415 		return (ENXIO);
416 	}
417 
418 	sc->sc_scr[idx] = scr;
419 
420 	/* if no screen has focus yet, activate the first we get */
421 	s = spltty();
422 	if (!sc->sc_focus) {
423 		(*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
424 						 scr->scr_dconf->emulcookie,
425 						 0, 0, 0);
426 		sc->sc_focusidx = idx;
427 		sc->sc_focus = scr;
428 	}
429 	splx(s);
430 
431 	allocate_copybuffer(sc); /* enlarge the copy buffer is necessary */
432 	return (0);
433 }
434 
435 int
436 wsdisplay_getscreen(sc, sd)
437 	struct wsdisplay_softc *sc;
438 	struct wsdisplay_addscreendata *sd;
439 {
440 	struct wsscreen *scr;
441 
442 	if (sd->idx < 0 && sc->sc_focus)
443 		sd->idx = sc->sc_focusidx;
444 
445 	if (sd->idx < 0 || sd->idx >= WSDISPLAY_MAXSCREEN)
446 		return (EINVAL);
447 
448 	scr = sc->sc_scr[sd->idx];
449 	if (scr == NULL)
450 		return (ENXIO);
451 
452 	strncpy(sd->screentype, scr->scr_dconf->scrdata->name,
453 	    WSSCREEN_NAME_SIZE);
454 	strncpy(sd->emul, scr->scr_dconf->wsemul->name, WSEMUL_NAME_SIZE);
455 
456 	return (0);
457 }
458 
459 void
460 wsdisplay_closescreen(sc, scr)
461 	struct wsdisplay_softc *sc;
462 	struct wsscreen *scr;
463 {
464 	int maj, mn, idx;
465 
466 	/* hangup */
467 	if (WSSCREEN_HAS_TTY(scr)) {
468 		struct tty *tp = scr->scr_tty;
469 		(*linesw[tp->t_line].l_modem)(tp, 0);
470 	}
471 
472 	/* locate the major number */
473 	for (maj = 0; maj < nchrdev; maj++)
474 		if (cdevsw[maj].d_open == wsdisplayopen)
475 			break;
476 	/* locate the screen index */
477 	for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++)
478 		if (scr == sc->sc_scr[idx])
479 			break;
480 #ifdef DIAGNOSTIC
481 	if (idx == WSDISPLAY_MAXSCREEN)
482 		panic("wsdisplay_forceclose: bad screen");
483 #endif
484 
485 	/* nuke the vnodes */
486 	mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx);
487 	vdevgone(maj, mn, mn, VCHR);
488 }
489 
490 int
491 wsdisplay_delscreen(sc, idx, flags)
492 	struct wsdisplay_softc *sc;
493 	int idx, flags;
494 {
495 	struct wsscreen *scr;
496 	int s;
497 	void *cookie;
498 
499 	if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
500 		return (EINVAL);
501 	scr = sc->sc_scr[idx];
502 	if (!scr)
503 		return (ENXIO);
504 
505 	if (scr->scr_dconf == &wsdisplay_console_conf ||
506 	    scr->scr_syncops ||
507 	    ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE)))
508 		return(EBUSY);
509 
510 	wsdisplay_closescreen(sc, scr);
511 
512 	/*
513 	 * delete pointers, so neither device entries
514 	 * nor keyboard input can reference it anymore
515 	 */
516 	s = spltty();
517 	if (sc->sc_focus == scr) {
518 		sc->sc_focus = 0;
519 #ifdef WSDISPLAY_COMPAT_RAWKBD
520 		wsdisplay_update_rawkbd(sc, 0);
521 #endif
522 	}
523 	sc->sc_scr[idx] = 0;
524 	splx(s);
525 
526 	/*
527 	 * Wake up processes waiting for the screen to
528 	 * be activated. Sleepers must check whether
529 	 * the screen still exists.
530 	 */
531 	if (scr->scr_flags & SCR_WAITACTIVE)
532 		wakeup(scr);
533 
534 	/* save a reference to the graphics screen */
535 	cookie = scr->scr_dconf->emulcookie;
536 
537 	wsscreen_detach(scr);
538 
539 	(*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
540 					 cookie);
541 
542 	printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx);
543 	return (0);
544 }
545 
546 /*
547  * Autoconfiguration functions.
548  */
549 int
550 wsdisplay_emul_match(parent, match, aux)
551 	struct device *parent;
552 	void *match;
553 	void *aux;
554 {
555 	struct cfdata *cf = match;
556 	struct wsemuldisplaydev_attach_args *ap = aux;
557 
558 	if (cf->wsemuldisplaydevcf_console !=
559 	    WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
560 		/*
561 		 * If console-ness of device specified, either match
562 		 * exactly (at high priority), or fail.
563 		 */
564 		if (cf->wsemuldisplaydevcf_console != 0 &&
565 		    ap->console != 0)
566 			return (10);
567 		else
568 			return (0);
569 	}
570 
571 	/* If console-ness unspecified, it wins. */
572 	return (1);
573 }
574 
575 void
576 wsdisplay_emul_attach(parent, self, aux)
577 	struct device *parent, *self;
578 	void *aux;
579 {
580 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
581 	struct wsemuldisplaydev_attach_args *ap = aux;
582 
583 	wsdisplay_common_attach(sc, ap->console, ap->scrdata,
584 				ap->accessops, ap->accesscookie);
585 
586 	if (ap->console && cn_tab == &wsdisplay_cons) {
587 		int maj;
588 
589 		/* locate the major number */
590 		for (maj = 0; maj < nchrdev; maj++)
591 			if (cdevsw[maj].d_open == wsdisplayopen)
592 				break;
593 
594 		cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0));
595 	}
596 }
597 
598 /* Print function (for parent devices). */
599 int
600 wsemuldisplaydevprint(aux, pnp)
601 	void *aux;
602 	const char *pnp;
603 {
604 #if 0 /* -Wunused */
605 	struct wsemuldisplaydev_attach_args *ap = aux;
606 #endif
607 
608 	if (pnp)
609 		printf("wsdisplay at %s", pnp);
610 #if 0 /* don't bother; it's ugly */
611 	printf(" console %d", ap->console);
612 #endif
613 
614 	return (UNCONF);
615 }
616 
617 int
618 wsdisplay_noemul_match(parent, match, aux)
619 	struct device *parent;
620 	void *match;
621 	void *aux;
622 {
623 #if 0 /* -Wunused */
624 	struct wsdisplaydev_attach_args *ap = aux;
625 #endif
626 
627 	/* Always match. */
628 	return (1);
629 }
630 
631 void
632 wsdisplay_noemul_attach(parent, self, aux)
633 	struct device *parent, *self;
634 	void *aux;
635 {
636 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
637 	struct wsdisplaydev_attach_args *ap = aux;
638 
639 	wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie);
640 }
641 
642 /* Print function (for parent devices). */
643 int
644 wsdisplaydevprint(aux, pnp)
645 	void *aux;
646 	const char *pnp;
647 {
648 #if 0 /* -Wunused */
649 	struct wsdisplaydev_attach_args *ap = aux;
650 #endif
651 
652 	if (pnp)
653 		printf("wsdisplay at %s", pnp);
654 
655 	return (UNCONF);
656 }
657 
658 void
659 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie)
660 	struct wsdisplay_softc *sc;
661 	int console;
662 	const struct wsscreen_list *scrdata;
663 	const struct wsdisplay_accessops *accessops;
664 	void *accesscookie;
665 {
666 	static int hookset = 0;
667 	int i, start = 0;
668 #if NWSKBD > 0
669 	struct device *dv;
670 
671 	sc->sc_muxdv = wsmux_create("dmux", sc->sc_dv.dv_unit);
672 	if (!sc->sc_muxdv)
673 		panic("wsdisplay_common_attach: no memory\n");
674 	sc->sc_muxdv->sc_displaydv = &sc->sc_dv;
675 #endif
676 
677 	sc->sc_isconsole = console;
678 
679 	if (console) {
680 		KASSERT(wsdisplay_console_initted);
681 		KASSERT(wsdisplay_console_device == NULL);
682 
683 		sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
684 		if (sc->sc_scr[0] == NULL)
685 			return;
686 		wsdisplay_console_device = sc;
687 
688 		printf(": console (%s, %s emulation)",
689 		       wsdisplay_console_conf.scrdata->name,
690 		       wsdisplay_console_conf.wsemul->name);
691 
692 #if NWSKBD > 0
693 		if ((dv = wskbd_set_console_display(&sc->sc_dv, sc->sc_muxdv)))
694 			printf(", using %s", dv->dv_xname);
695 #endif
696 
697 		sc->sc_focusidx = 0;
698 		sc->sc_focus = sc->sc_scr[0];
699 		start = 1;
700 	}
701 	printf("\n");
702 
703 	sc->sc_accessops = accessops;
704 	sc->sc_accesscookie = accesscookie;
705 	sc->sc_scrdata = scrdata;
706 
707 	/*
708 	 * Set up a number of virtual screens if wanted. The
709 	 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
710 	 * is for special cases like installation kernels.
711 	 */
712 	for (i = start; i < wsdisplay_defaultscreens; i++) {
713 		if (wsdisplay_addscreen(sc, i, 0, 0))
714 			break;
715 	}
716 
717 	if (i > start)
718 		wsdisplay_addscreen_print(sc, start, i-start);
719 
720 	sc->sc_burnoutintvl = (hz * WSDISPLAY_DEFBURNOUT) / 1000;
721 	sc->sc_burninintvl  = (hz * WSDISPLAY_DEFBURNIN ) / 1000;
722 	sc->sc_burnflags = 0;	/* off by default */
723 	timeout_set(&sc->sc_burner, wsdisplay_burner, sc);
724 	sc->sc_burnout = sc->sc_burnoutintvl;
725 	wsdisplay_burn(sc, sc->sc_burnflags);
726 
727 	if (hookset == 0)
728 		shutdownhook_establish(wsdisplay_shutdownhook, NULL);
729 	hookset = 1;
730 }
731 
732 void
733 wsdisplay_cnattach(type, cookie, ccol, crow, defattr)
734 	const struct wsscreen_descr *type;
735 	void *cookie;
736 	int ccol, crow;
737 	long defattr;
738 {
739 	const struct wsemul_ops *wsemul;
740 
741 	KASSERT(!wsdisplay_console_initted);
742 	KASSERT(type->nrows > 0);
743 	KASSERT(type->ncols > 0);
744 	KASSERT(crow < type->nrows);
745 	KASSERT(ccol < type->ncols);
746 
747 	wsdisplay_console_conf.emulops = type->textops;
748 	wsdisplay_console_conf.emulcookie = cookie;
749 	wsdisplay_console_conf.scrdata = type;
750 
751 	wsemul = wsemul_pick(""); /* default */
752 	wsdisplay_console_conf.wsemul = wsemul;
753 	wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
754 								  ccol, crow,
755 								  defattr);
756 
757 	cn_tab = &wsdisplay_cons;
758 
759 	wsdisplay_console_initted = 1;
760 }
761 
762 /*
763  * Tty and cdevsw functions.
764  */
765 int
766 wsdisplayopen(dev, flag, mode, p)
767 	dev_t dev;
768 	int flag, mode;
769 	struct proc *p;
770 {
771 	struct wsdisplay_softc *sc;
772 	struct tty *tp;
773 	int unit, newopen, error;
774 	struct wsscreen *scr;
775 
776 	unit = WSDISPLAYUNIT(dev);
777 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
778 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
779 		return (ENXIO);
780 
781 	if (ISWSDISPLAYCTL(dev))
782 		return (0);
783 
784 	if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
785 		return (ENXIO);
786 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
787 	if (!scr)
788 		return (ENXIO);
789 
790 	if (WSSCREEN_HAS_TTY(scr)) {
791 		tp = scr->scr_tty;
792 		tp->t_oproc = wsdisplaystart;
793 		tp->t_param = wsdisplayparam;
794 		tp->t_dev = dev;
795 		newopen = (tp->t_state & TS_ISOPEN) == 0;
796 		if (newopen) {
797 			ttychars(tp);
798 			tp->t_iflag = TTYDEF_IFLAG;
799 			tp->t_oflag = TTYDEF_OFLAG;
800 			tp->t_cflag = TTYDEF_CFLAG;
801 			tp->t_lflag = TTYDEF_LFLAG;
802 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
803 			wsdisplayparam(tp, &tp->t_termios);
804 			ttsetwater(tp);
805 		} else if ((tp->t_state & TS_XCLUDE) != 0 &&
806 			   p->p_ucred->cr_uid != 0)
807 			return (EBUSY);
808 		tp->t_state |= TS_CARR_ON;
809 
810 		error = ((*linesw[tp->t_line].l_open)(dev, tp));
811 		if (error)
812 			return (error);
813 
814 		if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
815 			/* set window sizes as appropriate, and reset
816 			 the emulation */
817 			tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
818 			tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
819 
820 			/* wsdisplay_set_emulation() */
821 		}
822 	}
823 
824 	scr->scr_flags |= SCR_OPEN;
825 	return (0);
826 }
827 
828 int
829 wsdisplayclose(dev, flag, mode, p)
830 	dev_t dev;
831 	int flag, mode;
832 	struct proc *p;
833 {
834 	struct wsdisplay_softc *sc;
835 	struct tty *tp;
836 	int unit;
837 	struct wsscreen *scr;
838 
839 	unit = WSDISPLAYUNIT(dev);
840 	sc = wsdisplay_cd.cd_devs[unit];
841 
842 	if (ISWSDISPLAYCTL(dev))
843 		return (0);
844 
845 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
846 
847 	if (WSSCREEN_HAS_TTY(scr)) {
848 		if (scr->scr_hold_screen) {
849 			int s;
850 
851 			/* XXX RESET KEYBOARD LEDS, etc. */
852 			s = spltty();	/* avoid conflict with keyboard */
853 			wsdisplay_kbdholdscreen((struct device *)sc, 0);
854 			splx(s);
855 		}
856 		tp = scr->scr_tty;
857 		(*linesw[tp->t_line].l_close)(tp, flag);
858 		ttyclose(tp);
859 	}
860 
861 	if (scr->scr_syncops)
862 		(*scr->scr_syncops->destroy)(scr->scr_synccookie);
863 
864 	if (WSSCREEN_HAS_EMULATOR(scr)) {
865 		scr->scr_flags &= ~SCR_GRAPHICS;
866 		(*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
867 						 WSEMUL_RESET);
868 		if (wsdisplay_clearonclose)
869 			(*scr->scr_dconf->wsemul->reset)
870 				(scr->scr_dconf->wsemulcookie,
871 				 WSEMUL_CLEARSCREEN);
872 	}
873 
874 #ifdef WSDISPLAY_COMPAT_RAWKBD
875 	if (scr->scr_rawkbd) {
876 		int kbmode = WSKBD_TRANSLATED;
877 		(void) wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
878 						(caddr_t)&kbmode, 0, p);
879 	}
880 #endif
881 
882 	scr->scr_flags &= ~SCR_OPEN;
883 
884 	/* remove the selection at logout */
885 	if (Copybuffer)
886 		bzero(Copybuffer, Copybuffer_size);
887 	Paste_avail = 0;
888 
889 	return (0);
890 }
891 
892 int
893 wsdisplayread(dev, uio, flag)
894 	dev_t dev;
895 	struct uio *uio;
896 	int flag;
897 {
898 	struct wsdisplay_softc *sc;
899 	struct tty *tp;
900 	int unit;
901 	struct wsscreen *scr;
902 
903 	unit = WSDISPLAYUNIT(dev);
904 	sc = wsdisplay_cd.cd_devs[unit];
905 
906 	if (ISWSDISPLAYCTL(dev))
907 		return (0);
908 
909 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
910 
911 	if (!WSSCREEN_HAS_TTY(scr))
912 		return (ENODEV);
913 
914 	tp = scr->scr_tty;
915 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
916 }
917 
918 int
919 wsdisplaywrite(dev, uio, flag)
920 	dev_t dev;
921 	struct uio *uio;
922 	int flag;
923 {
924 	struct wsdisplay_softc *sc;
925 	struct tty *tp;
926 	int unit;
927 	struct wsscreen *scr;
928 
929 	unit = WSDISPLAYUNIT(dev);
930 	sc = wsdisplay_cd.cd_devs[unit];
931 
932 	if (ISWSDISPLAYCTL(dev))
933 		return (0);
934 
935 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
936 
937 	if (!WSSCREEN_HAS_TTY(scr))
938 		return (ENODEV);
939 
940 	tp = scr->scr_tty;
941 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
942 }
943 
944 struct tty *
945 wsdisplaytty(dev)
946 	dev_t dev;
947 {
948 	struct wsdisplay_softc *sc;
949 	int unit;
950 	struct wsscreen *scr;
951 
952 	unit = WSDISPLAYUNIT(dev);
953 	sc = wsdisplay_cd.cd_devs[unit];
954 
955 	if (ISWSDISPLAYCTL(dev))
956 		panic("wsdisplaytty() on ctl device");
957 
958 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
959 
960 	return (scr->scr_tty);
961 }
962 
963 int
964 wsdisplayioctl(dev, cmd, data, flag, p)
965 	dev_t dev;
966 	u_long cmd;
967 	caddr_t data;
968 	int flag;
969 	struct proc *p;
970 {
971 	struct wsdisplay_softc *sc;
972 	struct tty *tp;
973 	int unit, error;
974 	struct wsscreen *scr;
975 
976 	unit = WSDISPLAYUNIT(dev);
977 	sc = wsdisplay_cd.cd_devs[unit];
978 
979 #ifdef WSDISPLAY_COMPAT_USL
980 	error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p);
981 	if (error >= 0)
982 		return (error);
983 #endif
984 
985 	if (ISWSDISPLAYCTL(dev))
986 		return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p));
987 
988 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
989 
990 	if (WSSCREEN_HAS_TTY(scr)) {
991 		tp = scr->scr_tty;
992 
993 /* printf("disc\n"); */
994 		/* do the line discipline ioctls first */
995 		error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
996 		if (error >= 0)
997 			return (error);
998 
999 /* printf("tty\n"); */
1000 		/* then the tty ioctls */
1001 		error = ttioctl(tp, cmd, data, flag, p);
1002 		if (error >= 0)
1003 			return (error);
1004 	}
1005 
1006 #ifdef WSDISPLAY_COMPAT_USL
1007 	error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p);
1008 	if (error >= 0)
1009 		return (error);
1010 #endif
1011 
1012 	error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p);
1013 	return (error != -1 ? error : ENOTTY);
1014 }
1015 
1016 int
1017 wsdisplay_param(dev, cmd, dp)
1018 	struct device *dev;
1019 	u_long cmd;
1020 	struct wsdisplay_param *dp;
1021 {
1022 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1023 	return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
1024 					   (caddr_t)dp, 0, NULL));
1025 }
1026 
1027 int
1028 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)
1029 	struct wsdisplay_softc *sc;
1030 	struct wsscreen *scr;
1031 	u_long cmd;
1032 	caddr_t data;
1033 	int flag;
1034 	struct proc *p;
1035 {
1036 	int error;
1037 
1038 #if NWSKBD > 0
1039 #ifdef WSDISPLAY_COMPAT_RAWKBD
1040 	switch (cmd) {
1041 	    case WSKBDIO_SETMODE:
1042 		scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
1043 		return (wsdisplay_update_rawkbd(sc, scr));
1044 	    case WSKBDIO_GETMODE:
1045 		*(int *)data = (scr->scr_rawkbd ?
1046 				WSKBD_RAW : WSKBD_TRANSLATED);
1047 		return (0);
1048 	}
1049 #endif
1050 	error = wsmux_displayioctl(&sc->sc_muxdv->sc_dv, cmd, data, flag, p);
1051 	if (error >= 0)
1052 		return (error);
1053 #endif /* NWSKBD > 0 */
1054 
1055 	switch (cmd) {
1056 	case WSDISPLAYIO_GMODE:
1057 		*(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ?
1058 		    WSDISPLAYIO_MODE_MAPPED : WSDISPLAYIO_MODE_EMUL);
1059 		return (0);
1060 
1061 	case WSDISPLAYIO_SMODE:
1062 #define d (*(int *)data)
1063 		if (d != WSDISPLAYIO_MODE_EMUL && d != WSDISPLAYIO_MODE_MAPPED)
1064 			return (EINVAL);
1065 
1066 	    if (WSSCREEN_HAS_EMULATOR(scr)) {
1067 		    scr->scr_flags &= ~SCR_GRAPHICS;
1068 		    if (d == WSDISPLAYIO_MODE_MAPPED)
1069 			    scr->scr_flags |= SCR_GRAPHICS;
1070 	    } else if (d == WSDISPLAYIO_MODE_EMUL)
1071 		    return (EINVAL);
1072 
1073 	    (void)(*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
1074 		    flag, p);
1075 
1076 	    return (0);
1077 #undef d
1078 
1079 	case WSDISPLAYIO_USEFONT:
1080 #define d ((struct wsdisplay_font *)data)
1081 		if (!sc->sc_accessops->load_font)
1082 			return (EINVAL);
1083 		d->data = 0;
1084 		error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
1085 		    scr->scr_dconf->emulcookie, d);
1086 		if (!error && WSSCREEN_HAS_EMULATOR(scr))
1087 			(*scr->scr_dconf->wsemul->reset)
1088 			    (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
1089 		return (error);
1090 #undef d
1091 	case WSDISPLAYIO_GVIDEO:
1092 		*(u_int *)data = !sc->sc_burnman;
1093 		break;
1094 
1095 	case WSDISPLAYIO_SVIDEO:
1096 		if (*(u_int *)data != WSDISPLAYIO_VIDEO_OFF &&
1097 		    *(u_int *)data != WSDISPLAYIO_VIDEO_ON)
1098 			return (EINVAL);
1099 		if (sc->sc_accessops->burn_screen == NULL)
1100 			return (EOPNOTSUPP);
1101 		(*sc->sc_accessops->burn_screen)(sc->sc_accesscookie,
1102 		     *(u_int *)data, sc->sc_burnflags);
1103 		break;
1104 
1105 	case WSDISPLAYIO_GBURNER:
1106 #define d ((struct wsdisplay_burner *)data)
1107 		d->on  = sc->sc_burninintvl  * 1000 / hz;
1108 		d->off = sc->sc_burnoutintvl * 1000 / hz;
1109 		d->flags = sc->sc_burnflags;
1110 		return (0);
1111 
1112 	case WSDISPLAYIO_SBURNER:
1113 		error = EINVAL;
1114 		if (d->flags & (WSDISPLAY_BURN_VBLANK | WSDISPLAY_BURN_KBD |
1115 		    WSDISPLAY_BURN_MOUSE | WSDISPLAY_BURN_OUTPUT)) {
1116 			error = 0;
1117 			sc->sc_burnflags = d->flags;
1118 		}
1119 		if (d->on) {
1120 			error = 0;
1121 			sc->sc_burninintvl = hz * d->on / 1000;
1122 			if (sc->sc_burnman)
1123 				sc->sc_burnout = sc->sc_burninintvl;
1124 		}
1125 		if (d->off) {
1126 			error = 0;
1127 			sc->sc_burnoutintvl = hz * d->off / 1000;
1128 			if (!sc->sc_burnman) {
1129 				sc->sc_burnout = sc->sc_burnoutintvl;
1130 				/* reinit timeout if changed */
1131 				wsdisplay_burn(sc, sc->sc_burnflags);
1132 			}
1133 		}
1134 		return (error);
1135 #undef d
1136 	case WSDISPLAYIO_GETSCREEN:
1137 		return (wsdisplay_getscreen(sc,
1138 		    (struct wsdisplay_addscreendata *)data));
1139 
1140 	case WSDISPLAYIO_SETSCREEN:
1141 		return (wsdisplay_switch((void *)sc, *(int *)data, 1));
1142 	}
1143 
1144 	/* check ioctls for display */
1145 	return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
1146 	    flag, p));
1147 }
1148 
1149 int
1150 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)
1151 	struct wsdisplay_softc *sc;
1152 	u_long cmd;
1153 	caddr_t data;
1154 	int flag;
1155 	struct proc *p;
1156 {
1157 	int error;
1158 	void *buf;
1159 	size_t fontsz;
1160 #if defined(COMPAT_14) && NWSKBD > 0
1161 	struct wsmux_device wsmuxdata;
1162 #endif
1163 
1164 	switch (cmd) {
1165 	case WSDISPLAYIO_WSMOUSED:
1166 		error = wsmoused(sc, cmd, data, flag, p);
1167 		return (error);
1168 	case WSDISPLAYIO_ADDSCREEN:
1169 #define d ((struct wsdisplay_addscreendata *)data)
1170 		if ((error = wsdisplay_addscreen(sc, d->idx,
1171 		    d->screentype, d->emul)) == 0)
1172 			wsdisplay_addscreen_print(sc, d->idx, 0);
1173 		return (error);
1174 #undef d
1175 	case WSDISPLAYIO_DELSCREEN:
1176 #define d ((struct wsdisplay_delscreendata *)data)
1177 		return (wsdisplay_delscreen(sc, d->idx, d->flags));
1178 #undef d
1179 	case WSDISPLAYIO_GETSCREEN:
1180 		return (wsdisplay_getscreen(sc,
1181 		    (struct wsdisplay_addscreendata *)data));
1182 	case WSDISPLAYIO_SETSCREEN:
1183 		return (wsdisplay_switch((void *)sc, *(int *)data, 1));
1184 	case WSDISPLAYIO_LDFONT:
1185 #define d ((struct wsdisplay_font *)data)
1186 		if (!sc->sc_accessops->load_font)
1187 			return (EINVAL);
1188 		if (d->index >= WSDISPLAY_MAXFONT)
1189 			return (EINVAL);
1190 		fontsz = d->fontheight * d->stride * d->numchars;
1191 		if (fontsz > WSDISPLAY_MAXFONTSZ)
1192 			return (EINVAL);
1193 
1194 		buf = malloc(fontsz, M_DEVBUF, M_WAITOK);
1195 		error = copyin(d->data, buf, fontsz);
1196 		if (error) {
1197 			free(buf, M_DEVBUF);
1198 			return (error);
1199 		}
1200 		d->data = buf;
1201 		error =
1202 		  (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
1203 		if (error)
1204 			free(buf, M_DEVBUF);
1205 		else if (d->index >= 0 || d->index < WSDISPLAY_MAXFONT)
1206 			sc->sc_fonts[d->index] = *d;
1207 		return (error);
1208 
1209 	case WSDISPLAYIO_LSFONT:
1210 		if (d->index < 0 || d->index >= WSDISPLAY_MAXFONT)
1211 			return (EINVAL);
1212 		*d = sc->sc_fonts[d->index];
1213 		return (0);
1214 
1215 	case WSDISPLAYIO_DELFONT:
1216 		return (EINVAL);
1217 #undef d
1218 
1219 #if NWSKBD > 0
1220 #ifdef COMPAT_14
1221 	case _O_WSDISPLAYIO_SETKEYBOARD:
1222 #define d ((struct wsdisplay_kbddata *)data)
1223 		switch (d->op) {
1224 		case _O_WSDISPLAY_KBD_ADD:
1225 			if (d->idx == -1) {
1226 				d->idx = wskbd_pickfree();
1227 				if (d->idx == -1)
1228 					return (ENXIO);
1229 			}
1230 			wsmuxdata.type = WSMUX_KBD;
1231 			wsmuxdata.idx = d->idx;
1232 			return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv,
1233 					     WSMUX_ADD_DEVICE,
1234 					     (caddr_t)&wsmuxdata, flag, p));
1235 		case _O_WSDISPLAY_KBD_DEL:
1236 			wsmuxdata.type = WSMUX_KBD;
1237 			wsmuxdata.idx = d->idx;
1238 			return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv,
1239 					     WSMUX_REMOVE_DEVICE,
1240 					     (caddr_t)&wsmuxdata, flag, p));
1241 		default:
1242 			return (EINVAL);
1243 		}
1244 #undef d
1245 #endif
1246 
1247 	case WSMUX_ADD_DEVICE:
1248 #define d ((struct wsmux_device *)data)
1249 		if (d->idx == -1 && d->type == WSMUX_KBD)
1250 			d->idx = wskbd_pickfree();
1251 #undef d
1252 		/* fall into */
1253 	case WSMUX_INJECTEVENT:
1254 	case WSMUX_REMOVE_DEVICE:
1255 	case WSMUX_LIST_DEVICES:
1256 		return (wsmuxdoioctl(&sc->sc_muxdv->sc_dv, cmd, data, flag,p));
1257 #endif /* NWSKBD > 0 */
1258 
1259 	}
1260 	return (EINVAL);
1261 }
1262 
1263 paddr_t
1264 wsdisplaymmap(dev, offset, prot)
1265 	dev_t dev;
1266 	off_t offset;
1267 	int prot;
1268 {
1269 	struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1270 	struct wsscreen *scr;
1271 
1272 	if (ISWSDISPLAYCTL(dev))
1273 		return (-1);
1274 
1275 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1276 
1277 	if (!(scr->scr_flags & SCR_GRAPHICS))
1278 		return (-1);
1279 
1280 	/* pass mmap to display */
1281 	return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
1282 }
1283 
1284 int
1285 wsdisplayselect(dev, events, p)
1286 	dev_t dev;
1287 	int events;
1288 	struct proc *p;
1289 {
1290 	struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1291 	struct wsscreen *scr;
1292 
1293 	if (ISWSDISPLAYCTL(dev))
1294 		return (0);
1295 
1296 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1297 
1298 	if (WSSCREEN_HAS_TTY(scr))
1299 		return (ttselect(dev, events, p));
1300 	else
1301 		return (0);
1302 }
1303 
1304 int
1305 wsdisplaykqfilter(dev, kn)
1306 	dev_t dev;
1307 	struct knote *kn;
1308 {
1309 	struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1310 	struct wsscreen *scr;
1311 
1312 	if (ISWSDISPLAYCTL(dev))
1313 		return (1);
1314 
1315 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1316 
1317 	if (WSSCREEN_HAS_TTY(scr))
1318 		return (ttkqfilter(dev, kn));
1319 	else
1320 		return (1);
1321 }
1322 
1323 void
1324 wsdisplaystart(tp)
1325 	struct tty *tp;
1326 {
1327 	struct wsdisplay_softc *sc;
1328 	struct wsscreen *scr;
1329 	int s, n, unit;
1330 	u_char *buf;
1331 
1332 	unit = WSDISPLAYUNIT(tp->t_dev);
1333 	if (unit >= wsdisplay_cd.cd_ndevs ||
1334 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
1335 		return;
1336 
1337 	s = spltty();
1338 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
1339 		splx(s);
1340 		return;
1341 	}
1342 	if (tp->t_outq.c_cc == 0 && tp->t_wsel.si_selpid == 0)
1343 		goto low;
1344 
1345 	scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)];
1346 	if (scr->scr_hold_screen) {
1347 		tp->t_state |= TS_TIMEOUT;
1348 		splx(s);
1349 		return;
1350 	}
1351 	tp->t_state |= TS_BUSY;
1352 	splx(s);
1353 
1354 	/*
1355 	 * Drain output from ring buffer.
1356 	 * The output will normally be in one contiguous chunk, but when the
1357 	 * ring wraps, it will be in two pieces.. one at the end of the ring,
1358 	 * the other at the start.  For performance, rather than loop here,
1359 	 * we output one chunk, see if there's another one, and if so, output
1360 	 * it too.
1361 	 */
1362 
1363 	n = ndqb(&tp->t_outq, 0);
1364 	buf = tp->t_outq.c_cf;
1365 
1366 	if (!(scr->scr_flags & SCR_GRAPHICS)) {
1367 		KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1368 		wsdisplay_burn(sc, WSDISPLAY_BURN_OUTPUT);
1369 		if (scr == sc->sc_focus) {
1370 			if (IS_SEL_EXISTS(sc->sc_focus))
1371 				/* hide a potential selection */
1372 				remove_selection(sc);
1373 			/* hide a potential mouse cursor */
1374 			mouse_hide(sc);
1375 		}
1376 		(*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1377 		    buf, n, 0);
1378 	}
1379 	ndflush(&tp->t_outq, n);
1380 
1381 	if ((n = ndqb(&tp->t_outq, 0)) > 0) {
1382 		buf = tp->t_outq.c_cf;
1383 
1384 		if (!(scr->scr_flags & SCR_GRAPHICS)) {
1385 			KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1386 			wsdisplay_burn(sc, WSDISPLAY_BURN_OUTPUT);
1387 			(*scr->scr_dconf->wsemul->output)
1388 			    (scr->scr_dconf->wsemulcookie, buf, n, 0);
1389 		}
1390 		ndflush(&tp->t_outq, n);
1391 	}
1392 
1393 	s = spltty();
1394 	tp->t_state &= ~TS_BUSY;
1395 
1396 	tp->t_state |= TS_TIMEOUT;
1397 	timeout_add(&tp->t_rstrt_to, (hz > 128) ? (hz / 128) : 1);
1398 
1399 	if (tp->t_outq.c_cc <= tp->t_lowat) {
1400 low:
1401 		if (tp->t_state&TS_ASLEEP) {
1402 			tp->t_state &= ~TS_ASLEEP;
1403 			wakeup((caddr_t)&tp->t_outq);
1404 		}
1405 		selwakeup(&tp->t_wsel);
1406 	}
1407 	splx(s);
1408 }
1409 
1410 int
1411 wsdisplaystop(tp, flag)
1412 	struct tty *tp;
1413 	int flag;
1414 {
1415 	int s;
1416 
1417 	s = spltty();
1418 	if (ISSET(tp->t_state, TS_BUSY))
1419 		if (!ISSET(tp->t_state, TS_TTSTOP))
1420 			SET(tp->t_state, TS_FLUSH);
1421 	splx(s);
1422 
1423 	return (0);
1424 }
1425 
1426 /* Set line parameters. */
1427 int
1428 wsdisplayparam(tp, t)
1429 	struct tty *tp;
1430 	struct termios *t;
1431 {
1432 
1433 	tp->t_ispeed = t->c_ispeed;
1434 	tp->t_ospeed = t->c_ospeed;
1435 	tp->t_cflag = t->c_cflag;
1436 	return (0);
1437 }
1438 
1439 /*
1440  * Callbacks for the emulation code.
1441  */
1442 void
1443 wsdisplay_emulbell(v)
1444 	void *v;
1445 {
1446 	struct wsscreen *scr = v;
1447 
1448 	if (scr == NULL)		/* console, before real attach */
1449 		return;
1450 
1451 	if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */
1452 		return;
1453 
1454 	(void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
1455 					FWRITE, NULL);
1456 }
1457 
1458 void
1459 wsdisplay_emulinput(v, data, count)
1460 	void *v;
1461 	const u_char *data;
1462 	u_int count;
1463 {
1464 	struct wsscreen *scr = v;
1465 	struct tty *tp;
1466 
1467 	if (v == NULL)			/* console, before real attach */
1468 		return;
1469 
1470 	if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */
1471 		return;
1472 	if (!WSSCREEN_HAS_TTY(scr))
1473 		return;
1474 
1475 	tp = scr->scr_tty;
1476 	while (count-- > 0)
1477 		(*linesw[tp->t_line].l_rint)(*data++, tp);
1478 }
1479 
1480 /*
1481  * Calls from the keyboard interface.
1482  */
1483 void
1484 wsdisplay_kbdinput(dev, ks)
1485 	struct device *dev;
1486 	keysym_t ks;
1487 {
1488 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1489 	struct wsscreen *scr;
1490 	char *dp;
1491 	int count;
1492 	struct tty *tp;
1493 
1494 	KASSERT(sc != NULL);
1495 
1496 	scr = sc->sc_focus;
1497 
1498 	if (!scr || !WSSCREEN_HAS_TTY(scr))
1499 		return;
1500 
1501 	tp = scr->scr_tty;
1502 
1503 	if (KS_GROUP(ks) == KS_GROUP_Ascii)
1504 		(*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp);
1505 	else if (WSSCREEN_HAS_EMULATOR(scr)) {
1506 		count = (*scr->scr_dconf->wsemul->translate)
1507 		    (scr->scr_dconf->wsemulcookie, ks, &dp);
1508 		while (count-- > 0)
1509 			(*linesw[tp->t_line].l_rint)(*dp++, tp);
1510 	}
1511 }
1512 
1513 #ifdef WSDISPLAY_COMPAT_RAWKBD
1514 int
1515 wsdisplay_update_rawkbd(sc, scr)
1516 	struct wsdisplay_softc *sc;
1517 	struct wsscreen *scr;
1518 {
1519 	int s, raw, data, error;
1520 	s = spltty();
1521 
1522 	raw = (scr ? scr->scr_rawkbd : 0);
1523 
1524 	if (scr != sc->sc_focus ||
1525 	    sc->sc_rawkbd == raw) {
1526 		splx(s);
1527 		return (0);
1528 	}
1529 
1530 	data = raw ? WSKBD_RAW : WSKBD_TRANSLATED;
1531 	error = wsmux_displayioctl(&sc->sc_muxdv->sc_dv, WSKBDIO_SETMODE,
1532 				   (caddr_t)&data, 0, 0);
1533 	if (!error)
1534 		sc->sc_rawkbd = raw;
1535 	splx(s);
1536 	return (error);
1537 }
1538 #endif
1539 
1540 int
1541 wsdisplay_switch3(arg, error, waitok)
1542 	void *arg;
1543 	int error, waitok;
1544 {
1545 	struct wsdisplay_softc *sc = arg;
1546 	int no;
1547 	struct wsscreen *scr;
1548 
1549 	if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1550 		printf("wsdisplay_switch3: not switching\n");
1551 		return (EINVAL);
1552 	}
1553 
1554 	no = sc->sc_screenwanted;
1555 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1556 		panic("wsdisplay_switch3: invalid screen %d", no);
1557 	scr = sc->sc_scr[no];
1558 	if (!scr) {
1559 		printf("wsdisplay_switch3: screen %d disappeared\n", no);
1560 		error = ENXIO;
1561 	}
1562 
1563 	if (error) {
1564 		/* try to recover, avoid recursion */
1565 
1566 		if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
1567 			printf("wsdisplay_switch3: giving up\n");
1568 			sc->sc_focus = 0;
1569 #ifdef WSDISPLAY_COMPAT_RAWKBD
1570 			wsdisplay_update_rawkbd(sc, 0);
1571 #endif
1572 		sc->sc_flags &= ~SC_SWITCHPENDING;
1573 			return (error);
1574 		}
1575 
1576 		sc->sc_screenwanted = sc->sc_oldscreen;
1577 		sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1578 		return (wsdisplay_switch1(arg, 0, waitok));
1579 	}
1580 
1581 	sc->sc_flags &= ~SC_SWITCHPENDING;
1582 
1583 	if (!error && (scr->scr_flags & SCR_WAITACTIVE))
1584 		wakeup(scr);
1585 	return (error);
1586 }
1587 
1588 int
1589 wsdisplay_switch2(arg, error, waitok)
1590 	void *arg;
1591 	int error, waitok;
1592 {
1593 	struct wsdisplay_softc *sc = arg;
1594 	int no;
1595 	struct wsscreen *scr;
1596 
1597 	if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1598 		printf("wsdisplay_switch2: not switching\n");
1599 		return (EINVAL);
1600 	}
1601 
1602 	no = sc->sc_screenwanted;
1603 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1604 		panic("wsdisplay_switch2: invalid screen %d", no);
1605 	scr = sc->sc_scr[no];
1606 	if (!scr) {
1607 		printf("wsdisplay_switch2: screen %d disappeared\n", no);
1608 		error = ENXIO;
1609 	}
1610 
1611 	if (error) {
1612 		/* try to recover, avoid recursion */
1613 
1614 		if (sc->sc_oldscreen == WSDISPLAY_NULLSCREEN) {
1615 			printf("wsdisplay_switch2: giving up\n");
1616 			sc->sc_focus = 0;
1617 			sc->sc_flags &= ~SC_SWITCHPENDING;
1618 			return (error);
1619 		}
1620 
1621 		sc->sc_screenwanted = sc->sc_oldscreen;
1622 		sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1623 		return (wsdisplay_switch1(arg, 0, waitok));
1624 	}
1625 
1626 	sc->sc_focusidx = no;
1627 	sc->sc_focus = scr;
1628 
1629 #ifdef WSDISPLAY_COMPAT_RAWKBD
1630 	(void) wsdisplay_update_rawkbd(sc, scr);
1631 #endif
1632 	/* keyboard map??? */
1633 
1634 #define wsswitch_cb3 ((void (*) __P((void *, int, int)))wsdisplay_switch3)
1635 	if (scr->scr_syncops) {
1636 		error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok,
1637 	  sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb3, sc);
1638 		if (error == EAGAIN) {
1639 			/* switch will be done asynchronously */
1640 			return (0);
1641 		}
1642 	}
1643 
1644 	return (wsdisplay_switch3(sc, error, waitok));
1645 }
1646 
1647 int
1648 wsdisplay_switch1(arg, error, waitok)
1649 	void *arg;
1650 	int error, waitok;
1651 {
1652 	struct wsdisplay_softc *sc = arg;
1653 	int no;
1654 	struct wsscreen *scr;
1655 
1656 	if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1657 		printf("wsdisplay_switch1: not switching\n");
1658 		return (EINVAL);
1659 	}
1660 
1661 	no = sc->sc_screenwanted;
1662 	if (no == WSDISPLAY_NULLSCREEN) {
1663 		sc->sc_flags &= ~SC_SWITCHPENDING;
1664 		if (!error) {
1665 			sc->sc_focus = 0;
1666 		}
1667 		wakeup(sc);
1668 		return (error);
1669 	}
1670 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1671 		panic("wsdisplay_switch1: invalid screen %d", no);
1672 	scr = sc->sc_scr[no];
1673 	if (!scr) {
1674 		printf("wsdisplay_switch1: screen %d disappeared\n", no);
1675 		error = ENXIO;
1676 	}
1677 
1678 	if (error) {
1679 		sc->sc_flags &= ~SC_SWITCHPENDING;
1680 		return (error);
1681 	}
1682 
1683 #define wsswitch_cb2 ((void (*) __P((void *, int, int)))wsdisplay_switch2)
1684 	error = (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
1685 						 scr->scr_dconf->emulcookie,
1686 						 waitok,
1687 	  sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb2, sc);
1688 	if (error == EAGAIN) {
1689 		/* switch will be done asynchronously */
1690 		return (0);
1691 	}
1692 
1693 	return (wsdisplay_switch2(sc, error, waitok));
1694 }
1695 
1696 int
1697 wsdisplay_switch(dev, no, waitok)
1698 	struct device *dev;
1699 	int no, waitok;
1700 {
1701 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1702 	int s, res = 0;
1703 	struct wsscreen *scr;
1704 
1705 	if (no != WSDISPLAY_NULLSCREEN &&
1706 	    (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no]))
1707 		return (ENXIO);
1708 
1709 	s = spltty();
1710 
1711 	if ((sc->sc_focus && no == sc->sc_focusidx) ||
1712 	    (sc->sc_focus == NULL && no == WSDISPLAY_NULLSCREEN)) {
1713 		splx(s);
1714 		return (0);
1715 	}
1716 
1717 	if (sc->sc_flags & SC_SWITCHPENDING) {
1718 		splx(s);
1719 		return (EBUSY);
1720 	}
1721 
1722 	sc->sc_flags |= SC_SWITCHPENDING;
1723 	sc->sc_screenwanted = no;
1724 
1725 	splx(s);
1726 
1727 	scr = sc->sc_focus;
1728 	if (!scr) {
1729 		sc->sc_oldscreen = WSDISPLAY_NULLSCREEN;
1730 		return (wsdisplay_switch1(sc, 0, waitok));
1731 	} else
1732 		sc->sc_oldscreen = sc->sc_focusidx;
1733 
1734 #define wsswitch_cb1 ((void (*) __P((void *, int, int)))wsdisplay_switch1)
1735 	if (scr->scr_syncops) {
1736 		res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok,
1737 	  sc->sc_isconsole && wsdisplay_cons_pollmode ? 0 : wsswitch_cb1, sc);
1738 		if (res == EAGAIN) {
1739 			/* switch will be done asynchronously */
1740 			return (0);
1741 		}
1742 	} else if (scr->scr_flags & SCR_GRAPHICS) {
1743 		/* no way to save state */
1744 		res = EBUSY;
1745 	}
1746 
1747 	if (IS_SEL_EXISTS(sc->sc_focus))
1748 		/* hide a potential selection */
1749 		remove_selection(sc);
1750 
1751 	mouse_hide(sc); /* hide a potential mouse cursor */
1752 
1753 	return (wsdisplay_switch1(sc, res, waitok));
1754 }
1755 
1756 void
1757 wsdisplay_reset(dev, op)
1758 	struct device *dev;
1759 	enum wsdisplay_resetops op;
1760 {
1761 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1762 	struct wsscreen *scr;
1763 
1764 	KASSERT(sc != NULL);
1765 	scr = sc->sc_focus;
1766 
1767 	if (!scr)
1768 		return;
1769 
1770 	switch (op) {
1771 	case WSDISPLAY_RESETEMUL:
1772 		if (!WSSCREEN_HAS_EMULATOR(scr))
1773 			break;
1774 		(*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
1775 						 WSEMUL_RESET);
1776 		break;
1777 	case WSDISPLAY_RESETCLOSE:
1778 		wsdisplay_closescreen(sc, scr);
1779 		break;
1780 	}
1781 }
1782 
1783 /*
1784  * Interface for (external) VT switch / process synchronization code
1785  */
1786 int
1787 wsscreen_attach_sync(scr, ops, cookie)
1788 	struct wsscreen *scr;
1789 	const struct wscons_syncops *ops;
1790 	void *cookie;
1791 {
1792 	if (scr->scr_syncops) {
1793 		/*
1794 		 * The screen is already claimed.
1795 		 * Check if the owner is still alive.
1796 		 */
1797 		if ((*scr->scr_syncops->check)(scr->scr_synccookie))
1798 			return (EBUSY);
1799 	}
1800 	scr->scr_syncops = ops;
1801 	scr->scr_synccookie = cookie;
1802 	return (0);
1803 }
1804 
1805 int
1806 wsscreen_detach_sync(scr)
1807 	struct wsscreen *scr;
1808 {
1809 	if (!scr->scr_syncops)
1810 		return (EINVAL);
1811 	scr->scr_syncops = 0;
1812 	return (0);
1813 }
1814 
1815 int
1816 wsscreen_lookup_sync(scr, ops, cookiep)
1817 	struct wsscreen *scr;
1818 	const struct wscons_syncops *ops; /* used as ID */
1819 	void **cookiep;
1820 {
1821 	if (!scr->scr_syncops || ops != scr->scr_syncops)
1822 		return (EINVAL);
1823 	*cookiep = scr->scr_synccookie;
1824 	return (0);
1825 }
1826 
1827 /*
1828  * Interface to virtual screen stuff
1829  */
1830 int
1831 wsdisplay_maxscreenidx(sc)
1832 	struct wsdisplay_softc *sc;
1833 {
1834 	return (WSDISPLAY_MAXSCREEN - 1);
1835 }
1836 
1837 int
1838 wsdisplay_screenstate(sc, idx)
1839 	struct wsdisplay_softc *sc;
1840 	int idx;
1841 {
1842 	if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
1843 		return (EINVAL);
1844 	if (!sc->sc_scr[idx])
1845 		return (ENXIO);
1846 	return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0);
1847 }
1848 
1849 int
1850 wsdisplay_getactivescreen(sc)
1851 	struct wsdisplay_softc *sc;
1852 {
1853 	return (sc->sc_focus ? sc->sc_focusidx : WSDISPLAY_NULLSCREEN);
1854 }
1855 
1856 int
1857 wsscreen_switchwait(sc, no)
1858 	struct wsdisplay_softc *sc;
1859 	int no;
1860 {
1861 	struct wsscreen *scr;
1862 	int s, res = 0;
1863 
1864 	if (no == WSDISPLAY_NULLSCREEN) {
1865 		s = spltty();
1866 		while (sc->sc_focus && res == 0) {
1867 			res = tsleep(sc, PCATCH, "wswait", 0);
1868 		}
1869 		splx(s);
1870 		return (res);
1871 	}
1872 
1873 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1874 		return (ENXIO);
1875 	scr = sc->sc_scr[no];
1876 	if (!scr)
1877 		return (ENXIO);
1878 
1879 	s = spltty();
1880 	if (scr != sc->sc_focus) {
1881 		scr->scr_flags |= SCR_WAITACTIVE;
1882 		res = tsleep(scr, PCATCH, "wswait", 0);
1883 		if (scr != sc->sc_scr[no])
1884 			res = ENXIO; /* disappeared in the meantime */
1885 		else
1886 			scr->scr_flags &= ~SCR_WAITACTIVE;
1887 	}
1888 	splx(s);
1889 	return (res);
1890 }
1891 
1892 void
1893 wsdisplay_kbdholdscreen(dev, hold)
1894 	struct device *dev;
1895 	int hold;
1896 {
1897 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1898 	struct wsscreen *scr;
1899 
1900 	scr = sc->sc_focus;
1901 
1902 	if (hold)
1903 		scr->scr_hold_screen = 1;
1904 	else {
1905 		scr->scr_hold_screen = 0;
1906 		timeout_add(&scr->scr_tty->t_rstrt_to, 0); /* "immediate" */
1907 	}
1908 }
1909 
1910 #if NWSKBD > 0
1911 struct device *
1912 wsdisplay_set_console_kbd(kbddv)
1913 	struct device *kbddv;
1914 {
1915 	if (!wsdisplay_console_device)
1916 		return (0);
1917 	if (wskbd_add_mux(kbddv->dv_unit, wsdisplay_console_device->sc_muxdv))
1918 		return (0);
1919 	return (&wsdisplay_console_device->sc_dv);
1920 }
1921 #endif /* NWSKBD > 0 */
1922 
1923 /*
1924  * Console interface.
1925  */
1926 void
1927 wsdisplay_cnputc(dev, i)
1928 	dev_t dev;
1929 	int i;
1930 {
1931 	struct wsscreen_internal *dc;
1932 	char c = i;
1933 
1934 	if (!wsdisplay_console_initted)
1935 		return;
1936 
1937 	if (wsdisplay_console_device != NULL &&
1938 	    (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
1939 		return;
1940 
1941 	dc = &wsdisplay_console_conf;
1942 	/*wsdisplay_burn(wsdisplay_console_device, WSDISPLAY_BURN_OUTPUT);*/
1943 	(*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
1944 }
1945 
1946 int
1947 wsdisplay_getc_dummy(dev)
1948 	dev_t dev;
1949 {
1950 	/* panic? */
1951 	return (0);
1952 }
1953 
1954 void
1955 wsdisplay_pollc(dev, on)
1956 	dev_t dev;
1957 	int on;
1958 {
1959 	struct wsdisplay_softc *sc = NULL;
1960 	int unit = WSDISPLAYUNIT(dev);
1961 
1962 	if (unit < wsdisplay_cd.cd_ndevs)
1963 		sc = wsdisplay_cd.cd_devs[unit];
1964 
1965 	wsdisplay_cons_pollmode = on;
1966 
1967 	/* notify to fb drivers */
1968 	if (sc != NULL && sc->sc_accessops->pollc != NULL)
1969 		(*sc->sc_accessops->pollc)(sc->sc_accesscookie, on);
1970 
1971 	/* notify to kbd drivers */
1972 	if (wsdisplay_cons_kbd_pollc)
1973 		(*wsdisplay_cons_kbd_pollc)(dev, on);
1974 }
1975 
1976 void
1977 wsdisplay_set_cons_kbd(get, poll, bell)
1978 	int (*get) __P((dev_t));
1979 	void (*poll) __P((dev_t, int));
1980 	void (*bell) __P((dev_t, u_int, u_int, u_int));
1981 {
1982 	wsdisplay_cons.cn_getc = get;
1983 	wsdisplay_cons.cn_bell = bell;
1984 	wsdisplay_cons_kbd_pollc = poll;
1985 }
1986 
1987 void
1988 wsdisplay_unset_cons_kbd()
1989 {
1990 	wsdisplay_cons.cn_getc = wsdisplay_getc_dummy;
1991 	wsdisplay_cons.cn_bell = NULL;
1992 	wsdisplay_cons_kbd_pollc = 0;
1993 }
1994 
1995 /*
1996  * Switch the console display to it's first screen.
1997  */
1998 void
1999 wsdisplay_switchtoconsole()
2000 {
2001 	struct wsdisplay_softc *sc;
2002 	struct wsscreen *scr;
2003 
2004 	if (wsdisplay_console_device != NULL) {
2005 		sc = wsdisplay_console_device;
2006 		scr = sc->sc_scr[0];
2007 		(*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
2008 		    scr->scr_dconf->emulcookie, 0, NULL, NULL);
2009 	}
2010 }
2011 
2012 void
2013 wsscrollback(arg, op)
2014 	void *arg;
2015 	int op;
2016 {
2017 	struct wsdisplay_softc *sc = arg;
2018 	int lines;
2019 
2020 	if (op == WSDISPLAY_SCROLL_RESET)
2021 		lines = 0;
2022 	else {
2023 		lines = sc->sc_focus->scr_dconf->scrdata->nrows - 1;
2024 		if (op == WSDISPLAY_SCROLL_BACKWARD)
2025 			lines = -lines;
2026 	}
2027 
2028 	if (sc->sc_accessops->scrollback) {
2029 		(*sc->sc_accessops->scrollback)(sc->sc_accesscookie,
2030 		    sc->sc_focus->scr_dconf->emulcookie, lines);
2031 	}
2032 }
2033 
2034 void
2035 wsdisplay_burn(v, flags)
2036 	void *v;
2037 	u_int flags;
2038 {
2039 	struct wsdisplay_softc *sc = v;
2040 
2041 	if ((flags & sc->sc_burnflags & (WSDISPLAY_BURN_OUTPUT |
2042 	    WSDISPLAY_BURN_KBD | WSDISPLAY_BURN_MOUSE)) &&
2043 	    sc->sc_accessops->burn_screen) {
2044 		if (sc->sc_burnout)
2045 			timeout_add(&sc->sc_burner, sc->sc_burnout);
2046 		if (sc->sc_burnman)
2047 			sc->sc_burnout = 0;
2048 	}
2049 }
2050 
2051 void
2052 wsdisplay_burner(v)
2053 	void *v;
2054 {
2055 	struct wsdisplay_softc *sc = v;
2056 	int s;
2057 
2058 	if (sc->sc_accessops->burn_screen) {
2059 		(*sc->sc_accessops->burn_screen)(sc->sc_accesscookie,
2060 		    sc->sc_burnman, sc->sc_burnflags);
2061 		s = spltty();
2062 		if (sc->sc_burnman) {
2063 			sc->sc_burnout = sc->sc_burnoutintvl;
2064 			timeout_add(&sc->sc_burner, sc->sc_burnout);
2065 		} else
2066 			sc->sc_burnout = sc->sc_burninintvl;
2067 		sc->sc_burnman = !sc->sc_burnman;
2068 		splx(s);
2069 	}
2070 }
2071 
2072 /*
2073  * Switch the console at shutdown.
2074  */
2075 void
2076 wsdisplay_shutdownhook(arg)
2077 	void *arg;
2078 {
2079 	wsdisplay_switchtoconsole();
2080 }
2081 
2082 /*
2083  * mouse console support functions
2084  */
2085 
2086 /* pointer to the current screen wsdisplay_softc structure */
2087 static struct wsdisplay_softc *sc = NULL;
2088 
2089 /*
2090  * Main function, called from wsdisplay_cfg_ioctl.
2091  */
2092 int
2093 wsmoused(struct wsdisplay_softc *ws_sc, u_long cmd, caddr_t data,
2094 		int flag, struct proc *p)
2095 {
2096 	int error = -1;
2097 	struct wscons_event mouse_event = *(struct wscons_event *)data;
2098 
2099 	if (cmd == WSDISPLAYIO_WSMOUSED) {
2100 		if (IS_MOTION_EVENT(mouse_event.type)) {
2101 			motion_event(mouse_event.type, mouse_event.value);
2102 			return (0);
2103 		}
2104 		if (IS_BUTTON_EVENT(mouse_event.type)) {
2105 			/* XXX tv_sec contains the number of clicks */
2106 			if (mouse_event.type == WSCONS_EVENT_MOUSE_DOWN) {
2107 				button_event(mouse_event.value,
2108 				    mouse_event.time.tv_sec);
2109 			} else
2110 				button_event(mouse_event.value, 0);
2111 			return (0);
2112 		}
2113 		if (IS_CTRL_EVENT(mouse_event.type)) {
2114 			return (ctrl_event(mouse_event.type, mouse_event.value,
2115 			    ws_sc, p));
2116 		}
2117 	}
2118 	return (error);
2119 }
2120 
2121 /*
2122  * Mouse motion events
2123  */
2124 void
2125 motion_event(u_int type, int value)
2126 {
2127 	switch (type) {
2128 		case WSCONS_EVENT_MOUSE_DELTA_X:
2129 			mouse_moverel(value, 0);
2130 			break;
2131 		case WSCONS_EVENT_MOUSE_DELTA_Y:
2132 			mouse_moverel(0, 0 - value);
2133 			break;
2134 		case WSCONS_EVENT_MOUSE_DELTA_Z:
2135 			mouse_zaxis(value);
2136 			break;
2137 		default:
2138 			break;
2139 	}
2140 }
2141 
2142 /*
2143  * Button clicks events
2144  */
2145 void
2146 button_event(int button, int clicks)
2147 {
2148 	switch (button) {
2149 	case MOUSE_COPY_BUTTON:
2150 		switch (clicks % 4) {
2151 		case 0: /* button is up */
2152 			mouse_copy_end();
2153 			mouse_copy_selection();
2154 			break;
2155 		case 1: /* single click */
2156 			mouse_copy_start();
2157 			mouse_copy_selection();
2158 			break;
2159 		case 2: /* double click */
2160 			mouse_copy_word();
2161 			mouse_copy_selection();
2162 			break;
2163 		case 3: /* triple click */
2164 			mouse_copy_line();
2165 			mouse_copy_selection();
2166 			break;
2167 		default:
2168 			break;
2169 		}
2170 		break;
2171 
2172 	case MOUSE_PASTE_BUTTON:
2173 		switch (clicks) {
2174 		case 0: /* button is up */
2175 			break;
2176 		default: /* paste */
2177 			mouse_paste();
2178 			break;
2179 		}
2180 		break;
2181 
2182 	case MOUSE_EXTEND_BUTTON:
2183 		switch (clicks) {
2184 		case 0: /* button is up */
2185 			break;
2186 		default: /* extend the selection */
2187 			mouse_copy_extend_after();
2188 			break;
2189 		}
2190 		break;
2191 
2192 	default:
2193 		break;
2194 	}
2195 }
2196 
2197 /*
2198  * Control events
2199  */
2200 int
2201 ctrl_event(u_int type, int value, struct wsdisplay_softc *ws_sc, struct proc *p)
2202 {
2203 	int i;
2204 
2205 	if (type == WSCONS_EVENT_WSMOUSED_ON) {
2206 		if (!ws_sc->sc_accessops->getchar)
2207 			/* no wsmoused support in the display driver */
2208 			return (1);
2209 		/* initialization of globals */
2210 		sc = ws_sc;
2211 		allocate_copybuffer(sc);
2212 		Paste_avail = 0;
2213 	}
2214 	if (type == WSCONS_EVENT_WSMOUSED_OFF) {
2215 		Paste_avail = 0;
2216 		return (0);
2217 	}
2218 	for (i = 0 ; i < WSDISPLAY_DEFAULTSCREENS ; i++) {
2219 		sc->sc_scr[i]->mouse =
2220 			((WS_NCOLS(sc->sc_scr[i]) *
2221 			  WS_NROWS(sc->sc_scr[i])) / 2);
2222 		sc->sc_scr[i]->cursor = sc->sc_scr[i]->mouse;
2223 		sc->sc_scr[i]->cpy_start = 0;
2224 		sc->sc_scr[i]->cpy_end = 0;
2225 		sc->sc_scr[i]->orig_start = 0;
2226 		sc->sc_scr[i]->orig_end = 0;
2227 		sc->sc_scr[i]->mouse_flags = 0;
2228 	}
2229 	return (0);
2230 }
2231 
2232 void
2233 mouse_moverel(char dx, char dy)
2234 {
2235 	unsigned short old_mouse = MOUSE;
2236 	unsigned char mouse_col = (MOUSE % N_COLS);
2237 	unsigned char mouse_row = (MOUSE / N_COLS);
2238 
2239 	/* wscons has support for screen saver via the WSDISPLAYIO_{G,S}VIDEO
2240 	   with WSDISPLAY_VIDEO_OFF and WSDISPLAY_VIDEO_ON values.
2241 	   However, none of the pc display driver (pcdisplay.c or vga.c)
2242 	   support this ioctl. Only the alpha display driver (tga.c) support it.
2243 
2244 	   When screen saver support is available, /usr/sbin/screenblank can be
2245 	   used with the -m option, so that mice movements stop the screen
2246 	   saver.
2247 	 */
2248 
2249 	/* update position */
2250 
2251 	if (mouse_col + dx >= MAXCOL)
2252 		mouse_col = MAXCOL;
2253 	else {
2254 		if (mouse_col + dx <= 0)
2255 			mouse_col = 0;
2256 		else
2257 			mouse_col += dx;
2258 	}
2259 	if (mouse_row + dy >= MAXROW)
2260 		mouse_row = MAXROW;
2261 	else {
2262 		if (mouse_row + dy <= 0)
2263 			mouse_row = 0;
2264 		else
2265 			mouse_row += dy;
2266 	}
2267 	MOUSE = XY_TO_POS(mouse_col, mouse_row);
2268 	/* if we have moved */
2269 	if (old_mouse != MOUSE) {
2270 		if (IS_SEL_IN_PROGRESS(sc->sc_focus)) {
2271 			/* selection in progress */
2272 			mouse_copy_extend();
2273 		} else {
2274 			inverse_char(MOUSE);
2275 			if (IS_MOUSE_VISIBLE(sc->sc_focus))
2276 				inverse_char(old_mouse);
2277 			else
2278 				MOUSE_FLAGS |= MOUSE_VISIBLE;
2279 		}
2280 	}
2281 }
2282 
2283 void
2284 inverse_char(unsigned short pos)
2285 {
2286 	u_int16_t uc;
2287 	u_int16_t attr;
2288 
2289 	uc = GET_FULLCHAR(pos);
2290 	attr = uc;
2291 
2292 	if ((attr >> 8) == 0)
2293 		attr = (FG_LIGHTGREY << 8);
2294 
2295 	attr = (((attr >> 8) & 0x88) | ((((attr >> 8) >> 4) |
2296 		((attr >> 8) << 4)) & 0x77)) ;
2297 	PUTCHAR(pos, (u_int) (uc & 0x00FF), (long) attr);
2298 }
2299 
2300 void
2301 inverse_region(unsigned short start, unsigned short end)
2302 {
2303 	unsigned short current_pos;
2304 	unsigned short abs_end;
2305 
2306 	/* sanity check, useful because 'end' can be (0 - 1) = 65535 */
2307 	abs_end = N_COLS * N_ROWS;
2308 	if (end > abs_end)
2309 		return;
2310 	current_pos = start;
2311 	while (current_pos <= end)
2312 		inverse_char(current_pos++);
2313 }
2314 
2315 /*
2316  * Return the number of contiguous blank characters between the right margin
2317  * if border == 1 or between the next non-blank character and the current mouse
2318  * cursor if border == 0
2319  */
2320 unsigned char
2321 skip_spc_right(char border)
2322 {
2323 	unsigned short current = CPY_END;
2324 	unsigned short mouse_col = (CPY_END % N_COLS);
2325 	unsigned short limit = current + (N_COLS - mouse_col - 1);
2326 	unsigned char res = 0;
2327 
2328 	while ((GETCHAR(current) == ' ') && (current <= limit)) {
2329 		current++;
2330 		res++;
2331 	}
2332 	if (border == BORDER) {
2333 		if (current > limit)
2334 			return (res - 1);
2335 		else
2336 			return (0);
2337 	} else {
2338 		if (res)
2339 			return (res - 1);
2340 		else
2341 			return (res);
2342 	}
2343 }
2344 
2345 /*
2346  * Return the number of contiguous blank characters between the first of the
2347  * contiguous blank characters and the current mouse cursor
2348  */
2349 unsigned char
2350 skip_spc_left(void)
2351 {
2352 	short current = CPY_START;
2353 	unsigned short mouse_col = (MOUSE % N_COLS);
2354 	unsigned short limit = current - mouse_col;
2355 	unsigned char res = 0;
2356 
2357 	while ((GETCHAR(current) == ' ') && (current >= limit)) {
2358 		current--;
2359 		res++;
2360 	}
2361 	if (res)
2362 		res--;
2363 	return (res);
2364 }
2365 
2366 /*
2367  * Class of characters
2368  * Stolen from xterm sources of the Xfree project (see cvs tag below)
2369  * $TOG: button.c /main/76 1997/07/30 16:56:19 kaleb $
2370  */
2371 static int charClass[256] = {
2372 /* NUL  SOH  STX  ETX  EOT  ENQ  ACK  BEL */
2373     32,   1,   1,   1,   1,   1,   1,   1,
2374 /*  BS   HT   NL   VT   NP   CR   SO   SI */
2375      1,  32,   1,   1,   1,   1,   1,   1,
2376 /* DLE  DC1  DC2  DC3  DC4  NAK  SYN  ETB */
2377      1,   1,   1,   1,   1,   1,   1,   1,
2378 /* CAN   EM  SUB  ESC   FS   GS   RS   US */
2379      1,   1,   1,   1,   1,   1,   1,   1,
2380 /*  SP    !    "    #    $    %    &    ' */
2381     32,  33,  34,  35,  36,  37,  38,  39,
2382 /*   (    )    *    +    ,    -    .    / */
2383     40,  41,  42,  43,  44,  45,  46,  47,
2384 /*   0    1    2    3    4    5    6    7 */
2385     48,  48,  48,  48,  48,  48,  48,  48,
2386 /*   8    9    :    ;    <    =    >    ? */
2387     48,  48,  58,  59,  60,  61,  62,  63,
2388 /*   @    A    B    C    D    E    F    G */
2389     64,  48,  48,  48,  48,  48,  48,  48,
2390 /*   H    I    J    K    L    M    N    O */
2391     48,  48,  48,  48,  48,  48,  48,  48,
2392 /*   P    Q    R    S    T    U    V    W */
2393     48,  48,  48,  48,  48,  48,  48,  48,
2394 /*   X    Y    Z    [    \    ]    ^    _ */
2395     48,  48,  48,  91,  92,  93,  94,  48,
2396 /*   `    a    b    c    d    e    f    g */
2397     96,  48,  48,  48,  48,  48,  48,  48,
2398 /*   h    i    j    k    l    m    n    o */
2399     48,  48,  48,  48,  48,  48,  48,  48,
2400 /*   p    q    r    s    t    u    v    w */
2401     48,  48,  48,  48,  48,  48,  48,  48,
2402 /*   x    y    z    {    |    }    ~  DEL */
2403     48,  48,  48, 123, 124, 125, 126,   1,
2404 /* x80  x81  x82  x83  IND  NEL  SSA  ESA */
2405      1,   1,   1,   1,   1,   1,   1,   1,
2406 /* HTS  HTJ  VTS  PLD  PLU   RI  SS2  SS3 */
2407      1,   1,   1,   1,   1,   1,   1,   1,
2408 /* DCS  PU1  PU2  STS  CCH   MW  SPA  EPA */
2409      1,   1,   1,   1,   1,   1,   1,   1,
2410 /* x98  x99  x9A  CSI   ST  OSC   PM  APC */
2411      1,   1,   1,   1,   1,   1,   1,   1,
2412 /*   -    i   c/    L   ox   Y-    |   So */
2413    160, 161, 162, 163, 164, 165, 166, 167,
2414 /*  ..   c0   ip   <<    _        R0    - */
2415    168, 169, 170, 171, 172, 173, 174, 175,
2416 /*   o   +-    2    3    '    u   q|    . */
2417    176, 177, 178, 179, 180, 181, 182, 183,
2418 /*   ,    1    2   >>  1/4  1/2  3/4    ? */
2419    184, 185, 186, 187, 188, 189, 190, 191,
2420 /*  A`   A'   A^   A~   A:   Ao   AE   C, */
2421     48,  48,  48,  48,  48,  48,  48,  48,
2422 /*  E`   E'   E^   E:   I`   I'   I^   I: */
2423     48,  48,  48,  48,  48,  48,  48,  48,
2424 /*  D-   N~   O`   O'   O^   O~   O:    X */
2425     48,  48,  48,  48,  48,  48,  48, 216,
2426 /*  O/   U`   U'   U^   U:   Y'    P    B */
2427     48,  48,  48,  48,  48,  48,  48,  48,
2428 /*  a`   a'   a^   a~   a:   ao   ae   c, */
2429     48,  48,  48,  48,  48,  48,  48,  48,
2430 /*  e`   e'   e^   e:    i`  i'   i^   i: */
2431     48,  48,  48,  48,  48,  48,  48,  48,
2432 /*   d   n~   o`   o'   o^   o~   o:   -: */
2433     48,  48,  48,  48,  48,  48,  48,  248,
2434 /*  o/   u`   u'   u^   u:   y'    P   y: */
2435     48,  48,  48,  48,  48,  48,  48,  48};
2436 
2437 /*
2438  * Find the first blank beginning after the current cursor position
2439  */
2440 unsigned char
2441 skip_char_right(unsigned short offset)
2442 {
2443 	unsigned short current = offset;
2444 	unsigned short limit = current + (N_COLS - (MOUSE % N_COLS) - 1);
2445 	unsigned char class = charClass[GETCHAR(current)];
2446 	unsigned char res = 0;
2447 
2448 	while ((charClass[GETCHAR(current)] == class)
2449 		&& (current <= limit)) {
2450 		current++;
2451 		res++;
2452 	}
2453 	if (res)
2454 		res--;
2455 	return (res);
2456 }
2457 
2458 /*
2459  * Find the first non-blank character before the cursor position
2460  */
2461 unsigned char
2462 skip_char_left(unsigned short offset)
2463 {
2464 	short current = offset;
2465 	unsigned short limit = current - (MOUSE % N_COLS);
2466 	unsigned char class = charClass[GETCHAR(current)];
2467 	unsigned char res = 0;
2468 
2469 	while ((charClass[GETCHAR(current)] == class) && (current >= limit)) {
2470 		current--;
2471 		res++;
2472 	}
2473 	if (res)
2474 		res--;
2475 	return (res);
2476 }
2477 
2478 /*
2479  * Compare character classes
2480  */
2481 unsigned char
2482 class_cmp(unsigned short first, unsigned short second)
2483 {
2484 	unsigned char first_class;
2485 	unsigned char second_class;
2486 
2487 	first_class = charClass[GETCHAR(first)];
2488 	second_class = charClass[GETCHAR(second)];
2489 
2490 	if (first_class != second_class)
2491 		return (1);
2492 	else
2493 		return (0);
2494 }
2495 
2496 /*
2497  * Beginning of a copy operation
2498  */
2499 void
2500 mouse_copy_start(void)
2501 {
2502 	unsigned char right;
2503 	/* if no selection, then that's the first one */
2504 
2505 	if (!Paste_avail)
2506 		Paste_avail = 1;
2507 
2508 	/* remove the previous selection */
2509 
2510 	if (IS_SEL_EXISTS(sc->sc_focus))
2511 		remove_selection(sc);
2512 
2513 	/* initial show of the cursor */
2514 	if (!IS_MOUSE_VISIBLE(sc->sc_focus))
2515 		inverse_char(MOUSE);
2516 
2517     	CPY_START = MOUSE;
2518 	CPY_END = MOUSE;
2519 	ORIG_START = CPY_START;
2520 	ORIG_END = CPY_END;
2521 	CURSOR = CPY_END + 1; /* init value */
2522 
2523 	right = skip_spc_right(BORDER); /* useful later, in mouse_copy_extend */
2524 	if (right)
2525 		MOUSE_FLAGS |= BLANK_TO_EOL;
2526 
2527 	MOUSE_FLAGS |= SEL_IN_PROGRESS;
2528 	MOUSE_FLAGS |= SEL_EXISTS;
2529 	MOUSE_FLAGS |= SEL_BY_CHAR; /* select by char */
2530 	MOUSE_FLAGS &= ~SEL_BY_WORD;
2531 	MOUSE_FLAGS &= ~SEL_BY_LINE;
2532 	MOUSE_FLAGS &= ~MOUSE_VISIBLE; /* cursor hidden in selection */
2533 }
2534 
2535 /*
2536  * Copy of the word under the cursor
2537  */
2538 void
2539 mouse_copy_word()
2540 {
2541 	unsigned char right;
2542 	unsigned char left;
2543 
2544 	if (IS_SEL_EXISTS(sc->sc_focus))
2545 		remove_selection(sc);
2546 
2547 	if (IS_MOUSE_VISIBLE(sc->sc_focus))
2548 		inverse_char(MOUSE);
2549 
2550 	CPY_START = MOUSE;
2551 	CPY_END = MOUSE;
2552 
2553 	if (IS_ALPHANUM(MOUSE)) {
2554 		right = skip_char_right(CPY_END);
2555 		left = skip_char_left(CPY_START);
2556 	} else {
2557 		right = skip_spc_right(NO_BORDER);
2558 		left = skip_spc_left();
2559 	}
2560 
2561 	CPY_START -= left;
2562 	CPY_END += right;
2563 	ORIG_START = CPY_START;
2564 	ORIG_END = CPY_END;
2565 	CURSOR = CPY_END + 1; /* init value, never happen */
2566 	inverse_region(CPY_START, CPY_END);
2567 
2568 	MOUSE_FLAGS |= SEL_IN_PROGRESS;
2569 	MOUSE_FLAGS |= SEL_EXISTS;
2570 	MOUSE_FLAGS &= ~SEL_BY_CHAR;
2571 	MOUSE_FLAGS |= SEL_BY_WORD;
2572 	MOUSE_FLAGS &= ~SEL_BY_LINE;
2573 
2574 	/* mouse cursor hidden in the selection */
2575 	MOUSE_FLAGS &= ~BLANK_TO_EOL;
2576 	MOUSE_FLAGS &= ~MOUSE_VISIBLE;
2577 }
2578 
2579 /*
2580  * Copy of the current line
2581  */
2582 void
2583 mouse_copy_line(void)
2584 {
2585 	unsigned char row = MOUSE / N_COLS;
2586 
2587 	if (IS_SEL_EXISTS(sc->sc_focus))
2588 		remove_selection(sc);
2589 
2590 	if (IS_MOUSE_VISIBLE(sc->sc_focus))
2591 		inverse_char(MOUSE);
2592 
2593 	CPY_START = row * N_COLS;
2594 	CPY_END = CPY_START + (N_COLS - 1);
2595 	ORIG_START = CPY_START;
2596 	ORIG_END = CPY_END;
2597 	CURSOR = CPY_END + 1;
2598 	inverse_region(CPY_START, CPY_END);
2599 
2600 	MOUSE_FLAGS |= SEL_IN_PROGRESS;
2601 	MOUSE_FLAGS |= SEL_EXISTS;
2602 	MOUSE_FLAGS &= ~SEL_BY_CHAR;
2603 	MOUSE_FLAGS &= ~SEL_BY_WORD;
2604 	MOUSE_FLAGS |= SEL_BY_LINE;
2605 
2606 	/* mouse cursor hidden in the selection */
2607 	MOUSE_FLAGS &= ~BLANK_TO_EOL;
2608 	MOUSE_FLAGS &= ~MOUSE_VISIBLE;
2609 }
2610 
2611 /*
2612  * End of a copy operation
2613  */
2614 void
2615 mouse_copy_end(void)
2616 {
2617 	MOUSE_FLAGS &= ~(SEL_IN_PROGRESS);
2618 	if (IS_SEL_BY_WORD(sc->sc_focus) || IS_SEL_BY_LINE(sc->sc_focus)) {
2619 		if (CURSOR != (CPY_END + 1))
2620 			inverse_char(CURSOR);
2621 		CURSOR = CPY_END + 1;
2622 	}
2623 }
2624 
2625 
2626 /*
2627  * Generic selection extend function
2628  */
2629 void
2630 mouse_copy_extend(void)
2631 {
2632 	if (IS_SEL_BY_CHAR(sc->sc_focus))
2633 		mouse_copy_extend_char();
2634 	if (IS_SEL_BY_WORD(sc->sc_focus))
2635 		mouse_copy_extend_word();
2636 	if (IS_SEL_BY_LINE(sc->sc_focus))
2637 		mouse_copy_extend_line();
2638 }
2639 
2640 /*
2641  * Extend a selected region, character by character
2642  */
2643 void
2644 mouse_copy_extend_char()
2645 {
2646 	unsigned char right;
2647 
2648 	if (!IS_SEL_EXT_AFTER(sc->sc_focus)) {
2649 
2650 		if (IS_BLANK_TO_EOL(sc->sc_focus)) {
2651 			/*
2652 			 * First extension of selection. We handle special
2653 			 * cases of blank characters to eol
2654 			 */
2655 
2656 			right = skip_spc_right(BORDER);
2657 			if (MOUSE > ORIG_START) {
2658 				/* the selection goes to the lower part of
2659 				   the screen */
2660 
2661 				/* remove the previous cursor, start of
2662 				   selection is now next line */
2663 				inverse_char(CPY_START);
2664 				CPY_START += (right + 1);
2665 				CPY_END = CPY_START;
2666 				ORIG_START = CPY_START;
2667 				/* simulate the initial mark */
2668 				inverse_char(CPY_START);
2669 			} else {
2670 				/* the selection goes to the upper part
2671 				   of the screen */
2672 				/* remove the previous cursor, start of
2673 				   selection is now at the eol */
2674 				inverse_char(CPY_START);
2675 				ORIG_START += (right + 1);
2676 				CPY_START = ORIG_START - 1;
2677 				CPY_END = ORIG_START - 1;
2678 				/* simulate the initial mark */
2679 				inverse_char(CPY_START);
2680 			}
2681 			MOUSE_FLAGS &= ~ BLANK_TO_EOL;
2682 		}
2683 
2684 		if (MOUSE < ORIG_START && CPY_END >= ORIG_START) {
2685 			/* we go to the upper part of the screen */
2686 
2687 			/* reverse the old selection region */
2688 			remove_selection(sc);
2689 			CPY_END = ORIG_START - 1;
2690 			CPY_START = ORIG_START;
2691 		}
2692 		if (CPY_START < ORIG_START && MOUSE >= ORIG_START) {
2693 			/* we go to the lower part of the screen */
2694 
2695 			/* reverse the old selection region */
2696 
2697 			remove_selection(sc);
2698 			CPY_START = ORIG_START;
2699 			CPY_END = ORIG_START - 1;
2700 		}
2701 		/* restore flags cleared in remove_selection() */
2702 		MOUSE_FLAGS |= SEL_IN_PROGRESS;
2703 		MOUSE_FLAGS |= SEL_EXISTS;
2704 	}
2705 	/* beginning of common part */
2706 
2707 	if (MOUSE >= ORIG_START) {
2708 
2709 		/* lower part of the screen */
2710 		if (MOUSE > CPY_END) {
2711 			/* extending selection */
2712 			inverse_region(CPY_END + 1, MOUSE);
2713 		} else {
2714 			/* reducing selection */
2715 			inverse_region(MOUSE + 1, CPY_END);
2716 		}
2717 		CPY_END = MOUSE;
2718 	} else {
2719 		/* upper part of the screen */
2720 		if (MOUSE < CPY_START) {
2721 			/* extending selection */
2722 			inverse_region(MOUSE,CPY_START - 1);
2723 		} else {
2724 			/* reducing selection */
2725 			inverse_region(CPY_START,MOUSE - 1);
2726 		}
2727 		CPY_START = MOUSE;
2728 	}
2729 	/* end of common part */
2730 }
2731 
2732 /*
2733  * Extend a selected region, word by word
2734  */
2735 void
2736 mouse_copy_extend_word(void)
2737 {
2738 	unsigned short old_cpy_end;
2739 	unsigned short old_cpy_start;
2740 
2741 	if (!IS_SEL_EXT_AFTER(sc->sc_focus)) {
2742 
2743 		/* remove cursor in selection (black one) */
2744 
2745 		if (CURSOR != (CPY_END + 1))
2746 			inverse_char(CURSOR);
2747 
2748 		/* now, switch between lower and upper part of the screen */
2749 
2750 		if (MOUSE < ORIG_START && CPY_END >= ORIG_START) {
2751 			/* going to the upper part of the screen */
2752 			inverse_region(ORIG_END + 1, CPY_END);
2753 			CPY_END = ORIG_END;
2754 		}
2755 
2756 		if (MOUSE > ORIG_END && CPY_START <= ORIG_START) {
2757 			/* going to the lower part of the screen */
2758 			inverse_region(CPY_START, ORIG_START - 1);
2759 			CPY_START = ORIG_START;
2760 		}
2761 	}
2762 
2763 	if (MOUSE >= ORIG_START) {
2764 		/* lower part of the screen */
2765 
2766 		if (MOUSE > CPY_END) {
2767 			/* extending selection */
2768 
2769 			old_cpy_end = CPY_END;
2770 			CPY_END = MOUSE + skip_char_right(MOUSE);
2771 			inverse_region(old_cpy_end + 1, CPY_END);
2772 		} else {
2773 			if (class_cmp(MOUSE, MOUSE + 1)) {
2774 				/* reducing selection (remove last word) */
2775 				old_cpy_end = CPY_END;
2776 				CPY_END = MOUSE;
2777 				inverse_region(CPY_END + 1, old_cpy_end);
2778 			} else {
2779 				old_cpy_end = CPY_END;
2780 				CPY_END = MOUSE + skip_char_right(MOUSE);
2781 			       	if (CPY_END != old_cpy_end) {
2782 					/* reducing selection, from the end of
2783 					 * next word */
2784 					inverse_region(CPY_END + 1,
2785 					    old_cpy_end);
2786 				}
2787 			}
2788 		}
2789 	} else {
2790 		/* upper part of the screen */
2791 		if (MOUSE < CPY_START) {
2792 			/* extending selection */
2793 			old_cpy_start = CPY_START;
2794 			CPY_START = MOUSE - skip_char_left(MOUSE);
2795 			inverse_region(CPY_START, old_cpy_start - 1);
2796 		} else {
2797 			if (class_cmp(MOUSE - 1, MOUSE)) {
2798 				/* reducing selection (remove last word) */
2799 				old_cpy_start = CPY_START;
2800 				CPY_START = MOUSE;
2801 				inverse_region(old_cpy_start,
2802 				    CPY_START - 1);
2803 			} else {
2804 				old_cpy_start = CPY_START;
2805 				CPY_START = MOUSE - skip_char_left(MOUSE);
2806 				if (CPY_START != old_cpy_start) {
2807 					inverse_region(old_cpy_start,
2808 					    CPY_START - 1);
2809 				}
2810 			}
2811 		}
2812 	}
2813 
2814 	if (!IS_SEL_EXT_AFTER(sc->sc_focus)) {
2815 		/* display new cursor */
2816 		CURSOR = MOUSE;
2817 		inverse_char(CURSOR);
2818 	}
2819 }
2820 
2821 /*
2822  * Extend a selected region, line by line
2823  */
2824 void
2825 mouse_copy_extend_line(void)
2826 {
2827 	unsigned short old_row;
2828 	unsigned short new_row;
2829 	unsigned short old_cpy_start;
2830 	unsigned short old_cpy_end;
2831 
2832 	if (!IS_SEL_EXT_AFTER(sc->sc_focus)) {
2833 		/* remove cursor in selection (black one) */
2834 
2835 		if (CURSOR != (CPY_END + 1))
2836 			inverse_char(CURSOR);
2837 
2838 		/* now, switch between lower and upper part of the screen */
2839 
2840 		if (MOUSE < ORIG_START && CPY_END >= ORIG_START) {
2841 			/* going to the upper part of the screen */
2842 			inverse_region(ORIG_END + 1, CPY_END);
2843 			CPY_END = ORIG_END;
2844 		}
2845 
2846 		if (MOUSE > ORIG_END && CPY_START <= ORIG_START) {
2847 			/* going to the lower part of the screen */
2848 			inverse_region(CPY_START, ORIG_START - 1);
2849 			CPY_START = ORIG_START;
2850 		}
2851 	}
2852 
2853 	if (MOUSE >= ORIG_START) {
2854 		/* lower part of the screen */
2855 		if (CURSOR == (CPY_END + 1))
2856 			CURSOR = CPY_END;
2857 		old_row = CURSOR / N_COLS;
2858 		new_row = MOUSE / N_COLS;
2859 		old_cpy_end = CPY_END;
2860 		CPY_END = (new_row * N_COLS) + MAXCOL;
2861 		if (new_row > old_row)
2862 			inverse_region(old_cpy_end + 1, CPY_END);
2863 		else if (new_row < old_row)
2864 			inverse_region(CPY_END + 1, old_cpy_end);
2865 	} else {
2866 		/* upper part of the screen */
2867 		old_row = CURSOR / N_COLS;
2868 		new_row = MOUSE / N_COLS;
2869 		old_cpy_start = CPY_START;
2870 		CPY_START = new_row * N_COLS;
2871 		if (new_row < old_row)
2872 			inverse_region(CPY_START, old_cpy_start - 1);
2873 		else if (new_row > old_row)
2874 			inverse_region(old_cpy_start, CPY_START - 1);
2875 	}
2876 
2877 	if (!IS_SEL_EXT_AFTER(sc->sc_focus)) {
2878 		/* display new cursor */
2879 		CURSOR = MOUSE;
2880 		inverse_char(CURSOR);
2881 	}
2882 }
2883 
2884 void
2885 mouse_hide(struct wsdisplay_softc *sc)
2886 {
2887 	if (IS_MOUSE_VISIBLE(sc->sc_focus)) {
2888 		inverse_char(MOUSE);
2889 		MOUSE_FLAGS &= ~MOUSE_VISIBLE;
2890 	}
2891 }
2892 
2893 /*
2894  * Add an extension to a selected region, word by word
2895  */
2896 void
2897 mouse_copy_extend_after(void)
2898 {
2899 	unsigned short start_dist;
2900 	unsigned short end_dist;
2901 
2902 	if (IS_SEL_EXISTS(sc->sc_focus)) {
2903 		MOUSE_FLAGS |= SEL_EXT_AFTER;
2904 		mouse_hide(sc); /* hide current cursor */
2905 
2906 		if (CPY_START > MOUSE)
2907 			start_dist = CPY_START - MOUSE;
2908 		else
2909 			start_dist = MOUSE - CPY_START;
2910 		if (MOUSE > CPY_END)
2911 			end_dist = MOUSE - CPY_END;
2912 		else
2913 			end_dist = CPY_END - MOUSE;
2914 		if (start_dist < end_dist) {
2915 			/* upper part of the screen*/
2916 			ORIG_START = MOUSE + 1;
2917 			/* only used in mouse_copy_extend_line() */
2918 			CURSOR = CPY_START;
2919 		} else {
2920 			/* lower part of the screen */
2921 			ORIG_START = MOUSE;
2922 			/* only used in mouse_copy_extend_line() */
2923 			CURSOR = CPY_END;
2924 		}
2925 		if (IS_SEL_BY_CHAR(sc->sc_focus))
2926 			mouse_copy_extend_char();
2927 		if (IS_SEL_BY_WORD(sc->sc_focus))
2928 			mouse_copy_extend_word();
2929 		if (IS_SEL_BY_LINE(sc->sc_focus))
2930 			mouse_copy_extend_line();
2931 		mouse_copy_selection();
2932 	}
2933 }
2934 
2935 /*
2936  * Remove a previously selected region
2937  */
2938 void
2939 remove_selection(struct wsdisplay_softc *sc)
2940 {
2941 	if (IS_SEL_EXT_AFTER(sc->sc_focus)) {
2942 		/* reset the flag indicating an extension of selection */
2943 		MOUSE_FLAGS &= ~SEL_EXT_AFTER;
2944 	}
2945 	inverse_region(CPY_START, CPY_END);
2946 	MOUSE_FLAGS &= ~SEL_IN_PROGRESS;
2947 	MOUSE_FLAGS &= ~SEL_EXISTS;
2948 }
2949 
2950 /*
2951  * Put the current visual selection in the selection buffer
2952  */
2953 void
2954 mouse_copy_selection(void)
2955 {
2956 	unsigned short current = 0;
2957 	unsigned short blank = current;
2958 	unsigned short buf_end = ((N_COLS + 1) * N_ROWS);
2959 	unsigned short sel_cur;
2960 	unsigned short sel_end;
2961 
2962 	sel_cur = CPY_START;
2963 	sel_end = CPY_END;
2964 
2965 	while (sel_cur <= sel_end && current < buf_end - 1) {
2966 		Copybuffer[current] = (GETCHAR(sel_cur));
2967 		if (!IS_SPACE(Copybuffer[current]))
2968 			blank = current + 1; /* first blank after non-blank */
2969 		current++;
2970 		if (POS_TO_X(sel_cur) == MAXCOL) {
2971 			/* we are on the last col of the screen */
2972 			Copybuffer[blank] = '\r'; /* carriage return */
2973 			current = blank + 1; /* restart just after the carriage
2974 					       return in the buffer */
2975 			blank = current;
2976 		}
2977 		sel_cur++;
2978 	}
2979 
2980 	Copybuffer[current] = '\0';
2981 }
2982 
2983 /*
2984  * Paste the current selection
2985  */
2986 void
2987 mouse_paste(void)
2988 {
2989 	unsigned short len;
2990 	unsigned char *current = Copybuffer;
2991 
2992 	if (Paste_avail) {
2993 		for (len = strlen(Copybuffer) ; len > 0; len--) {
2994 			(*linesw[sc->sc_focus->scr_tty->t_line].l_rint)
2995 			    (*current++, sc->sc_focus->scr_tty);
2996 		}
2997 	}
2998 }
2999 
3000 /*
3001  * Handle the z axis.
3002  * The z axis (roller or wheel) is mapped by default to scrollback.
3003  */
3004 void
3005 mouse_zaxis(int z)
3006 {
3007 	if (z < 0)
3008 		wsscrollback(sc, WSDISPLAY_SCROLL_BACKWARD);
3009 	else
3010 		wsscrollback(sc, WSDISPLAY_SCROLL_FORWARD);
3011 }
3012 
3013 /*
3014  * Allocate the copy buffer. The size is:
3015  * (cols + 1) * (rows)
3016  * (+1 for '\n' at the end of lines),
3017  * where cols and rows are the maximum of column and rows of all screens.
3018  */
3019 void
3020 allocate_copybuffer(struct wsdisplay_softc *sc)
3021 {
3022 	int nscreens = sc->sc_scrdata->nscreens;
3023 	int i,s;
3024 	const struct wsscreen_descr **screens_list = sc->sc_scrdata->screens;
3025 	const struct wsscreen_descr *current;
3026 	unsigned short size = Copybuffer_size;
3027 
3028 	s = spltty();
3029 	for (i = 0; i < nscreens; i++) {
3030 		current = *screens_list;
3031 		if (( (current->ncols + 1) * current->nrows) > size)
3032 			size = ((current->ncols + 1) * current->nrows);
3033 			screens_list++;
3034 	}
3035 	if ((size != Copybuffer_size) && (Copybuffer_size != 0)) {
3036 		bzero(Copybuffer, Copybuffer_size);
3037 		free(Copybuffer, M_DEVBUF);
3038 	}
3039 	if ((Copybuffer = (char *)malloc(size, M_DEVBUF, M_NOWAIT)) == NULL) {
3040 		printf("wscons: copybuffer memory malloc failed\n");
3041 		Copybuffer_size = 0;
3042 	}
3043 	Copybuffer_size = size;
3044 	splx(s);
3045 }
3046