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