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