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