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