wsdisplay.c revision 1.17 1 /* $NetBSD: wsdisplay.c,v 1.17 1999/01/18 20:03:59 drochner Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christopher G. Demetriou
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 static const char _copyright[] __attribute__ ((unused)) =
34 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.";
35 static const char _rcsid[] __attribute__ ((unused)) =
36 "$NetBSD: wsdisplay.c,v 1.17 1999/01/18 20:03:59 drochner Exp $";
37
38 #include <sys/param.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 #include <sys/ioctl.h>
42 #include <sys/kernel.h>
43 #include <sys/proc.h>
44 #include <sys/malloc.h>
45 #include <sys/syslog.h>
46 #include <sys/systm.h>
47 #include <sys/tty.h>
48 #include <sys/signalvar.h>
49 #include <sys/errno.h>
50 #include <sys/fcntl.h>
51 #include <sys/vnode.h>
52
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wscons/wsdisplayvar.h>
55 #include <dev/wscons/wsksymvar.h>
56 #include <dev/wscons/wsksymdef.h>
57 #include <dev/wscons/wsemulvar.h>
58 #include <dev/wscons/wscons_callbacks.h>
59 #include <dev/cons.h>
60
61 #include "opt_wsdisplay_compat.h"
62
63 #include "wsdisplay.h"
64
65 struct wsscreen_internal {
66 const struct wsdisplay_emulops *emulops;
67 void *emulcookie;
68
69 const struct wsscreen_descr *scrdata;
70
71 const struct wsemul_ops *wsemul;
72 void *wsemulcookie;
73 };
74
75 struct wsscreen {
76 struct wsscreen_internal *scr_dconf;
77
78 struct tty *scr_tty;
79 int scr_hold_screen; /* hold tty output */
80
81 int scr_flags;
82 #define SCR_OPEN 1 /* is it open? */
83 #define SCR_WAITACTIVE 2 /* someone waiting on activation */
84 #define SCR_GRAPHICS 4 /* graphics mode, no text (emulation) output */
85 const struct wscons_syncops *scr_syncops;
86 void *scr_synccookie;
87
88 #ifdef WSDISPLAY_COMPAT_RAWKBD
89 int scr_rawkbd;
90 #endif
91
92 struct wsdisplay_softc *sc;
93 };
94
95 struct wsscreen *wsscreen_attach __P((struct wsdisplay_softc *, int,
96 const char *,
97 const struct wsscreen_descr *, void *,
98 int, int, long));
99 void wsscreen_detach __P((struct wsscreen *));
100 static const struct wsscreen_descr *
101 wsdisplay_screentype_pick __P((const struct wsscreen_list *, char *));
102 int wsdisplay_addscreen __P((struct wsdisplay_softc *, int, char *, char *));
103 static void wsdisplay_closescreen __P((struct wsdisplay_softc *,
104 struct wsscreen *));
105 int wsdisplay_delscreen __P((struct wsdisplay_softc *, int, int));
106
107 #define WSDISPLAY_MAXSCREEN 8
108
109 struct wsdisplay_softc {
110 struct device sc_dv;
111
112 const struct wsdisplay_accessops *sc_accessops;
113 void *sc_accesscookie;
114
115 const struct wsscreen_list *sc_scrdata;
116
117 struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
118 int sc_focusidx;
119 struct wsscreen *sc_focus;
120
121 int sc_isconsole;
122 struct device *sc_kbddv;
123
124 int sc_flags;
125 #define SC_SWITCHPENDING 1
126 int sc_screenwanted; /* valid with SC_SWITCHPENDING */
127
128 #ifdef WSDISPLAY_COMPAT_RAWKBD
129 int sc_rawkbd;
130 #endif
131 };
132
133 #if NWSDISPLAY > 0
134 extern struct cfdriver wsdisplay_cd;
135 #endif /* NWSDISPLAY > 0 */
136
137 /* Autoconfiguration definitions. */
138 static int wsdisplay_emul_match __P((struct device *, struct cfdata *,
139 void *));
140 static void wsdisplay_emul_attach __P((struct device *, struct device *,
141 void *));
142 static int wsdisplay_noemul_match __P((struct device *, struct cfdata *,
143 void *));
144 static void wsdisplay_noemul_attach __P((struct device *, struct device *,
145 void *));
146
147 struct cfattach wsdisplay_emul_ca = {
148 sizeof (struct wsdisplay_softc),
149 wsdisplay_emul_match,
150 wsdisplay_emul_attach,
151 };
152
153 struct cfattach wsdisplay_noemul_ca = {
154 sizeof (struct wsdisplay_softc),
155 wsdisplay_noemul_match,
156 wsdisplay_noemul_attach,
157 };
158
159 /* Exported tty- and cdevsw-related functions. */
160 cdev_decl(wsdisplay);
161
162 #if NWSDISPLAY > 0
163 static void wsdisplaystart __P((struct tty *));
164 static int wsdisplayparam __P((struct tty *, struct termios *));
165 #endif /* NWSDISPLAY > 0 */
166
167
168 /* Internal macros, functions, and variables. */
169 #define SET(t, f) (t) |= (f)
170 #define CLR(t, f) (t) &= ~(f)
171 #define ISSET(t, f) ((t) & (f))
172
173 #define WSDISPLAYUNIT(dev) (minor(dev) >> 8)
174 #define WSDISPLAYSCREEN(dev) (minor(dev) & 0xff)
175 #define ISWSDISPLAYCTL(dev) (WSDISPLAYSCREEN(dev) == 255)
176 #define WSDISPLAYMINOR(unit, screen) (((unit) << 8) | (screen))
177 #define WSDISPLAYBURST (OBUFSIZ - 1)
178
179 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL)
180 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL)
181
182 static void wsdisplay_common_attach __P((struct wsdisplay_softc *sc,
183 int console, const struct wsscreen_list *,
184 const struct wsdisplay_accessops *accessops,
185 void *accesscookie));
186
187 #ifdef WSDISPLAY_COMPAT_RAWKBD
188 int wsdisplay_update_rawkbd __P((struct wsdisplay_softc *,
189 struct wsscreen *));
190 #endif
191
192 static int wsdisplay_console_initted;
193 static struct wsdisplay_softc *wsdisplay_console_device;
194 static struct wsscreen_internal wsdisplay_console_conf;
195
196 static int wsdisplay_getc_dummy __P((dev_t));
197 static void wsdisplay_pollc_dummy __P((dev_t, int));
198
199 static struct consdev wsdisplay_cons = {
200 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
201 wsdisplay_pollc_dummy, NODEV, CN_NORMAL
202 };
203
204 int wsdisplay_switch1 __P((void *, int));
205
206 int wsdisplay_clearonclose;
207
208 struct wsscreen *
209 wsscreen_attach(sc, console, emul, type, cookie, ccol, crow, defattr)
210 struct wsdisplay_softc *sc;
211 int console;
212 const char *emul;
213 const struct wsscreen_descr *type;
214 void *cookie;
215 int ccol, crow;
216 long defattr;
217 {
218 struct wsscreen_internal *dconf;
219 struct wsscreen *scr;
220
221 scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK);
222 if (!scr)
223 return (NULL);
224
225 if (console) {
226 dconf = &wsdisplay_console_conf;
227 /*
228 * If there's an emulation, tell it about the callback argument.
229 * The other stuff is already there.
230 */
231 if (dconf->wsemul != NULL)
232 (*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr, 0);
233 } else { /* not console */
234 dconf = malloc(sizeof(struct wsscreen_internal),
235 M_DEVBUF, M_NOWAIT);
236 dconf->emulops = type->textops;
237 dconf->emulcookie = cookie;
238 if (dconf->emulops) {
239 dconf->wsemul = wsemul_pick(emul);
240 if (dconf->wsemul == NULL) {
241 free(dconf, M_DEVBUF);
242 free(scr, M_DEVBUF);
243 return (NULL);
244 }
245 dconf->wsemulcookie =
246 (*dconf->wsemul->attach)(0, type, cookie,
247 ccol, crow, scr, defattr);
248 } else
249 dconf->wsemul = NULL;
250 dconf->scrdata = type;
251 }
252
253 scr->scr_dconf = dconf;
254
255 scr->scr_tty = ttymalloc();
256 tty_attach(scr->scr_tty);
257 scr->scr_hold_screen = 0;
258 if (WSSCREEN_HAS_EMULATOR(scr))
259 scr->scr_flags = 0;
260 else
261 scr->scr_flags = SCR_GRAPHICS;
262
263 scr->scr_syncops = 0;
264 scr->sc = sc;
265 #ifdef WSDISPLAY_COMPAT_RAWKBD
266 scr->scr_rawkbd = 0;
267 #endif
268 return (scr);
269 }
270
271 void
272 wsscreen_detach(scr)
273 struct wsscreen *scr;
274 {
275 int ccol, crow; /* XXX */
276
277 if (WSSCREEN_HAS_TTY(scr)) {
278 tty_detach(scr->scr_tty);
279 ttyfree(scr->scr_tty);
280 }
281 if (WSSCREEN_HAS_EMULATOR(scr))
282 (*scr->scr_dconf->wsemul->detach)(scr->scr_dconf->wsemulcookie,
283 &ccol, &crow);
284 free(scr->scr_dconf, M_DEVBUF);
285 free(scr, M_DEVBUF);
286 }
287
288 static const struct wsscreen_descr *
289 wsdisplay_screentype_pick(scrdata, name)
290 const struct wsscreen_list *scrdata;
291 char *name;
292 {
293 int i;
294 const struct wsscreen_descr *scr;
295
296 KASSERT(scrdata->nscreens > 0);
297
298 if (name == NULL)
299 return (scrdata->screens[0]);
300
301 for (i = 0; i < scrdata->nscreens; i++) {
302 scr = scrdata->screens[i];
303 if (!strcmp(name, scr->name))
304 return (scr);
305 }
306
307 return (0);
308 }
309
310 int
311 wsdisplay_addscreen(sc, idx, screentype, emul)
312 struct wsdisplay_softc *sc;
313 int idx;
314 char *screentype, *emul;
315 {
316 const struct wsscreen_descr *scrdesc;
317 int error;
318 void *cookie;
319 int ccol, crow;
320 long defattr;
321 struct wsscreen *scr;
322
323 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
324 return (EINVAL);
325 if (sc->sc_scr[idx] != NULL)
326 return (EBUSY);
327
328 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype);
329 if (!scrdesc)
330 return (ENXIO);
331 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie,
332 scrdesc, &cookie, &ccol, &crow, &defattr);
333 if (error)
334 return (error);
335
336 scr = wsscreen_attach(sc, 0, emul, scrdesc,
337 cookie, ccol, crow, defattr);
338 if (scr == NULL) {
339 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
340 cookie);
341 return (ENXIO);
342 }
343
344 sc->sc_scr[idx] = scr;
345
346 printf("%s: screen %d added (%s", sc->sc_dv.dv_xname, idx,
347 scrdesc->name);
348 if (WSSCREEN_HAS_EMULATOR(scr))
349 printf(", %s emulation", scr->scr_dconf->wsemul->name);
350 printf(")\n");
351 return (0);
352 }
353
354 static void
355 wsdisplay_closescreen(sc, scr)
356 struct wsdisplay_softc *sc;
357 struct wsscreen *scr;
358 {
359 int maj, mn, idx;
360
361 /* hangup */
362 if (WSSCREEN_HAS_TTY(scr)) {
363 struct tty *tp = scr->scr_tty;
364 (*linesw[tp->t_line].l_modem)(tp, 0);
365 }
366
367 /* locate the major number */
368 for (maj = 0; maj < nchrdev; maj++)
369 if (cdevsw[maj].d_open == wsdisplayopen)
370 break;
371 /* locate the screen index */
372 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++)
373 if (scr == sc->sc_scr[idx])
374 break;
375 #ifdef DIAGNOSTIC
376 if (idx == WSDISPLAY_MAXSCREEN)
377 panic("wsdisplay_forceclose: bad screen");
378 #endif
379
380 /* nuke the vnodes */
381 mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx);
382 vdevgone(maj, mn, mn, VCHR);
383 }
384
385 int
386 wsdisplay_delscreen(sc, idx, flags)
387 struct wsdisplay_softc *sc;
388 int idx, flags;
389 {
390 struct wsscreen *scr;
391 int s;
392 void *cookie;
393
394 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
395 return (EINVAL);
396 scr = sc->sc_scr[idx];
397 if (!scr)
398 return (ENXIO);
399
400 if (scr->scr_dconf == &wsdisplay_console_conf ||
401 scr->scr_syncops ||
402 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE)))
403 return(EBUSY);
404
405 wsdisplay_closescreen(sc, scr);
406
407 /*
408 * delete pointers, so neither device entries
409 * nor keyboard input can reference it anymore
410 */
411 s = spltty();
412 if (sc->sc_focus == scr)
413 sc->sc_focus = 0;
414 sc->sc_scr[idx] = 0;
415 splx(s);
416
417 /*
418 * Wake up processes waiting for the screen to
419 * be activated. Sleepers must check whether
420 * the screen still exists.
421 */
422 if (scr->scr_flags & SCR_WAITACTIVE)
423 wakeup(scr);
424
425 /* save a reference to the graphics screen */
426 cookie = scr->scr_dconf->emulcookie;
427
428 wsscreen_detach(scr);
429
430 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
431 cookie);
432
433 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx);
434 return (0);
435 }
436
437 /*
438 * Autoconfiguration functions.
439 */
440 int
441 wsdisplay_emul_match(parent, match, aux)
442 struct device *parent;
443 struct cfdata *match;
444 void *aux;
445 {
446 struct wsemuldisplaydev_attach_args *ap = aux;
447
448 if (match->wsemuldisplaydevcf_console !=
449 WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
450 /*
451 * If console-ness of device specified, either match
452 * exactly (at high priority), or fail.
453 */
454 if (match->wsemuldisplaydevcf_console != 0 &&
455 ap->console != 0)
456 return (10);
457 else
458 return (0);
459 }
460
461 /* If console-ness unspecified, it wins. */
462 return (1);
463 }
464
465 void
466 wsdisplay_emul_attach(parent, self, aux)
467 struct device *parent, *self;
468 void *aux;
469 {
470 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
471 struct wsemuldisplaydev_attach_args *ap = aux;
472
473 wsdisplay_common_attach(sc, ap->console, ap->scrdata,
474 ap->accessops, ap->accesscookie);
475
476 if (ap->console) {
477 int maj;
478
479 /* locate the major number */
480 for (maj = 0; maj < nchrdev; maj++)
481 if (cdevsw[maj].d_open == wsdisplayopen)
482 break;
483
484 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0));
485 }
486 }
487
488 /* Print function (for parent devices). */
489 int
490 wsemuldisplaydevprint(aux, pnp)
491 void *aux;
492 const char *pnp;
493 {
494 #if 0 /* -Wunused */
495 struct wsemuldisplaydev_attach_args *ap = aux;
496 #endif
497
498 if (pnp)
499 printf("wsdisplay at %s", pnp);
500 #if 0 /* don't bother; it's ugly */
501 printf(" console %d", ap->console);
502 #endif
503
504 return (UNCONF);
505 }
506
507 int
508 wsdisplay_noemul_match(parent, match, aux)
509 struct device *parent;
510 struct cfdata *match;
511 void *aux;
512 {
513 #if 0 /* -Wunused */
514 struct wsdisplaydev_attach_args *ap = aux;
515 #endif
516
517 /* Always match. */
518 return (1);
519 }
520
521 void
522 wsdisplay_noemul_attach(parent, self, aux)
523 struct device *parent, *self;
524 void *aux;
525 {
526 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
527 struct wsdisplaydev_attach_args *ap = aux;
528
529 wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie);
530 }
531
532 /* Print function (for parent devices). */
533 int
534 wsdisplaydevprint(aux, pnp)
535 void *aux;
536 const char *pnp;
537 {
538 #if 0 /* -Wunused */
539 struct wsdisplaydev_attach_args *ap = aux;
540 #endif
541
542 if (pnp)
543 printf("wsdisplay at %s", pnp);
544
545 return (UNCONF);
546 }
547
548 static void
549 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie)
550 struct wsdisplay_softc *sc;
551 int console;
552 const struct wsscreen_list *scrdata;
553 const struct wsdisplay_accessops *accessops;
554 void *accesscookie;
555 {
556 int i = 0;
557
558 if (console) {
559 KASSERT(wsdisplay_console_initted);
560 KASSERT(wsdisplay_console_device == NULL);
561
562 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
563 wsdisplay_console_device = sc;
564
565 printf(": console (%s, %s emulation)",
566 wsdisplay_console_conf.scrdata->name,
567 wsdisplay_console_conf.wsemul->name);
568
569 sc->sc_focusidx = 0;
570 sc->sc_focus = sc->sc_scr[0];
571 i++;
572 }
573
574 printf("\n");
575
576 sc->sc_accessops = accessops;
577 sc->sc_accesscookie = accesscookie;
578 sc->sc_scrdata = scrdata;
579
580 sc->sc_isconsole = console;
581 sc->sc_kbddv = NULL;
582
583 wscons_glue_set_callback();
584
585 /*
586 * Set up a number of virtual screens if possible. The
587 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
588 * should go away as soon as we have a userspace utility.
589 */
590 #ifndef WSDISPLAY_DEFAULTSCREENS
591 #define WSDISPLAY_DEFAULTSCREENS WSDISPLAY_MAXSCREEN
592 #endif
593 for (; i < WSDISPLAY_DEFAULTSCREENS; i++)
594 if (wsdisplay_addscreen(sc, i, 0, 0))
595 break;
596 }
597
598 void
599 wsdisplay_cnattach(type, cookie, ccol, crow, defattr)
600 const struct wsscreen_descr *type;
601 void *cookie;
602 int ccol, crow;
603 long defattr;
604 {
605 const struct wsemul_ops *wsemul;
606
607 KASSERT(!wsdisplay_console_initted);
608 KASSERT(type->nrows > 0);
609 KASSERT(type->ncols > 0);
610 KASSERT(crow < type->nrows);
611 KASSERT(ccol < type->ncols);
612
613 wsdisplay_console_conf.emulops = type->textops;
614 wsdisplay_console_conf.emulcookie = cookie;
615 wsdisplay_console_conf.scrdata = type;
616
617 wsemul = wsemul_pick(0); /* default */
618 wsdisplay_console_conf.wsemul = wsemul;
619 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
620 ccol, crow,
621 defattr);
622
623 cn_tab = &wsdisplay_cons;
624
625 wsdisplay_console_initted = 1;
626 }
627
628 /*
629 * Tty and cdevsw functions.
630 */
631 int
632 wsdisplayopen(dev, flag, mode, p)
633 dev_t dev;
634 int flag, mode;
635 struct proc *p;
636 {
637 #if NWSDISPLAY > 0
638 struct wsdisplay_softc *sc;
639 struct tty *tp;
640 int unit, newopen, error;
641 struct wsscreen *scr;
642
643 unit = WSDISPLAYUNIT(dev);
644 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
645 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
646 return (ENXIO);
647
648 if (ISWSDISPLAYCTL(dev))
649 return (0);
650
651 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
652 return (ENXIO);
653 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
654 if (!scr)
655 return (ENXIO);
656
657 if (WSSCREEN_HAS_TTY(scr)) {
658 tp = scr->scr_tty;
659 tp->t_oproc = wsdisplaystart;
660 tp->t_param = wsdisplayparam;
661 tp->t_dev = dev;
662 newopen = (tp->t_state & TS_ISOPEN) == 0;
663 if (newopen) {
664 ttychars(tp);
665 tp->t_iflag = TTYDEF_IFLAG;
666 tp->t_oflag = TTYDEF_OFLAG;
667 tp->t_cflag = TTYDEF_CFLAG;
668 tp->t_lflag = TTYDEF_LFLAG;
669 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
670 wsdisplayparam(tp, &tp->t_termios);
671 ttsetwater(tp);
672 } else if ((tp->t_state & TS_XCLUDE) != 0 &&
673 p->p_ucred->cr_uid != 0)
674 return EBUSY;
675 tp->t_state |= TS_CARR_ON;
676
677 error = ((*linesw[tp->t_line].l_open)(dev, tp));
678 if (error)
679 return (error);
680
681 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
682 /* set window sizes as appropriate, and reset
683 the emulation */
684 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
685 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
686
687 /* wsdisplay_set_emulation() */
688 }
689 }
690
691 scr->scr_flags |= SCR_OPEN;
692 return (0);
693 #else
694 return (ENXIO);
695 #endif /* NWSDISPLAY > 0 */
696 }
697
698 int
699 wsdisplayclose(dev, flag, mode, p)
700 dev_t dev;
701 int flag, mode;
702 struct proc *p;
703 {
704 #if NWSDISPLAY > 0
705 struct wsdisplay_softc *sc;
706 struct tty *tp;
707 int unit;
708 struct wsscreen *scr;
709
710 unit = WSDISPLAYUNIT(dev);
711 sc = wsdisplay_cd.cd_devs[unit];
712
713 if (ISWSDISPLAYCTL(dev))
714 return (0);
715
716 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
717
718 if (WSSCREEN_HAS_TTY(scr)) {
719 if (scr->scr_hold_screen) {
720 int s;
721
722 /* XXX RESET KEYBOARD LEDS, etc. */
723 s = spltty(); /* avoid conflict with keyboard */
724 wsdisplay_kbdholdscreen((struct device *)sc, 0);
725 splx(s);
726 }
727 tp = scr->scr_tty;
728 (*linesw[tp->t_line].l_close)(tp, flag);
729 ttyclose(tp);
730 }
731
732 if (scr->scr_syncops)
733 (*scr->scr_syncops->destroy)(scr->scr_synccookie);
734
735 if (WSSCREEN_HAS_EMULATOR(scr)) {
736 scr->scr_flags &= ~SCR_GRAPHICS;
737 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
738 WSEMUL_RESET);
739 if (wsdisplay_clearonclose)
740 (*scr->scr_dconf->wsemul->reset)
741 (scr->scr_dconf->wsemulcookie,
742 WSEMUL_CLEARSCREEN);
743 }
744
745 #ifdef WSDISPLAY_COMPAT_RAWKBD
746 if (scr->scr_rawkbd) {
747 int kbmode = WSKBD_TRANSLATED;
748 (void) wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
749 (caddr_t)&kbmode, 0, p);
750 }
751 #endif
752
753 scr->scr_flags &= ~SCR_OPEN;
754
755 return (0);
756 #else
757 return (ENXIO);
758 #endif /* NWSDISPLAY > 0 */
759 }
760
761 int
762 wsdisplayread(dev, uio, flag)
763 dev_t dev;
764 struct uio *uio;
765 int flag;
766 {
767 #if NWSDISPLAY > 0
768 struct wsdisplay_softc *sc;
769 struct tty *tp;
770 int unit;
771 struct wsscreen *scr;
772
773 unit = WSDISPLAYUNIT(dev);
774 sc = wsdisplay_cd.cd_devs[unit];
775
776 if (ISWSDISPLAYCTL(dev))
777 return (0);
778
779 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
780
781 if (!WSSCREEN_HAS_TTY(scr))
782 return (ENODEV);
783
784 tp = scr->scr_tty;
785 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
786 #else
787 return (ENXIO);
788 #endif /* NWSDISPLAY > 0 */
789 }
790
791 int
792 wsdisplaywrite(dev, uio, flag)
793 dev_t dev;
794 struct uio *uio;
795 int flag;
796 {
797 #if NWSDISPLAY > 0
798 struct wsdisplay_softc *sc;
799 struct tty *tp;
800 int unit;
801 struct wsscreen *scr;
802
803 unit = WSDISPLAYUNIT(dev);
804 sc = wsdisplay_cd.cd_devs[unit];
805
806 if (ISWSDISPLAYCTL(dev))
807 return (0);
808
809 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
810
811 if (!WSSCREEN_HAS_TTY(scr))
812 return (ENODEV);
813
814 tp = scr->scr_tty;
815 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
816 #else
817 return (ENXIO);
818 #endif /* NWSDISPLAY > 0 */
819 }
820
821 struct tty *
822 wsdisplaytty(dev)
823 dev_t dev;
824 {
825 #if NWSDISPLAY > 0
826 struct wsdisplay_softc *sc;
827 int unit;
828 struct wsscreen *scr;
829
830 unit = WSDISPLAYUNIT(dev);
831 sc = wsdisplay_cd.cd_devs[unit];
832
833 if (ISWSDISPLAYCTL(dev))
834 panic("wsdisplaytty() on ctl device");
835
836 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
837
838 return (scr->scr_tty);
839 #else
840 return (NULL);
841 #endif /* NWSDISPLAY > 0 */
842 }
843
844 int
845 wsdisplayioctl(dev, cmd, data, flag, p)
846 dev_t dev;
847 u_long cmd;
848 caddr_t data;
849 int flag;
850 struct proc *p;
851 {
852 #if NWSDISPLAY > 0
853 struct wsdisplay_softc *sc;
854 struct tty *tp;
855 int unit, error;
856 struct wsscreen *scr;
857
858 unit = WSDISPLAYUNIT(dev);
859 sc = wsdisplay_cd.cd_devs[unit];
860
861 if (ISWSDISPLAYCTL(dev))
862 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p));
863
864 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
865
866 if (WSSCREEN_HAS_TTY(scr)) {
867 tp = scr->scr_tty;
868
869 /* printf("disc\n"); */
870 /* do the line discipline ioctls first */
871 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
872 if (error >= 0)
873 return error;
874
875 /* printf("tty\n"); */
876 /* then the tty ioctls */
877 error = ttioctl(tp, cmd, data, flag, p);
878 if (error >= 0)
879 return error;
880 }
881
882 #ifdef WSDISPLAY_COMPAT_USL
883 error = wsdisplay_usl_ioctl(sc, scr, cmd, data, flag, p);
884 if (error >= 0)
885 return (error);
886 #endif
887
888 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p);
889 return (error != -1 ? error : ENOTTY);
890 #else
891 return (ENXIO);
892 #endif /* NWSDISPLAY > 0 */
893 }
894
895 int
896 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)
897 struct wsdisplay_softc *sc;
898 struct wsscreen *scr;
899 u_long cmd;
900 caddr_t data;
901 int flag;
902 struct proc *p;
903 {
904 int error;
905 char namebuf[16];
906 struct wsdisplay_font fd;
907
908 if (sc->sc_kbddv != NULL) {
909 /* check ioctls for keyboard */
910 #ifdef WSDISPLAY_COMPAT_RAWKBD
911 switch (cmd) {
912 case WSKBDIO_SETMODE:
913 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
914 return (wsdisplay_update_rawkbd(sc, scr));
915 case WSKBDIO_GETMODE:
916 *(int *)data = (scr->scr_rawkbd ?
917 WSKBD_RAW : WSKBD_TRANSLATED);
918 return (0);
919 }
920 #endif
921 /* printf("kbdcallback\n"); */
922 error = wskbd_displayioctl(sc->sc_kbddv, cmd, data, flag, p);
923 if (error >= 0)
924 return error;
925 }
926
927 /* printf("display\n"); */
928 switch (cmd) {
929 case WSDISPLAYIO_GMODE:
930 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ?
931 WSDISPLAYIO_MODE_MAPPED :
932 WSDISPLAYIO_MODE_EMUL);
933 return (0);
934
935 case WSDISPLAYIO_SMODE:
936 #define d (*(int *)data)
937 if (d != WSDISPLAYIO_MODE_EMUL &&
938 d != WSDISPLAYIO_MODE_MAPPED)
939 return (EINVAL);
940
941 if (WSSCREEN_HAS_EMULATOR(scr)) {
942 scr->scr_flags &= ~SCR_GRAPHICS;
943 if (d == WSDISPLAYIO_MODE_MAPPED)
944 scr->scr_flags |= SCR_GRAPHICS;
945 } else if (d == WSDISPLAYIO_MODE_EMUL)
946 return (EINVAL);
947 return (0);
948 #undef d
949
950 case WSDISPLAYIO_USEFONT:
951 #define d ((struct wsdisplay_usefontdata *)data)
952 if (!sc->sc_accessops->load_font)
953 return (EINVAL);
954 if (d->name) {
955 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0);
956 if (error)
957 return (error);
958 fd.name = namebuf;
959 } else
960 fd.name = 0;
961 fd.data = 0;
962 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
963 scr->scr_dconf->emulcookie, &fd);
964 if (!error && WSSCREEN_HAS_EMULATOR(scr))
965 (*scr->scr_dconf->wsemul->reset)
966 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
967 return (error);
968 #undef d
969 }
970
971 /* check ioctls for display */
972 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
973 flag, p));
974 }
975
976 int
977 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)
978 struct wsdisplay_softc *sc;
979 u_long cmd;
980 caddr_t data;
981 int flag;
982 struct proc *p;
983 {
984 int error;
985 char *type, typebuf[16], *emul, emulbuf[16];
986 void *buf;
987
988 switch (cmd) {
989 case WSDISPLAYIO_ADDSCREEN:
990 #define d ((struct wsdisplay_addscreendata *)data)
991 if (d->screentype) {
992 error = copyinstr(d->screentype, typebuf,
993 sizeof(typebuf), 0);
994 if (error)
995 return (error);
996 type = typebuf;
997 } else
998 type = 0;
999 if (d->emul) {
1000 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf), 0);
1001 if (error)
1002 return (error);
1003 emul = emulbuf;
1004 } else
1005 emul = 0;
1006
1007 return (wsdisplay_addscreen(sc, d->idx, type, emul));
1008 #undef d
1009 case WSDISPLAYIO_DELSCREEN:
1010 #define d ((struct wsdisplay_delscreendata *)data)
1011 return (wsdisplay_delscreen(sc, d->idx, d->flags));
1012 #undef d
1013 case WSDISPLAYIO_LDFONT:
1014 #define d ((struct wsdisplay_font *)data)
1015 if (!sc->sc_accessops->load_font)
1016 return (EINVAL);
1017 if (d->name) {
1018 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0);
1019 if (error)
1020 return (error);
1021 d->name = typebuf;
1022 } else
1023 d->name = "loaded"; /* ??? */
1024 buf = malloc(d->fontheight * d->stride * d->numchars,
1025 M_DEVBUF, M_WAITOK);
1026 error = copyin(d->data, buf,
1027 d->fontheight * d->stride * d->numchars);
1028 if (error) {
1029 free(buf, M_DEVBUF);
1030 return (error);
1031 }
1032 d->data = buf;
1033 error =
1034 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
1035 free(buf, M_DEVBUF);
1036 #undef d
1037 return (error);
1038 }
1039 return (EINVAL);
1040 }
1041
1042 int
1043 wsdisplaymmap(dev, offset, prot)
1044 dev_t dev;
1045 int offset; /* XXX */
1046 int prot;
1047 {
1048 #if NWSDISPLAY > 0
1049 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1050 struct wsscreen *scr;
1051
1052 if (ISWSDISPLAYCTL(dev))
1053 return (-1);
1054
1055 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1056
1057 if (!(scr->scr_flags & SCR_GRAPHICS))
1058 return (-1);
1059
1060 /* pass mmap to display */
1061 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
1062 #else
1063 return (-1);
1064 #endif /* NWSDISPLAY > 0 */
1065 }
1066
1067 int
1068 wsdisplaypoll(dev, events, p)
1069 dev_t dev;
1070 int events;
1071 struct proc *p;
1072 {
1073 #if NWSDISPLAY > 0
1074 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1075 struct wsscreen *scr;
1076
1077 if (ISWSDISPLAYCTL(dev))
1078 return (0);
1079
1080 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1081
1082 if (WSSCREEN_HAS_TTY(scr))
1083 return (ttpoll(dev, events, p));
1084 else
1085 return (0);
1086 #else
1087 return (0);
1088 #endif /* NWSDISPLAY > 0 */
1089 }
1090
1091 #if NWSDISPLAY > 0
1092 void
1093 wsdisplaystart(tp)
1094 register struct tty *tp;
1095 {
1096 struct wsdisplay_softc *sc;
1097 struct wsscreen *scr;
1098 register int s, n;
1099 u_char buf[WSDISPLAYBURST];
1100
1101 s = spltty();
1102 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
1103 splx(s);
1104 return;
1105 }
1106 sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(tp->t_dev)];
1107 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)];
1108 if (scr->scr_hold_screen) {
1109 tp->t_state |= TS_TIMEOUT;
1110 splx(s);
1111 return;
1112 }
1113 tp->t_state |= TS_BUSY;
1114 splx(s);
1115
1116 n = q_to_b(&tp->t_outq, buf, sizeof(buf));
1117
1118 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1119 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1120 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1121 buf, n, 0);
1122 }
1123
1124 s = spltty();
1125 tp->t_state &= ~TS_BUSY;
1126 /* Come back if there's more to do */
1127 if (tp->t_outq.c_cc) {
1128 tp->t_state |= TS_TIMEOUT;
1129 timeout(ttrstrt, tp, (hz > 128) ? (hz / 128) : 1);
1130 }
1131 if (tp->t_outq.c_cc <= tp->t_lowat) {
1132 if (tp->t_state&TS_ASLEEP) {
1133 tp->t_state &= ~TS_ASLEEP;
1134 wakeup((caddr_t)&tp->t_outq);
1135 }
1136 selwakeup(&tp->t_wsel);
1137 }
1138 splx(s);
1139 }
1140 #endif /* NWSDISPLAY > 0 */
1141
1142 void
1143 wsdisplaystop(tp, flag)
1144 struct tty *tp;
1145 int flag;
1146 {
1147 int s;
1148
1149 s = spltty();
1150 if (ISSET(tp->t_state, TS_BUSY))
1151 if (!ISSET(tp->t_state, TS_TTSTOP))
1152 SET(tp->t_state, TS_FLUSH);
1153 splx(s);
1154 }
1155
1156 #if NWSDISPLAY > 0
1157 /* Set line parameters. */
1158 int
1159 wsdisplayparam(tp, t)
1160 struct tty *tp;
1161 struct termios *t;
1162 {
1163
1164 tp->t_ispeed = t->c_ispeed;
1165 tp->t_ospeed = t->c_ospeed;
1166 tp->t_cflag = t->c_cflag;
1167 return 0;
1168 }
1169 #endif /* NWSDISPLAY > 0 */
1170
1171 /*
1172 * Callbacks for the emulation code.
1173 */
1174 void
1175 wsdisplay_emulbell(v)
1176 void *v;
1177 {
1178 struct wsscreen *scr = v;
1179
1180 if (scr == NULL) /* console, before real attach */
1181 return;
1182
1183 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */
1184 return;
1185
1186 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
1187 FWRITE, NULL);
1188 }
1189
1190 void
1191 wsdisplay_emulinput(v, data, count)
1192 void *v;
1193 const u_char *data;
1194 u_int count;
1195 {
1196 struct wsscreen *scr = v;
1197 struct tty *tp;
1198
1199 if (v == NULL) /* console, before real attach */
1200 return;
1201
1202 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */
1203 return;
1204 if (!WSSCREEN_HAS_TTY(scr))
1205 return;
1206
1207 tp = scr->scr_tty;
1208 while (count-- > 0)
1209 (*linesw[tp->t_line].l_rint)(*data++, tp);
1210 };
1211
1212 /*
1213 * Calls from the keyboard interface.
1214 */
1215 void
1216 wsdisplay_kbdinput(dev, ks)
1217 struct device *dev;
1218 keysym_t ks;
1219 {
1220 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1221 struct wsscreen *scr;
1222 char *dp;
1223 int count;
1224 struct tty *tp;
1225
1226 KASSERT(sc != NULL);
1227
1228 scr = sc->sc_focus;
1229
1230 if (!scr || !WSSCREEN_HAS_TTY(scr))
1231 return;
1232
1233 tp = scr->scr_tty;
1234
1235 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1236 (*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp);
1237 else if (WSSCREEN_HAS_EMULATOR(scr)) {
1238 count = (*scr->scr_dconf->wsemul->translate)
1239 (scr->scr_dconf->wsemulcookie, ks, &dp);
1240 while (count-- > 0)
1241 (*linesw[tp->t_line].l_rint)(*dp++, tp);
1242 }
1243 }
1244
1245 #ifdef WSDISPLAY_COMPAT_RAWKBD
1246 int
1247 wsdisplay_update_rawkbd(sc, scr)
1248 struct wsdisplay_softc *sc;
1249 struct wsscreen *scr;
1250 {
1251 int s, data, error;
1252 s = spltty();
1253
1254 if (!sc->sc_kbddv ||
1255 scr != sc->sc_focus ||
1256 sc->sc_rawkbd == scr->scr_rawkbd) {
1257 splx(s);
1258 return (0);
1259 }
1260
1261 data = (scr->scr_rawkbd ? WSKBD_RAW : WSKBD_TRANSLATED);
1262 error = wskbd_displayioctl(sc->sc_kbddv, WSKBDIO_SETMODE,
1263 (caddr_t)&data, 0, 0);
1264 if (!error)
1265 sc->sc_rawkbd = scr->scr_rawkbd;
1266 splx(s);
1267 return (error);
1268 }
1269 #endif
1270
1271 int
1272 wsdisplay_switch1(arg, waitok)
1273 void *arg;
1274 int waitok;
1275 {
1276 struct wsdisplay_softc *sc = arg;
1277 int no;
1278 struct wsscreen *scr;
1279
1280 if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1281 printf("wsdisplay_switchto: not switching\n");
1282 return (EINVAL);
1283 }
1284
1285 no = sc->sc_screenwanted;
1286 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1287 panic("wsdisplay_switch1: invalid screen %d", no);
1288 scr = sc->sc_scr[no];
1289 if (!scr) {
1290 printf("wsdisplay_switch1: screen %d disappeared\n", no);
1291 sc->sc_flags &= ~SC_SWITCHPENDING;
1292 return (ENXIO);
1293 }
1294
1295 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
1296 scr->scr_dconf->emulcookie);
1297 sc->sc_focusidx = no;
1298 sc->sc_focus = scr;
1299
1300 #ifdef WSDISPLAY_COMPAT_RAWKBD
1301 (void) wsdisplay_update_rawkbd(sc, scr);
1302 #endif
1303 /* keyboard map??? */
1304
1305 if (scr->scr_syncops) {
1306 (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok);
1307 /* XXX error handling */
1308 }
1309
1310 sc->sc_flags &= ~SC_SWITCHPENDING;
1311
1312 if (scr->scr_flags & SCR_WAITACTIVE)
1313 wakeup(scr);
1314 return (0);
1315 }
1316
1317 int
1318 wsdisplay_switch(dev, no, waitok)
1319 struct device *dev;
1320 int no, waitok;
1321 {
1322 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1323 int s, res = 0;
1324 struct wsscreen *scr;
1325
1326 if (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])
1327 return (ENXIO);
1328
1329 s = spltty();
1330
1331 if (no == sc->sc_focusidx) {
1332 splx(s);
1333 return (0);
1334 }
1335
1336 if (sc->sc_flags & SC_SWITCHPENDING) {
1337 splx(s);
1338 return (EBUSY);
1339 }
1340
1341 sc->sc_flags |= SC_SWITCHPENDING;
1342 sc->sc_screenwanted = no;
1343
1344 splx(s);
1345
1346 scr = sc->sc_focus;
1347 if (!scr)
1348 return (wsdisplay_switch1(sc, waitok));
1349
1350 #define wsswitch_callback ((void (*) __P((void *, int)))wsdisplay_switch1)
1351 if (scr->scr_syncops) {
1352 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok,
1353 wsswitch_callback, sc);
1354 if (res == EAGAIN) {
1355 /* switch will be done asynchronously */
1356 return (0);
1357 }
1358 } else if (scr->scr_flags & SCR_GRAPHICS) {
1359 /* no way to save state */
1360 res = EBUSY;
1361 }
1362
1363 if (res) {
1364 sc->sc_flags &= ~SC_SWITCHPENDING;
1365 return (res);
1366 } else
1367 return (wsdisplay_switch1(sc, waitok));
1368 }
1369
1370 void
1371 wsdisplay_reset(dev, op)
1372 struct device *dev;
1373 enum wsdisplay_resetops op;
1374 {
1375 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1376 struct wsscreen *scr;
1377
1378 KASSERT(sc != NULL);
1379 scr = sc->sc_focus;
1380
1381 if (!scr)
1382 return;
1383
1384 switch (op) {
1385 case WSDISPLAY_RESETEMUL:
1386 if (!WSSCREEN_HAS_EMULATOR(scr))
1387 break;
1388 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
1389 WSEMUL_RESET);
1390 break;
1391 case WSDISPLAY_RESETCLOSE:
1392 wsdisplay_closescreen(sc, scr);
1393 break;
1394 }
1395 }
1396
1397 /*
1398 * Interface for (external) VT switch / process synchronization code
1399 */
1400 int
1401 wsscreen_attach_sync(scr, ops, cookie)
1402 struct wsscreen *scr;
1403 const struct wscons_syncops *ops;
1404 void *cookie;
1405 {
1406 if (scr->scr_syncops) {
1407 /*
1408 * The screen is already claimed.
1409 * Check if the owner is still alive.
1410 */
1411 if ((*scr->scr_syncops->check)(scr->scr_synccookie))
1412 return (EBUSY);
1413 }
1414 scr->scr_syncops = ops;
1415 scr->scr_synccookie = cookie;
1416 return (0);
1417 }
1418
1419 int
1420 wsscreen_detach_sync(scr)
1421 struct wsscreen *scr;
1422 {
1423 if (!scr->scr_syncops)
1424 return (EINVAL);
1425 scr->scr_syncops = 0;
1426 return (0);
1427 }
1428
1429 int
1430 wsscreen_lookup_sync(scr, ops, cookiep)
1431 struct wsscreen *scr;
1432 const struct wscons_syncops *ops; /* used as ID */
1433 void **cookiep;
1434 {
1435 if (!scr->scr_syncops || ops != scr->scr_syncops)
1436 return (EINVAL);
1437 *cookiep = scr->scr_synccookie;
1438 return (0);
1439 }
1440
1441 /*
1442 * Interface to virtual screen stuff
1443 */
1444 int
1445 wsdisplay_maxscreenidx(sc)
1446 struct wsdisplay_softc *sc;
1447 {
1448 return (WSDISPLAY_MAXSCREEN - 1);
1449 }
1450
1451 int
1452 wsdisplay_screenstate(sc, idx)
1453 struct wsdisplay_softc *sc;
1454 int idx;
1455 {
1456 if (idx >= WSDISPLAY_MAXSCREEN)
1457 return (EINVAL);
1458 if (!sc->sc_scr[idx])
1459 return (ENXIO);
1460 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0);
1461 }
1462
1463 int
1464 wsdisplay_getactivescreen(sc)
1465 struct wsdisplay_softc *sc;
1466 {
1467 return (sc->sc_focusidx);
1468 }
1469
1470 int
1471 wsscreen_switchwait(sc, no)
1472 struct wsdisplay_softc *sc;
1473 int no;
1474 {
1475 struct wsscreen *scr;
1476 int s, res = 0;
1477
1478 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1479 return (ENXIO);
1480 scr = sc->sc_scr[no];
1481 if (!scr)
1482 return (ENXIO);
1483
1484 s = spltty();
1485 if (scr != sc->sc_focus) {
1486 scr->scr_flags |= SCR_WAITACTIVE;
1487 res = tsleep(scr, PCATCH, "wswait", 0);
1488 if (scr != sc->sc_scr[no])
1489 res = ENXIO; /* disappeared in the meantime */
1490 else
1491 scr->scr_flags &= ~SCR_WAITACTIVE;
1492 }
1493 splx(s);
1494 return (res);
1495 }
1496
1497 void
1498 wsdisplay_kbdholdscreen(dev, hold)
1499 struct device *dev;
1500 int hold;
1501 {
1502 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1503 struct wsscreen *scr;
1504
1505 scr = sc->sc_focus;
1506
1507 if (hold)
1508 scr->scr_hold_screen = 1;
1509 else {
1510 scr->scr_hold_screen = 0;
1511 timeout(ttrstrt, scr->scr_tty, 0); /* "immediate" */
1512 }
1513 }
1514
1515 /*
1516 * Calls from the glue code.
1517 */
1518 int
1519 wsdisplay_is_console(dv)
1520 struct device *dv;
1521 {
1522 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1523
1524 KASSERT(sc != NULL);
1525 return (sc->sc_isconsole);
1526 }
1527
1528 struct device *
1529 wsdisplay_kbd(dv)
1530 struct device *dv;
1531 {
1532 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1533
1534 KASSERT(sc != NULL);
1535 return (sc->sc_kbddv);
1536 }
1537
1538 void
1539 wsdisplay_set_kbd(dv, kbddv)
1540 struct device *dv, *kbddv;
1541 {
1542 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1543
1544 KASSERT(sc != NULL);
1545 if (sc->sc_kbddv) {
1546 /* disable old keyboard */
1547 wskbd_enable(sc->sc_kbddv, 0);
1548 }
1549 if (kbddv) {
1550 /* enable new keyboard */
1551 wskbd_enable(kbddv, 1);
1552 }
1553 sc->sc_kbddv = kbddv;
1554 }
1555
1556 /*
1557 * Console interface.
1558 */
1559 void
1560 wsdisplay_cnputc(dev, i)
1561 dev_t dev;
1562 int i;
1563 {
1564 struct wsscreen_internal *dc;
1565 char c = i;
1566
1567 if (!wsdisplay_console_initted)
1568 return;
1569
1570 if (wsdisplay_console_device != NULL &&
1571 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
1572 return;
1573
1574 dc = &wsdisplay_console_conf;
1575 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
1576 }
1577
1578 static int
1579 wsdisplay_getc_dummy(dev)
1580 dev_t dev;
1581 {
1582 /* panic? */
1583 return (0);
1584 }
1585
1586 static void
1587 wsdisplay_pollc_dummy(dev, on)
1588 dev_t dev;
1589 int on;
1590 {
1591 }
1592
1593 void
1594 wsdisplay_set_cons_kbd(get, poll)
1595 int (*get) __P((dev_t));
1596 void (*poll) __P((dev_t, int));
1597 {
1598 wsdisplay_cons.cn_getc = get;
1599 wsdisplay_cons.cn_pollc = poll;
1600 }
1601