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