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