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