wsdisplay.c revision 1.22.2.1 1 /* $NetBSD: wsdisplay.c,v 1.22.2.1 1999/10/19 16:39:20 he 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.22.2.1 1999/10/19 16:39:20 he 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, sc_oldscreen; /* 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
178 #define WSSCREEN_HAS_EMULATOR(scr) ((scr)->scr_dconf->wsemul != NULL)
179 #define WSSCREEN_HAS_TTY(scr) ((scr)->scr_tty != NULL)
180
181 static void wsdisplay_common_attach __P((struct wsdisplay_softc *sc,
182 int console, const struct wsscreen_list *,
183 const struct wsdisplay_accessops *accessops,
184 void *accesscookie));
185
186 #ifdef WSDISPLAY_COMPAT_RAWKBD
187 int wsdisplay_update_rawkbd __P((struct wsdisplay_softc *,
188 struct wsscreen *));
189 #endif
190
191 static int wsdisplay_console_initted;
192 static struct wsdisplay_softc *wsdisplay_console_device;
193 static struct wsscreen_internal wsdisplay_console_conf;
194
195 static int wsdisplay_getc_dummy __P((dev_t));
196 static void wsdisplay_pollc_dummy __P((dev_t, int));
197
198 static struct consdev wsdisplay_cons = {
199 NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
200 wsdisplay_pollc_dummy, NODEV, CN_NORMAL
201 };
202
203 int wsdisplay_switch1 __P((void *, int, int));
204 int wsdisplay_switch3 __P((void *, int, 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 int s;
323
324 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
325 return (EINVAL);
326 if (sc->sc_scr[idx] != NULL)
327 return (EBUSY);
328
329 scrdesc = wsdisplay_screentype_pick(sc->sc_scrdata, screentype);
330 if (!scrdesc)
331 return (ENXIO);
332 error = (*sc->sc_accessops->alloc_screen)(sc->sc_accesscookie,
333 scrdesc, &cookie, &ccol, &crow, &defattr);
334 if (error)
335 return (error);
336
337 scr = wsscreen_attach(sc, 0, emul, scrdesc,
338 cookie, ccol, crow, defattr);
339 if (scr == NULL) {
340 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
341 cookie);
342 return (ENXIO);
343 }
344
345 sc->sc_scr[idx] = scr;
346
347 printf("%s: screen %d added (%s", sc->sc_dv.dv_xname, idx,
348 scrdesc->name);
349 if (WSSCREEN_HAS_EMULATOR(scr))
350 printf(", %s emulation", scr->scr_dconf->wsemul->name);
351 printf(")\n");
352
353 /* if no screen has focus yet, activate the first we get */
354 s = spltty();
355 if (!sc->sc_focus) {
356 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
357 scr->scr_dconf->emulcookie);
358 sc->sc_focusidx = idx;
359 sc->sc_focus = scr;
360 }
361 splx(s);
362 return (0);
363 }
364
365 static void
366 wsdisplay_closescreen(sc, scr)
367 struct wsdisplay_softc *sc;
368 struct wsscreen *scr;
369 {
370 int maj, mn, idx;
371
372 /* hangup */
373 if (WSSCREEN_HAS_TTY(scr)) {
374 struct tty *tp = scr->scr_tty;
375 (*linesw[tp->t_line].l_modem)(tp, 0);
376 }
377
378 /* locate the major number */
379 for (maj = 0; maj < nchrdev; maj++)
380 if (cdevsw[maj].d_open == wsdisplayopen)
381 break;
382 /* locate the screen index */
383 for (idx = 0; idx < WSDISPLAY_MAXSCREEN; idx++)
384 if (scr == sc->sc_scr[idx])
385 break;
386 #ifdef DIAGNOSTIC
387 if (idx == WSDISPLAY_MAXSCREEN)
388 panic("wsdisplay_forceclose: bad screen");
389 #endif
390
391 /* nuke the vnodes */
392 mn = WSDISPLAYMINOR(sc->sc_dv.dv_unit, idx);
393 vdevgone(maj, mn, mn, VCHR);
394 }
395
396 int
397 wsdisplay_delscreen(sc, idx, flags)
398 struct wsdisplay_softc *sc;
399 int idx, flags;
400 {
401 struct wsscreen *scr;
402 int s;
403 void *cookie;
404
405 if (idx < 0 || idx >= WSDISPLAY_MAXSCREEN)
406 return (EINVAL);
407 scr = sc->sc_scr[idx];
408 if (!scr)
409 return (ENXIO);
410
411 if (scr->scr_dconf == &wsdisplay_console_conf ||
412 scr->scr_syncops ||
413 ((scr->scr_flags & SCR_OPEN) && !(flags & WSDISPLAY_DELSCR_FORCE)))
414 return(EBUSY);
415
416 wsdisplay_closescreen(sc, scr);
417
418 /*
419 * delete pointers, so neither device entries
420 * nor keyboard input can reference it anymore
421 */
422 s = spltty();
423 if (sc->sc_focus == scr) {
424 sc->sc_focus = 0;
425 #ifdef WSDISPLAY_COMPAT_RAWKBD
426 wsdisplay_update_rawkbd(sc, 0);
427 #endif
428 }
429 sc->sc_scr[idx] = 0;
430 splx(s);
431
432 /*
433 * Wake up processes waiting for the screen to
434 * be activated. Sleepers must check whether
435 * the screen still exists.
436 */
437 if (scr->scr_flags & SCR_WAITACTIVE)
438 wakeup(scr);
439
440 /* save a reference to the graphics screen */
441 cookie = scr->scr_dconf->emulcookie;
442
443 wsscreen_detach(scr);
444
445 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
446 cookie);
447
448 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx);
449 return (0);
450 }
451
452 /*
453 * Autoconfiguration functions.
454 */
455 int
456 wsdisplay_emul_match(parent, match, aux)
457 struct device *parent;
458 struct cfdata *match;
459 void *aux;
460 {
461 struct wsemuldisplaydev_attach_args *ap = aux;
462
463 if (match->wsemuldisplaydevcf_console !=
464 WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
465 /*
466 * If console-ness of device specified, either match
467 * exactly (at high priority), or fail.
468 */
469 if (match->wsemuldisplaydevcf_console != 0 &&
470 ap->console != 0)
471 return (10);
472 else
473 return (0);
474 }
475
476 /* If console-ness unspecified, it wins. */
477 return (1);
478 }
479
480 void
481 wsdisplay_emul_attach(parent, self, aux)
482 struct device *parent, *self;
483 void *aux;
484 {
485 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
486 struct wsemuldisplaydev_attach_args *ap = aux;
487
488 wsdisplay_common_attach(sc, ap->console, ap->scrdata,
489 ap->accessops, ap->accesscookie);
490
491 if (ap->console) {
492 int maj;
493
494 /* locate the major number */
495 for (maj = 0; maj < nchrdev; maj++)
496 if (cdevsw[maj].d_open == wsdisplayopen)
497 break;
498
499 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0));
500 }
501 }
502
503 /* Print function (for parent devices). */
504 int
505 wsemuldisplaydevprint(aux, pnp)
506 void *aux;
507 const char *pnp;
508 {
509 #if 0 /* -Wunused */
510 struct wsemuldisplaydev_attach_args *ap = aux;
511 #endif
512
513 if (pnp)
514 printf("wsdisplay at %s", pnp);
515 #if 0 /* don't bother; it's ugly */
516 printf(" console %d", ap->console);
517 #endif
518
519 return (UNCONF);
520 }
521
522 int
523 wsdisplay_noemul_match(parent, match, aux)
524 struct device *parent;
525 struct cfdata *match;
526 void *aux;
527 {
528 #if 0 /* -Wunused */
529 struct wsdisplaydev_attach_args *ap = aux;
530 #endif
531
532 /* Always match. */
533 return (1);
534 }
535
536 void
537 wsdisplay_noemul_attach(parent, self, aux)
538 struct device *parent, *self;
539 void *aux;
540 {
541 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
542 struct wsdisplaydev_attach_args *ap = aux;
543
544 wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie);
545 }
546
547 /* Print function (for parent devices). */
548 int
549 wsdisplaydevprint(aux, pnp)
550 void *aux;
551 const char *pnp;
552 {
553 #if 0 /* -Wunused */
554 struct wsdisplaydev_attach_args *ap = aux;
555 #endif
556
557 if (pnp)
558 printf("wsdisplay at %s", pnp);
559
560 return (UNCONF);
561 }
562
563 static void
564 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie)
565 struct wsdisplay_softc *sc;
566 int console;
567 const struct wsscreen_list *scrdata;
568 const struct wsdisplay_accessops *accessops;
569 void *accesscookie;
570 {
571 int i = 0;
572
573 if (console) {
574 KASSERT(wsdisplay_console_initted);
575 KASSERT(wsdisplay_console_device == NULL);
576
577 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
578 wsdisplay_console_device = sc;
579
580 printf(": console (%s, %s emulation)",
581 wsdisplay_console_conf.scrdata->name,
582 wsdisplay_console_conf.wsemul->name);
583
584 sc->sc_focusidx = 0;
585 sc->sc_focus = sc->sc_scr[0];
586 i++;
587 }
588
589 printf("\n");
590
591 sc->sc_accessops = accessops;
592 sc->sc_accesscookie = accesscookie;
593 sc->sc_scrdata = scrdata;
594
595 sc->sc_isconsole = console;
596 sc->sc_kbddv = NULL;
597
598 wscons_glue_set_callback();
599
600 /*
601 * Set up a number of virtual screens if possible. The
602 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
603 * should go away as soon as we have a userspace utility.
604 */
605 #ifdef WSDISPLAY_DEFAULTSCREENS
606 for (; i < WSDISPLAY_DEFAULTSCREENS; i++)
607 if (wsdisplay_addscreen(sc, i, 0, 0))
608 break;
609 #endif
610 }
611
612 void
613 wsdisplay_cnattach(type, cookie, ccol, crow, defattr)
614 const struct wsscreen_descr *type;
615 void *cookie;
616 int ccol, crow;
617 long defattr;
618 {
619 const struct wsemul_ops *wsemul;
620
621 KASSERT(!wsdisplay_console_initted);
622 KASSERT(type->nrows > 0);
623 KASSERT(type->ncols > 0);
624 KASSERT(crow < type->nrows);
625 KASSERT(ccol < type->ncols);
626
627 wsdisplay_console_conf.emulops = type->textops;
628 wsdisplay_console_conf.emulcookie = cookie;
629 wsdisplay_console_conf.scrdata = type;
630
631 wsemul = wsemul_pick(0); /* default */
632 wsdisplay_console_conf.wsemul = wsemul;
633 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
634 ccol, crow,
635 defattr);
636
637 cn_tab = &wsdisplay_cons;
638
639 wsdisplay_console_initted = 1;
640 }
641
642 /*
643 * Tty and cdevsw functions.
644 */
645 int
646 wsdisplayopen(dev, flag, mode, p)
647 dev_t dev;
648 int flag, mode;
649 struct proc *p;
650 {
651 #if NWSDISPLAY > 0
652 struct wsdisplay_softc *sc;
653 struct tty *tp;
654 int unit, newopen, error;
655 struct wsscreen *scr;
656
657 unit = WSDISPLAYUNIT(dev);
658 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
659 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
660 return (ENXIO);
661
662 if (ISWSDISPLAYCTL(dev))
663 return (0);
664
665 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
666 return (ENXIO);
667 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
668 if (!scr)
669 return (ENXIO);
670
671 if (WSSCREEN_HAS_TTY(scr)) {
672 tp = scr->scr_tty;
673 tp->t_oproc = wsdisplaystart;
674 tp->t_param = wsdisplayparam;
675 tp->t_dev = dev;
676 newopen = (tp->t_state & TS_ISOPEN) == 0;
677 if (newopen) {
678 ttychars(tp);
679 tp->t_iflag = TTYDEF_IFLAG;
680 tp->t_oflag = TTYDEF_OFLAG;
681 tp->t_cflag = TTYDEF_CFLAG;
682 tp->t_lflag = TTYDEF_LFLAG;
683 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
684 wsdisplayparam(tp, &tp->t_termios);
685 ttsetwater(tp);
686 } else if ((tp->t_state & TS_XCLUDE) != 0 &&
687 p->p_ucred->cr_uid != 0)
688 return EBUSY;
689 tp->t_state |= TS_CARR_ON;
690
691 error = ((*linesw[tp->t_line].l_open)(dev, tp));
692 if (error)
693 return (error);
694
695 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
696 /* set window sizes as appropriate, and reset
697 the emulation */
698 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
699 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
700
701 /* wsdisplay_set_emulation() */
702 }
703 }
704
705 scr->scr_flags |= SCR_OPEN;
706 return (0);
707 #else
708 return (ENXIO);
709 #endif /* NWSDISPLAY > 0 */
710 }
711
712 int
713 wsdisplayclose(dev, flag, mode, p)
714 dev_t dev;
715 int flag, mode;
716 struct proc *p;
717 {
718 #if NWSDISPLAY > 0
719 struct wsdisplay_softc *sc;
720 struct tty *tp;
721 int unit;
722 struct wsscreen *scr;
723
724 unit = WSDISPLAYUNIT(dev);
725 sc = wsdisplay_cd.cd_devs[unit];
726
727 if (ISWSDISPLAYCTL(dev))
728 return (0);
729
730 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
731
732 if (WSSCREEN_HAS_TTY(scr)) {
733 if (scr->scr_hold_screen) {
734 int s;
735
736 /* XXX RESET KEYBOARD LEDS, etc. */
737 s = spltty(); /* avoid conflict with keyboard */
738 wsdisplay_kbdholdscreen((struct device *)sc, 0);
739 splx(s);
740 }
741 tp = scr->scr_tty;
742 (*linesw[tp->t_line].l_close)(tp, flag);
743 ttyclose(tp);
744 }
745
746 if (scr->scr_syncops)
747 (*scr->scr_syncops->destroy)(scr->scr_synccookie);
748
749 if (WSSCREEN_HAS_EMULATOR(scr)) {
750 scr->scr_flags &= ~SCR_GRAPHICS;
751 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
752 WSEMUL_RESET);
753 if (wsdisplay_clearonclose)
754 (*scr->scr_dconf->wsemul->reset)
755 (scr->scr_dconf->wsemulcookie,
756 WSEMUL_CLEARSCREEN);
757 }
758
759 #ifdef WSDISPLAY_COMPAT_RAWKBD
760 if (scr->scr_rawkbd) {
761 int kbmode = WSKBD_TRANSLATED;
762 (void) wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
763 (caddr_t)&kbmode, 0, p);
764 }
765 #endif
766
767 scr->scr_flags &= ~SCR_OPEN;
768
769 return (0);
770 #else
771 return (ENXIO);
772 #endif /* NWSDISPLAY > 0 */
773 }
774
775 int
776 wsdisplayread(dev, uio, flag)
777 dev_t dev;
778 struct uio *uio;
779 int flag;
780 {
781 #if NWSDISPLAY > 0
782 struct wsdisplay_softc *sc;
783 struct tty *tp;
784 int unit;
785 struct wsscreen *scr;
786
787 unit = WSDISPLAYUNIT(dev);
788 sc = wsdisplay_cd.cd_devs[unit];
789
790 if (ISWSDISPLAYCTL(dev))
791 return (0);
792
793 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
794
795 if (!WSSCREEN_HAS_TTY(scr))
796 return (ENODEV);
797
798 tp = scr->scr_tty;
799 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
800 #else
801 return (ENXIO);
802 #endif /* NWSDISPLAY > 0 */
803 }
804
805 int
806 wsdisplaywrite(dev, uio, flag)
807 dev_t dev;
808 struct uio *uio;
809 int flag;
810 {
811 #if NWSDISPLAY > 0
812 struct wsdisplay_softc *sc;
813 struct tty *tp;
814 int unit;
815 struct wsscreen *scr;
816
817 unit = WSDISPLAYUNIT(dev);
818 sc = wsdisplay_cd.cd_devs[unit];
819
820 if (ISWSDISPLAYCTL(dev))
821 return (0);
822
823 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
824
825 if (!WSSCREEN_HAS_TTY(scr))
826 return (ENODEV);
827
828 tp = scr->scr_tty;
829 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
830 #else
831 return (ENXIO);
832 #endif /* NWSDISPLAY > 0 */
833 }
834
835 struct tty *
836 wsdisplaytty(dev)
837 dev_t dev;
838 {
839 #if NWSDISPLAY > 0
840 struct wsdisplay_softc *sc;
841 int unit;
842 struct wsscreen *scr;
843
844 unit = WSDISPLAYUNIT(dev);
845 sc = wsdisplay_cd.cd_devs[unit];
846
847 if (ISWSDISPLAYCTL(dev))
848 panic("wsdisplaytty() on ctl device");
849
850 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
851
852 return (scr->scr_tty);
853 #else
854 return (NULL);
855 #endif /* NWSDISPLAY > 0 */
856 }
857
858 int
859 wsdisplayioctl(dev, cmd, data, flag, p)
860 dev_t dev;
861 u_long cmd;
862 caddr_t data;
863 int flag;
864 struct proc *p;
865 {
866 #if NWSDISPLAY > 0
867 struct wsdisplay_softc *sc;
868 struct tty *tp;
869 int unit, error;
870 struct wsscreen *scr;
871
872 unit = WSDISPLAYUNIT(dev);
873 sc = wsdisplay_cd.cd_devs[unit];
874
875 #ifdef WSDISPLAY_COMPAT_USL
876 error = wsdisplay_usl_ioctl1(sc, cmd, data, flag, p);
877 if (error >= 0)
878 return (error);
879 #endif
880
881 if (ISWSDISPLAYCTL(dev))
882 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p));
883
884 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
885
886 if (WSSCREEN_HAS_TTY(scr)) {
887 tp = scr->scr_tty;
888
889 /* printf("disc\n"); */
890 /* do the line discipline ioctls first */
891 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
892 if (error >= 0)
893 return error;
894
895 /* printf("tty\n"); */
896 /* then the tty ioctls */
897 error = ttioctl(tp, cmd, data, flag, p);
898 if (error >= 0)
899 return error;
900 }
901
902 #ifdef WSDISPLAY_COMPAT_USL
903 error = wsdisplay_usl_ioctl2(sc, scr, cmd, data, flag, p);
904 if (error >= 0)
905 return (error);
906 #endif
907
908 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p);
909 return (error != -1 ? error : ENOTTY);
910 #else
911 return (ENXIO);
912 #endif /* NWSDISPLAY > 0 */
913 }
914
915 int
916 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)
917 struct wsdisplay_softc *sc;
918 struct wsscreen *scr;
919 u_long cmd;
920 caddr_t data;
921 int flag;
922 struct proc *p;
923 {
924 int error;
925 char namebuf[16];
926 struct wsdisplay_font fd;
927
928 if (sc->sc_kbddv != NULL) {
929 /* check ioctls for keyboard */
930 #ifdef WSDISPLAY_COMPAT_RAWKBD
931 switch (cmd) {
932 case WSKBDIO_SETMODE:
933 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
934 return (wsdisplay_update_rawkbd(sc, scr));
935 case WSKBDIO_GETMODE:
936 *(int *)data = (scr->scr_rawkbd ?
937 WSKBD_RAW : WSKBD_TRANSLATED);
938 return (0);
939 }
940 #endif
941 /* printf("kbdcallback\n"); */
942 error = wskbd_displayioctl(sc->sc_kbddv, cmd, data, flag, p);
943 if (error >= 0)
944 return error;
945 }
946
947 /* printf("display\n"); */
948 switch (cmd) {
949 case WSDISPLAYIO_GMODE:
950 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ?
951 WSDISPLAYIO_MODE_MAPPED :
952 WSDISPLAYIO_MODE_EMUL);
953 return (0);
954
955 case WSDISPLAYIO_SMODE:
956 #define d (*(int *)data)
957 if (d != WSDISPLAYIO_MODE_EMUL &&
958 d != WSDISPLAYIO_MODE_MAPPED)
959 return (EINVAL);
960
961 if (WSSCREEN_HAS_EMULATOR(scr)) {
962 scr->scr_flags &= ~SCR_GRAPHICS;
963 if (d == WSDISPLAYIO_MODE_MAPPED)
964 scr->scr_flags |= SCR_GRAPHICS;
965 } else if (d == WSDISPLAYIO_MODE_EMUL)
966 return (EINVAL);
967 return (0);
968 #undef d
969
970 case WSDISPLAYIO_USEFONT:
971 #define d ((struct wsdisplay_usefontdata *)data)
972 if (!sc->sc_accessops->load_font)
973 return (EINVAL);
974 if (d->name) {
975 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0);
976 if (error)
977 return (error);
978 fd.name = namebuf;
979 } else
980 fd.name = 0;
981 fd.data = 0;
982 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
983 scr->scr_dconf->emulcookie, &fd);
984 if (!error && WSSCREEN_HAS_EMULATOR(scr))
985 (*scr->scr_dconf->wsemul->reset)
986 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
987 return (error);
988 #undef d
989 }
990
991 /* check ioctls for display */
992 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
993 flag, p));
994 }
995
996 int
997 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)
998 struct wsdisplay_softc *sc;
999 u_long cmd;
1000 caddr_t data;
1001 int flag;
1002 struct proc *p;
1003 {
1004 int error;
1005 char *type, typebuf[16], *emul, emulbuf[16];
1006 void *buf;
1007
1008 switch (cmd) {
1009 case WSDISPLAYIO_ADDSCREEN:
1010 #define d ((struct wsdisplay_addscreendata *)data)
1011 if (d->screentype) {
1012 error = copyinstr(d->screentype, typebuf,
1013 sizeof(typebuf), 0);
1014 if (error)
1015 return (error);
1016 type = typebuf;
1017 } else
1018 type = 0;
1019 if (d->emul) {
1020 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf), 0);
1021 if (error)
1022 return (error);
1023 emul = emulbuf;
1024 } else
1025 emul = 0;
1026
1027 return (wsdisplay_addscreen(sc, d->idx, type, emul));
1028 #undef d
1029 case WSDISPLAYIO_DELSCREEN:
1030 #define d ((struct wsdisplay_delscreendata *)data)
1031 return (wsdisplay_delscreen(sc, d->idx, d->flags));
1032 #undef d
1033 case WSDISPLAYIO_LDFONT:
1034 #define d ((struct wsdisplay_font *)data)
1035 if (!sc->sc_accessops->load_font)
1036 return (EINVAL);
1037 if (d->name) {
1038 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0);
1039 if (error)
1040 return (error);
1041 d->name = typebuf;
1042 } else
1043 d->name = "loaded"; /* ??? */
1044 buf = malloc(d->fontheight * d->stride * d->numchars,
1045 M_DEVBUF, M_WAITOK);
1046 error = copyin(d->data, buf,
1047 d->fontheight * d->stride * d->numchars);
1048 if (error) {
1049 free(buf, M_DEVBUF);
1050 return (error);
1051 }
1052 d->data = buf;
1053 error =
1054 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
1055 free(buf, M_DEVBUF);
1056 #undef d
1057 return (error);
1058 }
1059 return (EINVAL);
1060 }
1061
1062 int
1063 wsdisplaymmap(dev, offset, prot)
1064 dev_t dev;
1065 int offset; /* XXX */
1066 int prot;
1067 {
1068 #if NWSDISPLAY > 0
1069 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1070 struct wsscreen *scr;
1071
1072 if (ISWSDISPLAYCTL(dev))
1073 return (-1);
1074
1075 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1076
1077 if (!(scr->scr_flags & SCR_GRAPHICS))
1078 return (-1);
1079
1080 /* pass mmap to display */
1081 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
1082 #else
1083 return (-1);
1084 #endif /* NWSDISPLAY > 0 */
1085 }
1086
1087 int
1088 wsdisplaypoll(dev, events, p)
1089 dev_t dev;
1090 int events;
1091 struct proc *p;
1092 {
1093 #if NWSDISPLAY > 0
1094 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1095 struct wsscreen *scr;
1096
1097 if (ISWSDISPLAYCTL(dev))
1098 return (0);
1099
1100 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1101
1102 if (WSSCREEN_HAS_TTY(scr))
1103 return (ttpoll(dev, events, p));
1104 else
1105 return (0);
1106 #else
1107 return (0);
1108 #endif /* NWSDISPLAY > 0 */
1109 }
1110
1111 #if NWSDISPLAY > 0
1112 void
1113 wsdisplaystart(tp)
1114 register struct tty *tp;
1115 {
1116 struct wsdisplay_softc *sc;
1117 struct wsscreen *scr;
1118 register int s, n;
1119 u_char *buf;
1120
1121 s = spltty();
1122 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
1123 splx(s);
1124 return;
1125 }
1126 sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(tp->t_dev)];
1127 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)];
1128 if (scr->scr_hold_screen) {
1129 tp->t_state |= TS_TIMEOUT;
1130 splx(s);
1131 return;
1132 }
1133 tp->t_state |= TS_BUSY;
1134 splx(s);
1135
1136 /*
1137 * Drain output from ring buffer.
1138 * The output will normally be in one contiguous chunk, but when the
1139 * ring wraps, it will be in two pieces.. one at the end of the ring,
1140 * the other at the start. For performance, rather than loop here,
1141 * we output one chunk, see if there's another one, and if so, output
1142 * it too.
1143 */
1144
1145 n = ndqb(&tp->t_outq, 0);
1146 buf = tp->t_outq.c_cf;
1147
1148 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1149 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1150 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1151 buf, n, 0);
1152 }
1153 ndflush(&tp->t_outq, n);
1154
1155 if ((n = ndqb(&tp->t_outq, 0)) > 0) {
1156 buf = tp->t_outq.c_cf;
1157
1158 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1159 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1160 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1161 buf, n, 0);
1162 }
1163 ndflush(&tp->t_outq, n);
1164 }
1165
1166 s = spltty();
1167 tp->t_state &= ~TS_BUSY;
1168 /* Come back if there's more to do */
1169 if (tp->t_outq.c_cc) {
1170 tp->t_state |= TS_TIMEOUT;
1171 timeout(ttrstrt, tp, (hz > 128) ? (hz / 128) : 1);
1172 }
1173 if (tp->t_outq.c_cc <= tp->t_lowat) {
1174 if (tp->t_state&TS_ASLEEP) {
1175 tp->t_state &= ~TS_ASLEEP;
1176 wakeup((caddr_t)&tp->t_outq);
1177 }
1178 selwakeup(&tp->t_wsel);
1179 }
1180 splx(s);
1181 }
1182 #endif /* NWSDISPLAY > 0 */
1183
1184 void
1185 wsdisplaystop(tp, flag)
1186 struct tty *tp;
1187 int flag;
1188 {
1189 int s;
1190
1191 s = spltty();
1192 if (ISSET(tp->t_state, TS_BUSY))
1193 if (!ISSET(tp->t_state, TS_TTSTOP))
1194 SET(tp->t_state, TS_FLUSH);
1195 splx(s);
1196 }
1197
1198 #if NWSDISPLAY > 0
1199 /* Set line parameters. */
1200 int
1201 wsdisplayparam(tp, t)
1202 struct tty *tp;
1203 struct termios *t;
1204 {
1205
1206 tp->t_ispeed = t->c_ispeed;
1207 tp->t_ospeed = t->c_ospeed;
1208 tp->t_cflag = t->c_cflag;
1209 return 0;
1210 }
1211 #endif /* NWSDISPLAY > 0 */
1212
1213 /*
1214 * Callbacks for the emulation code.
1215 */
1216 void
1217 wsdisplay_emulbell(v)
1218 void *v;
1219 {
1220 struct wsscreen *scr = v;
1221
1222 if (scr == NULL) /* console, before real attach */
1223 return;
1224
1225 if (scr->scr_flags & SCR_GRAPHICS) /* can this happen? */
1226 return;
1227
1228 (void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
1229 FWRITE, NULL);
1230 }
1231
1232 void
1233 wsdisplay_emulinput(v, data, count)
1234 void *v;
1235 const u_char *data;
1236 u_int count;
1237 {
1238 struct wsscreen *scr = v;
1239 struct tty *tp;
1240
1241 if (v == NULL) /* console, before real attach */
1242 return;
1243
1244 if (scr->scr_flags & SCR_GRAPHICS) /* XXX can't happen */
1245 return;
1246 if (!WSSCREEN_HAS_TTY(scr))
1247 return;
1248
1249 tp = scr->scr_tty;
1250 while (count-- > 0)
1251 (*linesw[tp->t_line].l_rint)(*data++, tp);
1252 };
1253
1254 /*
1255 * Calls from the keyboard interface.
1256 */
1257 void
1258 wsdisplay_kbdinput(dev, ks)
1259 struct device *dev;
1260 keysym_t ks;
1261 {
1262 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1263 struct wsscreen *scr;
1264 char *dp;
1265 int count;
1266 struct tty *tp;
1267
1268 KASSERT(sc != NULL);
1269
1270 scr = sc->sc_focus;
1271
1272 if (!scr || !WSSCREEN_HAS_TTY(scr))
1273 return;
1274
1275 tp = scr->scr_tty;
1276
1277 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1278 (*linesw[tp->t_line].l_rint)(KS_VALUE(ks), tp);
1279 else if (WSSCREEN_HAS_EMULATOR(scr)) {
1280 count = (*scr->scr_dconf->wsemul->translate)
1281 (scr->scr_dconf->wsemulcookie, ks, &dp);
1282 while (count-- > 0)
1283 (*linesw[tp->t_line].l_rint)(*dp++, tp);
1284 }
1285 }
1286
1287 #ifdef WSDISPLAY_COMPAT_RAWKBD
1288 int
1289 wsdisplay_update_rawkbd(sc, scr)
1290 struct wsdisplay_softc *sc;
1291 struct wsscreen *scr;
1292 {
1293 int s, raw, data, error;
1294 s = spltty();
1295
1296 raw = (scr ? scr->scr_rawkbd : 0);
1297
1298 if (!sc->sc_kbddv ||
1299 scr != sc->sc_focus ||
1300 sc->sc_rawkbd == raw) {
1301 splx(s);
1302 return (0);
1303 }
1304
1305 data = (raw ? WSKBD_RAW : WSKBD_TRANSLATED);
1306 error = wskbd_displayioctl(sc->sc_kbddv, WSKBDIO_SETMODE,
1307 (caddr_t)&data, 0, 0);
1308 if (!error)
1309 sc->sc_rawkbd = raw;
1310 splx(s);
1311 return (error);
1312 }
1313 #endif
1314
1315 int
1316 wsdisplay_switch3(arg, error, waitok)
1317 void *arg;
1318 int error, waitok;
1319 {
1320 struct wsdisplay_softc *sc = arg;
1321 int no;
1322 struct wsscreen *scr;
1323
1324 if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1325 printf("wsdisplay_switch3: not switching\n");
1326 return (EINVAL);
1327 }
1328
1329 no = sc->sc_screenwanted;
1330 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1331 panic("wsdisplay_switch3: invalid screen %d", no);
1332 scr = sc->sc_scr[no];
1333 if (!scr) {
1334 printf("wsdisplay_switch3: screen %d disappeared\n", no);
1335 error = ENXIO;
1336 }
1337
1338 if (error) {
1339 /* try to recover, avoid recursion */
1340
1341 if (sc->sc_oldscreen == -1) {
1342 printf("wsdisplay_switch3: giving up\n");
1343 sc->sc_focus = 0;
1344 #ifdef WSDISPLAY_COMPAT_RAWKBD
1345 wsdisplay_update_rawkbd(sc, 0);
1346 #endif
1347 sc->sc_flags &= ~SC_SWITCHPENDING;
1348 return (error);
1349 }
1350
1351 sc->sc_screenwanted = sc->sc_oldscreen;
1352 sc->sc_oldscreen = -1;
1353 return (wsdisplay_switch1(arg, 0, waitok));
1354 }
1355
1356 sc->sc_flags &= ~SC_SWITCHPENDING;
1357
1358 if (!error && (scr->scr_flags & SCR_WAITACTIVE))
1359 wakeup(scr);
1360 return (error);
1361 }
1362
1363 int
1364 wsdisplay_switch1(arg, error, waitok)
1365 void *arg;
1366 int error, waitok;
1367 {
1368 struct wsdisplay_softc *sc = arg;
1369 int no;
1370 struct wsscreen *scr;
1371
1372 if (!(sc->sc_flags & SC_SWITCHPENDING)) {
1373 printf("wsdisplay_switch1: not switching\n");
1374 return (EINVAL);
1375 }
1376
1377 no = sc->sc_screenwanted;
1378 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1379 panic("wsdisplay_switch1: invalid screen %d", no);
1380 scr = sc->sc_scr[no];
1381 if (!scr) {
1382 printf("wsdisplay_switch1: screen %d disappeared\n", no);
1383 error = ENXIO;
1384 }
1385
1386 if (error) {
1387 sc->sc_flags &= ~SC_SWITCHPENDING;
1388 return (error);
1389 }
1390
1391 (*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
1392 scr->scr_dconf->emulcookie);
1393 sc->sc_focusidx = no;
1394 sc->sc_focus = scr;
1395
1396 #ifdef WSDISPLAY_COMPAT_RAWKBD
1397 (void) wsdisplay_update_rawkbd(sc, scr);
1398 #endif
1399 /* keyboard map??? */
1400
1401 #define wsswitch_cb3 ((void (*) __P((void *, int, int)))wsdisplay_switch3)
1402 if (scr->scr_syncops) {
1403 error = (*scr->scr_syncops->attach)(scr->scr_synccookie, waitok,
1404 wsswitch_cb3, sc);
1405 if (error == EAGAIN) {
1406 /* switch will be done asynchronously */
1407 return (0);
1408 }
1409 }
1410
1411 return (wsdisplay_switch3(sc, error, waitok));
1412 }
1413
1414 int
1415 wsdisplay_switch(dev, no, waitok)
1416 struct device *dev;
1417 int no, waitok;
1418 {
1419 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1420 int s, res = 0;
1421 struct wsscreen *scr;
1422
1423 if (no < 0 || no >= WSDISPLAY_MAXSCREEN || !sc->sc_scr[no])
1424 return (ENXIO);
1425
1426 s = spltty();
1427
1428 if (sc->sc_focus && no == sc->sc_focusidx) {
1429 splx(s);
1430 return (0);
1431 }
1432
1433 if (sc->sc_flags & SC_SWITCHPENDING) {
1434 splx(s);
1435 return (EBUSY);
1436 }
1437
1438 sc->sc_flags |= SC_SWITCHPENDING;
1439 sc->sc_screenwanted = no;
1440
1441 splx(s);
1442
1443 scr = sc->sc_focus;
1444 if (!scr) {
1445 sc->sc_oldscreen = -1;
1446 return (wsdisplay_switch1(sc, 0, waitok));
1447 } else
1448 sc->sc_oldscreen = sc->sc_focusidx;
1449
1450 #define wsswitch_cb1 ((void (*) __P((void *, int, int)))wsdisplay_switch1)
1451 if (scr->scr_syncops) {
1452 res = (*scr->scr_syncops->detach)(scr->scr_synccookie, waitok,
1453 wsswitch_cb1, sc);
1454 if (res == EAGAIN) {
1455 /* switch will be done asynchronously */
1456 return (0);
1457 }
1458 } else if (scr->scr_flags & SCR_GRAPHICS) {
1459 /* no way to save state */
1460 res = EBUSY;
1461 }
1462
1463 return (wsdisplay_switch1(sc, res, waitok));
1464 }
1465
1466 void
1467 wsdisplay_reset(dev, op)
1468 struct device *dev;
1469 enum wsdisplay_resetops op;
1470 {
1471 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1472 struct wsscreen *scr;
1473
1474 KASSERT(sc != NULL);
1475 scr = sc->sc_focus;
1476
1477 if (!scr)
1478 return;
1479
1480 switch (op) {
1481 case WSDISPLAY_RESETEMUL:
1482 if (!WSSCREEN_HAS_EMULATOR(scr))
1483 break;
1484 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
1485 WSEMUL_RESET);
1486 break;
1487 case WSDISPLAY_RESETCLOSE:
1488 wsdisplay_closescreen(sc, scr);
1489 break;
1490 }
1491 }
1492
1493 /*
1494 * Interface for (external) VT switch / process synchronization code
1495 */
1496 int
1497 wsscreen_attach_sync(scr, ops, cookie)
1498 struct wsscreen *scr;
1499 const struct wscons_syncops *ops;
1500 void *cookie;
1501 {
1502 if (scr->scr_syncops) {
1503 /*
1504 * The screen is already claimed.
1505 * Check if the owner is still alive.
1506 */
1507 if ((*scr->scr_syncops->check)(scr->scr_synccookie))
1508 return (EBUSY);
1509 }
1510 scr->scr_syncops = ops;
1511 scr->scr_synccookie = cookie;
1512 return (0);
1513 }
1514
1515 int
1516 wsscreen_detach_sync(scr)
1517 struct wsscreen *scr;
1518 {
1519 if (!scr->scr_syncops)
1520 return (EINVAL);
1521 scr->scr_syncops = 0;
1522 return (0);
1523 }
1524
1525 int
1526 wsscreen_lookup_sync(scr, ops, cookiep)
1527 struct wsscreen *scr;
1528 const struct wscons_syncops *ops; /* used as ID */
1529 void **cookiep;
1530 {
1531 if (!scr->scr_syncops || ops != scr->scr_syncops)
1532 return (EINVAL);
1533 *cookiep = scr->scr_synccookie;
1534 return (0);
1535 }
1536
1537 /*
1538 * Interface to virtual screen stuff
1539 */
1540 int
1541 wsdisplay_maxscreenidx(sc)
1542 struct wsdisplay_softc *sc;
1543 {
1544 return (WSDISPLAY_MAXSCREEN - 1);
1545 }
1546
1547 int
1548 wsdisplay_screenstate(sc, idx)
1549 struct wsdisplay_softc *sc;
1550 int idx;
1551 {
1552 if (idx >= WSDISPLAY_MAXSCREEN)
1553 return (EINVAL);
1554 if (!sc->sc_scr[idx])
1555 return (ENXIO);
1556 return ((sc->sc_scr[idx]->scr_flags & SCR_OPEN) ? EBUSY : 0);
1557 }
1558
1559 int
1560 wsdisplay_getactivescreen(sc)
1561 struct wsdisplay_softc *sc;
1562 {
1563 return (sc->sc_focusidx);
1564 }
1565
1566 int
1567 wsscreen_switchwait(sc, no)
1568 struct wsdisplay_softc *sc;
1569 int no;
1570 {
1571 struct wsscreen *scr;
1572 int s, res = 0;
1573
1574 if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
1575 return (ENXIO);
1576 scr = sc->sc_scr[no];
1577 if (!scr)
1578 return (ENXIO);
1579
1580 s = spltty();
1581 if (scr != sc->sc_focus) {
1582 scr->scr_flags |= SCR_WAITACTIVE;
1583 res = tsleep(scr, PCATCH, "wswait", 0);
1584 if (scr != sc->sc_scr[no])
1585 res = ENXIO; /* disappeared in the meantime */
1586 else
1587 scr->scr_flags &= ~SCR_WAITACTIVE;
1588 }
1589 splx(s);
1590 return (res);
1591 }
1592
1593 void
1594 wsdisplay_kbdholdscreen(dev, hold)
1595 struct device *dev;
1596 int hold;
1597 {
1598 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
1599 struct wsscreen *scr;
1600
1601 scr = sc->sc_focus;
1602
1603 if (hold)
1604 scr->scr_hold_screen = 1;
1605 else {
1606 scr->scr_hold_screen = 0;
1607 timeout(ttrstrt, scr->scr_tty, 0); /* "immediate" */
1608 }
1609 }
1610
1611 /*
1612 * Calls from the glue code.
1613 */
1614 int
1615 wsdisplay_is_console(dv)
1616 struct device *dv;
1617 {
1618 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1619
1620 KASSERT(sc != NULL);
1621 return (sc->sc_isconsole);
1622 }
1623
1624 struct device *
1625 wsdisplay_kbd(dv)
1626 struct device *dv;
1627 {
1628 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1629
1630 KASSERT(sc != NULL);
1631 return (sc->sc_kbddv);
1632 }
1633
1634 void
1635 wsdisplay_set_kbd(dv, kbddv)
1636 struct device *dv, *kbddv;
1637 {
1638 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1639
1640 KASSERT(sc != NULL);
1641 if (sc->sc_kbddv) {
1642 /* disable old keyboard */
1643 wskbd_enable(sc->sc_kbddv, 0);
1644 }
1645 if (kbddv) {
1646 /* enable new keyboard */
1647 wskbd_enable(kbddv, 1);
1648 }
1649 sc->sc_kbddv = kbddv;
1650 }
1651
1652 /*
1653 * Console interface.
1654 */
1655 void
1656 wsdisplay_cnputc(dev, i)
1657 dev_t dev;
1658 int i;
1659 {
1660 struct wsscreen_internal *dc;
1661 char c = i;
1662
1663 if (!wsdisplay_console_initted)
1664 return;
1665
1666 if (wsdisplay_console_device != NULL &&
1667 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
1668 return;
1669
1670 dc = &wsdisplay_console_conf;
1671 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
1672 }
1673
1674 static int
1675 wsdisplay_getc_dummy(dev)
1676 dev_t dev;
1677 {
1678 /* panic? */
1679 return (0);
1680 }
1681
1682 static void
1683 wsdisplay_pollc_dummy(dev, on)
1684 dev_t dev;
1685 int on;
1686 {
1687 }
1688
1689 void
1690 wsdisplay_set_cons_kbd(get, poll)
1691 int (*get) __P((dev_t));
1692 void (*poll) __P((dev_t, int));
1693 {
1694 wsdisplay_cons.cn_getc = get;
1695 wsdisplay_cons.cn_pollc = poll;
1696 }
1697