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