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