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