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