wsdisplay.c revision 1.20 1 /* $NetBSD: wsdisplay.c,v 1.20 1999/02/08 14:48:07 sommerfe 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.20 1999/02/08 14:48:07 sommerfe 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
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 #ifdef WSDISPLAY_COMPAT_RAWKBD
415 wsdisplay_update_rawkbd(sc, 0);
416 #endif
417 }
418 sc->sc_scr[idx] = 0;
419 splx(s);
420
421 /*
422 * Wake up processes waiting for the screen to
423 * be activated. Sleepers must check whether
424 * the screen still exists.
425 */
426 if (scr->scr_flags & SCR_WAITACTIVE)
427 wakeup(scr);
428
429 /* save a reference to the graphics screen */
430 cookie = scr->scr_dconf->emulcookie;
431
432 wsscreen_detach(scr);
433
434 (*sc->sc_accessops->free_screen)(sc->sc_accesscookie,
435 cookie);
436
437 printf("%s: screen %d deleted\n", sc->sc_dv.dv_xname, idx);
438 return (0);
439 }
440
441 /*
442 * Autoconfiguration functions.
443 */
444 int
445 wsdisplay_emul_match(parent, match, aux)
446 struct device *parent;
447 struct cfdata *match;
448 void *aux;
449 {
450 struct wsemuldisplaydev_attach_args *ap = aux;
451
452 if (match->wsemuldisplaydevcf_console !=
453 WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
454 /*
455 * If console-ness of device specified, either match
456 * exactly (at high priority), or fail.
457 */
458 if (match->wsemuldisplaydevcf_console != 0 &&
459 ap->console != 0)
460 return (10);
461 else
462 return (0);
463 }
464
465 /* If console-ness unspecified, it wins. */
466 return (1);
467 }
468
469 void
470 wsdisplay_emul_attach(parent, self, aux)
471 struct device *parent, *self;
472 void *aux;
473 {
474 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
475 struct wsemuldisplaydev_attach_args *ap = aux;
476
477 wsdisplay_common_attach(sc, ap->console, ap->scrdata,
478 ap->accessops, ap->accesscookie);
479
480 if (ap->console) {
481 int maj;
482
483 /* locate the major number */
484 for (maj = 0; maj < nchrdev; maj++)
485 if (cdevsw[maj].d_open == wsdisplayopen)
486 break;
487
488 cn_tab->cn_dev = makedev(maj, WSDISPLAYMINOR(self->dv_unit, 0));
489 }
490 }
491
492 /* Print function (for parent devices). */
493 int
494 wsemuldisplaydevprint(aux, pnp)
495 void *aux;
496 const char *pnp;
497 {
498 #if 0 /* -Wunused */
499 struct wsemuldisplaydev_attach_args *ap = aux;
500 #endif
501
502 if (pnp)
503 printf("wsdisplay at %s", pnp);
504 #if 0 /* don't bother; it's ugly */
505 printf(" console %d", ap->console);
506 #endif
507
508 return (UNCONF);
509 }
510
511 int
512 wsdisplay_noemul_match(parent, match, aux)
513 struct device *parent;
514 struct cfdata *match;
515 void *aux;
516 {
517 #if 0 /* -Wunused */
518 struct wsdisplaydev_attach_args *ap = aux;
519 #endif
520
521 /* Always match. */
522 return (1);
523 }
524
525 void
526 wsdisplay_noemul_attach(parent, self, aux)
527 struct device *parent, *self;
528 void *aux;
529 {
530 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
531 struct wsdisplaydev_attach_args *ap = aux;
532
533 wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie);
534 }
535
536 /* Print function (for parent devices). */
537 int
538 wsdisplaydevprint(aux, pnp)
539 void *aux;
540 const char *pnp;
541 {
542 #if 0 /* -Wunused */
543 struct wsdisplaydev_attach_args *ap = aux;
544 #endif
545
546 if (pnp)
547 printf("wsdisplay at %s", pnp);
548
549 return (UNCONF);
550 }
551
552 static void
553 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie)
554 struct wsdisplay_softc *sc;
555 int console;
556 const struct wsscreen_list *scrdata;
557 const struct wsdisplay_accessops *accessops;
558 void *accesscookie;
559 {
560 int i = 0;
561
562 if (console) {
563 KASSERT(wsdisplay_console_initted);
564 KASSERT(wsdisplay_console_device == NULL);
565
566 sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0, 0);
567 wsdisplay_console_device = sc;
568
569 printf(": console (%s, %s emulation)",
570 wsdisplay_console_conf.scrdata->name,
571 wsdisplay_console_conf.wsemul->name);
572
573 sc->sc_focusidx = 0;
574 sc->sc_focus = sc->sc_scr[0];
575 i++;
576 }
577
578 printf("\n");
579
580 sc->sc_accessops = accessops;
581 sc->sc_accesscookie = accesscookie;
582 sc->sc_scrdata = scrdata;
583
584 sc->sc_isconsole = console;
585 sc->sc_kbddv = NULL;
586
587 wscons_glue_set_callback();
588
589 /*
590 * Set up a number of virtual screens if possible. The
591 * WSDISPLAYIO_ADDSCREEN ioctl is more flexible, so this code
592 * should go away as soon as we have a userspace utility.
593 */
594 #ifndef WSDISPLAY_DEFAULTSCREENS
595 #define WSDISPLAY_DEFAULTSCREENS WSDISPLAY_MAXSCREEN
596 #endif
597 for (; i < WSDISPLAY_DEFAULTSCREENS; i++)
598 if (wsdisplay_addscreen(sc, i, 0, 0))
599 break;
600 }
601
602 void
603 wsdisplay_cnattach(type, cookie, ccol, crow, defattr)
604 const struct wsscreen_descr *type;
605 void *cookie;
606 int ccol, crow;
607 long defattr;
608 {
609 const struct wsemul_ops *wsemul;
610
611 KASSERT(!wsdisplay_console_initted);
612 KASSERT(type->nrows > 0);
613 KASSERT(type->ncols > 0);
614 KASSERT(crow < type->nrows);
615 KASSERT(ccol < type->ncols);
616
617 wsdisplay_console_conf.emulops = type->textops;
618 wsdisplay_console_conf.emulcookie = cookie;
619 wsdisplay_console_conf.scrdata = type;
620
621 wsemul = wsemul_pick(0); /* default */
622 wsdisplay_console_conf.wsemul = wsemul;
623 wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
624 ccol, crow,
625 defattr);
626
627 cn_tab = &wsdisplay_cons;
628
629 wsdisplay_console_initted = 1;
630 }
631
632 /*
633 * Tty and cdevsw functions.
634 */
635 int
636 wsdisplayopen(dev, flag, mode, p)
637 dev_t dev;
638 int flag, mode;
639 struct proc *p;
640 {
641 #if NWSDISPLAY > 0
642 struct wsdisplay_softc *sc;
643 struct tty *tp;
644 int unit, newopen, error;
645 struct wsscreen *scr;
646
647 unit = WSDISPLAYUNIT(dev);
648 if (unit >= wsdisplay_cd.cd_ndevs || /* make sure it was attached */
649 (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
650 return (ENXIO);
651
652 if (ISWSDISPLAYCTL(dev))
653 return (0);
654
655 if (WSDISPLAYSCREEN(dev) >= WSDISPLAY_MAXSCREEN)
656 return (ENXIO);
657 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
658 if (!scr)
659 return (ENXIO);
660
661 if (WSSCREEN_HAS_TTY(scr)) {
662 tp = scr->scr_tty;
663 tp->t_oproc = wsdisplaystart;
664 tp->t_param = wsdisplayparam;
665 tp->t_dev = dev;
666 newopen = (tp->t_state & TS_ISOPEN) == 0;
667 if (newopen) {
668 ttychars(tp);
669 tp->t_iflag = TTYDEF_IFLAG;
670 tp->t_oflag = TTYDEF_OFLAG;
671 tp->t_cflag = TTYDEF_CFLAG;
672 tp->t_lflag = TTYDEF_LFLAG;
673 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
674 wsdisplayparam(tp, &tp->t_termios);
675 ttsetwater(tp);
676 } else if ((tp->t_state & TS_XCLUDE) != 0 &&
677 p->p_ucred->cr_uid != 0)
678 return EBUSY;
679 tp->t_state |= TS_CARR_ON;
680
681 error = ((*linesw[tp->t_line].l_open)(dev, tp));
682 if (error)
683 return (error);
684
685 if (newopen && WSSCREEN_HAS_EMULATOR(scr)) {
686 /* set window sizes as appropriate, and reset
687 the emulation */
688 tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
689 tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
690
691 /* wsdisplay_set_emulation() */
692 }
693 }
694
695 scr->scr_flags |= SCR_OPEN;
696 return (0);
697 #else
698 return (ENXIO);
699 #endif /* NWSDISPLAY > 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 #if NWSDISPLAY > 0
709 struct wsdisplay_softc *sc;
710 struct tty *tp;
711 int unit;
712 struct wsscreen *scr;
713
714 unit = WSDISPLAYUNIT(dev);
715 sc = wsdisplay_cd.cd_devs[unit];
716
717 if (ISWSDISPLAYCTL(dev))
718 return (0);
719
720 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
721
722 if (WSSCREEN_HAS_TTY(scr)) {
723 if (scr->scr_hold_screen) {
724 int s;
725
726 /* XXX RESET KEYBOARD LEDS, etc. */
727 s = spltty(); /* avoid conflict with keyboard */
728 wsdisplay_kbdholdscreen((struct device *)sc, 0);
729 splx(s);
730 }
731 tp = scr->scr_tty;
732 (*linesw[tp->t_line].l_close)(tp, flag);
733 ttyclose(tp);
734 }
735
736 if (scr->scr_syncops)
737 (*scr->scr_syncops->destroy)(scr->scr_synccookie);
738
739 if (WSSCREEN_HAS_EMULATOR(scr)) {
740 scr->scr_flags &= ~SCR_GRAPHICS;
741 (*scr->scr_dconf->wsemul->reset)(scr->scr_dconf->wsemulcookie,
742 WSEMUL_RESET);
743 if (wsdisplay_clearonclose)
744 (*scr->scr_dconf->wsemul->reset)
745 (scr->scr_dconf->wsemulcookie,
746 WSEMUL_CLEARSCREEN);
747 }
748
749 #ifdef WSDISPLAY_COMPAT_RAWKBD
750 if (scr->scr_rawkbd) {
751 int kbmode = WSKBD_TRANSLATED;
752 (void) wsdisplay_internal_ioctl(sc, scr, WSKBDIO_SETMODE,
753 (caddr_t)&kbmode, 0, p);
754 }
755 #endif
756
757 scr->scr_flags &= ~SCR_OPEN;
758
759 return (0);
760 #else
761 return (ENXIO);
762 #endif /* NWSDISPLAY > 0 */
763 }
764
765 int
766 wsdisplayread(dev, uio, flag)
767 dev_t dev;
768 struct uio *uio;
769 int flag;
770 {
771 #if NWSDISPLAY > 0
772 struct wsdisplay_softc *sc;
773 struct tty *tp;
774 int unit;
775 struct wsscreen *scr;
776
777 unit = WSDISPLAYUNIT(dev);
778 sc = wsdisplay_cd.cd_devs[unit];
779
780 if (ISWSDISPLAYCTL(dev))
781 return (0);
782
783 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
784
785 if (!WSSCREEN_HAS_TTY(scr))
786 return (ENODEV);
787
788 tp = scr->scr_tty;
789 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
790 #else
791 return (ENXIO);
792 #endif /* NWSDISPLAY > 0 */
793 }
794
795 int
796 wsdisplaywrite(dev, uio, flag)
797 dev_t dev;
798 struct uio *uio;
799 int flag;
800 {
801 #if NWSDISPLAY > 0
802 struct wsdisplay_softc *sc;
803 struct tty *tp;
804 int unit;
805 struct wsscreen *scr;
806
807 unit = WSDISPLAYUNIT(dev);
808 sc = wsdisplay_cd.cd_devs[unit];
809
810 if (ISWSDISPLAYCTL(dev))
811 return (0);
812
813 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
814
815 if (!WSSCREEN_HAS_TTY(scr))
816 return (ENODEV);
817
818 tp = scr->scr_tty;
819 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
820 #else
821 return (ENXIO);
822 #endif /* NWSDISPLAY > 0 */
823 }
824
825 struct tty *
826 wsdisplaytty(dev)
827 dev_t dev;
828 {
829 #if NWSDISPLAY > 0
830 struct wsdisplay_softc *sc;
831 int unit;
832 struct wsscreen *scr;
833
834 unit = WSDISPLAYUNIT(dev);
835 sc = wsdisplay_cd.cd_devs[unit];
836
837 if (ISWSDISPLAYCTL(dev))
838 panic("wsdisplaytty() on ctl device");
839
840 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
841
842 return (scr->scr_tty);
843 #else
844 return (NULL);
845 #endif /* NWSDISPLAY > 0 */
846 }
847
848 int
849 wsdisplayioctl(dev, cmd, data, flag, p)
850 dev_t dev;
851 u_long cmd;
852 caddr_t data;
853 int flag;
854 struct proc *p;
855 {
856 #if NWSDISPLAY > 0
857 struct wsdisplay_softc *sc;
858 struct tty *tp;
859 int unit, error;
860 struct wsscreen *scr;
861
862 unit = WSDISPLAYUNIT(dev);
863 sc = wsdisplay_cd.cd_devs[unit];
864
865 if (ISWSDISPLAYCTL(dev))
866 return (wsdisplay_cfg_ioctl(sc, cmd, data, flag, p));
867
868 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
869
870 if (WSSCREEN_HAS_TTY(scr)) {
871 tp = scr->scr_tty;
872
873 /* printf("disc\n"); */
874 /* do the line discipline ioctls first */
875 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
876 if (error >= 0)
877 return error;
878
879 /* printf("tty\n"); */
880 /* then the tty ioctls */
881 error = ttioctl(tp, cmd, data, flag, p);
882 if (error >= 0)
883 return error;
884 }
885
886 #ifdef WSDISPLAY_COMPAT_USL
887 error = wsdisplay_usl_ioctl(sc, scr, cmd, data, flag, p);
888 if (error >= 0)
889 return (error);
890 #endif
891
892 error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p);
893 return (error != -1 ? error : ENOTTY);
894 #else
895 return (ENXIO);
896 #endif /* NWSDISPLAY > 0 */
897 }
898
899 int
900 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)
901 struct wsdisplay_softc *sc;
902 struct wsscreen *scr;
903 u_long cmd;
904 caddr_t data;
905 int flag;
906 struct proc *p;
907 {
908 int error;
909 char namebuf[16];
910 struct wsdisplay_font fd;
911
912 if (sc->sc_kbddv != NULL) {
913 /* check ioctls for keyboard */
914 #ifdef WSDISPLAY_COMPAT_RAWKBD
915 switch (cmd) {
916 case WSKBDIO_SETMODE:
917 scr->scr_rawkbd = (*(int *)data == WSKBD_RAW);
918 return (wsdisplay_update_rawkbd(sc, scr));
919 case WSKBDIO_GETMODE:
920 *(int *)data = (scr->scr_rawkbd ?
921 WSKBD_RAW : WSKBD_TRANSLATED);
922 return (0);
923 }
924 #endif
925 /* printf("kbdcallback\n"); */
926 error = wskbd_displayioctl(sc->sc_kbddv, cmd, data, flag, p);
927 if (error >= 0)
928 return error;
929 }
930
931 /* printf("display\n"); */
932 switch (cmd) {
933 case WSDISPLAYIO_GMODE:
934 *(u_int *)data = (scr->scr_flags & SCR_GRAPHICS ?
935 WSDISPLAYIO_MODE_MAPPED :
936 WSDISPLAYIO_MODE_EMUL);
937 return (0);
938
939 case WSDISPLAYIO_SMODE:
940 #define d (*(int *)data)
941 if (d != WSDISPLAYIO_MODE_EMUL &&
942 d != WSDISPLAYIO_MODE_MAPPED)
943 return (EINVAL);
944
945 if (WSSCREEN_HAS_EMULATOR(scr)) {
946 scr->scr_flags &= ~SCR_GRAPHICS;
947 if (d == WSDISPLAYIO_MODE_MAPPED)
948 scr->scr_flags |= SCR_GRAPHICS;
949 } else if (d == WSDISPLAYIO_MODE_EMUL)
950 return (EINVAL);
951 return (0);
952 #undef d
953
954 case WSDISPLAYIO_USEFONT:
955 #define d ((struct wsdisplay_usefontdata *)data)
956 if (!sc->sc_accessops->load_font)
957 return (EINVAL);
958 if (d->name) {
959 error = copyinstr(d->name, namebuf, sizeof(namebuf), 0);
960 if (error)
961 return (error);
962 fd.name = namebuf;
963 } else
964 fd.name = 0;
965 fd.data = 0;
966 error = (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
967 scr->scr_dconf->emulcookie, &fd);
968 if (!error && WSSCREEN_HAS_EMULATOR(scr))
969 (*scr->scr_dconf->wsemul->reset)
970 (scr->scr_dconf->wsemulcookie, WSEMUL_SYNCFONT);
971 return (error);
972 #undef d
973 }
974
975 /* check ioctls for display */
976 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
977 flag, p));
978 }
979
980 int
981 wsdisplay_cfg_ioctl(sc, cmd, data, flag, p)
982 struct wsdisplay_softc *sc;
983 u_long cmd;
984 caddr_t data;
985 int flag;
986 struct proc *p;
987 {
988 int error;
989 char *type, typebuf[16], *emul, emulbuf[16];
990 void *buf;
991
992 switch (cmd) {
993 case WSDISPLAYIO_ADDSCREEN:
994 #define d ((struct wsdisplay_addscreendata *)data)
995 if (d->screentype) {
996 error = copyinstr(d->screentype, typebuf,
997 sizeof(typebuf), 0);
998 if (error)
999 return (error);
1000 type = typebuf;
1001 } else
1002 type = 0;
1003 if (d->emul) {
1004 error = copyinstr(d->emul, emulbuf, sizeof(emulbuf), 0);
1005 if (error)
1006 return (error);
1007 emul = emulbuf;
1008 } else
1009 emul = 0;
1010
1011 return (wsdisplay_addscreen(sc, d->idx, type, emul));
1012 #undef d
1013 case WSDISPLAYIO_DELSCREEN:
1014 #define d ((struct wsdisplay_delscreendata *)data)
1015 return (wsdisplay_delscreen(sc, d->idx, d->flags));
1016 #undef d
1017 case WSDISPLAYIO_LDFONT:
1018 #define d ((struct wsdisplay_font *)data)
1019 if (!sc->sc_accessops->load_font)
1020 return (EINVAL);
1021 if (d->name) {
1022 error = copyinstr(d->name, typebuf, sizeof(typebuf), 0);
1023 if (error)
1024 return (error);
1025 d->name = typebuf;
1026 } else
1027 d->name = "loaded"; /* ??? */
1028 buf = malloc(d->fontheight * d->stride * d->numchars,
1029 M_DEVBUF, M_WAITOK);
1030 error = copyin(d->data, buf,
1031 d->fontheight * d->stride * d->numchars);
1032 if (error) {
1033 free(buf, M_DEVBUF);
1034 return (error);
1035 }
1036 d->data = buf;
1037 error =
1038 (*sc->sc_accessops->load_font)(sc->sc_accesscookie, 0, d);
1039 free(buf, M_DEVBUF);
1040 #undef d
1041 return (error);
1042 }
1043 return (EINVAL);
1044 }
1045
1046 int
1047 wsdisplaymmap(dev, offset, prot)
1048 dev_t dev;
1049 int offset; /* XXX */
1050 int prot;
1051 {
1052 #if NWSDISPLAY > 0
1053 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1054 struct wsscreen *scr;
1055
1056 if (ISWSDISPLAYCTL(dev))
1057 return (-1);
1058
1059 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1060
1061 if (!(scr->scr_flags & SCR_GRAPHICS))
1062 return (-1);
1063
1064 /* pass mmap to display */
1065 return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
1066 #else
1067 return (-1);
1068 #endif /* NWSDISPLAY > 0 */
1069 }
1070
1071 int
1072 wsdisplaypoll(dev, events, p)
1073 dev_t dev;
1074 int events;
1075 struct proc *p;
1076 {
1077 #if NWSDISPLAY > 0
1078 struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(dev)];
1079 struct wsscreen *scr;
1080
1081 if (ISWSDISPLAYCTL(dev))
1082 return (0);
1083
1084 scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
1085
1086 if (WSSCREEN_HAS_TTY(scr))
1087 return (ttpoll(dev, events, p));
1088 else
1089 return (0);
1090 #else
1091 return (0);
1092 #endif /* NWSDISPLAY > 0 */
1093 }
1094
1095 #if NWSDISPLAY > 0
1096 void
1097 wsdisplaystart(tp)
1098 register struct tty *tp;
1099 {
1100 struct wsdisplay_softc *sc;
1101 struct wsscreen *scr;
1102 register int s, n;
1103 u_char *buf;
1104
1105 s = spltty();
1106 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
1107 splx(s);
1108 return;
1109 }
1110 sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(tp->t_dev)];
1111 scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)];
1112 if (scr->scr_hold_screen) {
1113 tp->t_state |= TS_TIMEOUT;
1114 splx(s);
1115 return;
1116 }
1117 tp->t_state |= TS_BUSY;
1118 splx(s);
1119
1120 /*
1121 * Drain output from ring buffer.
1122 * The output will normally be in one contiguous chunk, but when the
1123 * ring wraps, it will be in two pieces.. one at the end of the ring,
1124 * the other at the start. For performance, rather than loop here,
1125 * we output one chunk, see if there's another one, and if so, output
1126 * it too.
1127 */
1128
1129 n = ndqb(&tp->t_outq, 0);
1130 buf = tp->t_outq.c_cf;
1131
1132 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1133 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1134 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1135 buf, n, 0);
1136 }
1137 ndflush(&tp->t_outq, n);
1138
1139 if ((n = ndqb(&tp->t_outq, 0)) > 0) {
1140 buf = tp->t_outq.c_cf;
1141
1142 if (!(scr->scr_flags & SCR_GRAPHICS)) {
1143 KASSERT(WSSCREEN_HAS_EMULATOR(scr));
1144 (*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
1145 buf, n, 0);
1146 }
1147 ndflush(&tp->t_outq, n);
1148 }
1149
1150 s = spltty();
1151 tp->t_state &= ~TS_BUSY;
1152 /* Come back if there's more to do */
1153 if (tp->t_outq.c_cc) {
1154 tp->t_state |= TS_TIMEOUT;
1155 timeout(ttrstrt, tp, (hz > 128) ? (hz / 128) : 1);
1156 }
1157 if (tp->t_outq.c_cc <= tp->t_lowat) {
1158 if (tp->t_state&TS_ASLEEP) {
1159 tp->t_state &= ~TS_ASLEEP;
1160 wakeup((caddr_t)&tp->t_outq);
1161 }
1162 selwakeup(&tp->t_wsel);
1163 }
1164 splx(s);
1165 }
1166 #endif /* NWSDISPLAY > 0 */
1167
1168 void
1169 wsdisplaystop(tp, flag)
1170 struct tty *tp;
1171 int flag;
1172 {
1173 int s;
1174
1175 s = spltty();
1176 if (ISSET(tp->t_state, TS_BUSY))
1177 if (!ISSET(tp->t_state, TS_TTSTOP))
1178 SET(tp->t_state, TS_FLUSH);
1179 splx(s);
1180 }
1181
1182 #if NWSDISPLAY > 0
1183 /* Set line parameters. */
1184 int
1185 wsdisplayparam(tp, t)
1186 struct tty *tp;
1187 struct termios *t;
1188 {
1189
1190 tp->t_ispeed = t->c_ispeed;
1191 tp->t_ospeed = t->c_ospeed;
1192 tp->t_cflag = t->c_cflag;
1193 return 0;
1194 }
1195 #endif /* NWSDISPLAY > 0 */
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 int
1599 wsdisplay_is_console(dv)
1600 struct device *dv;
1601 {
1602 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1603
1604 KASSERT(sc != NULL);
1605 return (sc->sc_isconsole);
1606 }
1607
1608 struct device *
1609 wsdisplay_kbd(dv)
1610 struct device *dv;
1611 {
1612 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1613
1614 KASSERT(sc != NULL);
1615 return (sc->sc_kbddv);
1616 }
1617
1618 void
1619 wsdisplay_set_kbd(dv, kbddv)
1620 struct device *dv, *kbddv;
1621 {
1622 struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
1623
1624 KASSERT(sc != NULL);
1625 if (sc->sc_kbddv) {
1626 /* disable old keyboard */
1627 wskbd_enable(sc->sc_kbddv, 0);
1628 }
1629 if (kbddv) {
1630 /* enable new keyboard */
1631 wskbd_enable(kbddv, 1);
1632 }
1633 sc->sc_kbddv = kbddv;
1634 }
1635
1636 /*
1637 * Console interface.
1638 */
1639 void
1640 wsdisplay_cnputc(dev, i)
1641 dev_t dev;
1642 int i;
1643 {
1644 struct wsscreen_internal *dc;
1645 char c = i;
1646
1647 if (!wsdisplay_console_initted)
1648 return;
1649
1650 if (wsdisplay_console_device != NULL &&
1651 (wsdisplay_console_device->sc_scr[0]->scr_flags & SCR_GRAPHICS))
1652 return;
1653
1654 dc = &wsdisplay_console_conf;
1655 (*dc->wsemul->output)(dc->wsemulcookie, &c, 1, 1);
1656 }
1657
1658 static int
1659 wsdisplay_getc_dummy(dev)
1660 dev_t dev;
1661 {
1662 /* panic? */
1663 return (0);
1664 }
1665
1666 static void
1667 wsdisplay_pollc_dummy(dev, on)
1668 dev_t dev;
1669 int on;
1670 {
1671 }
1672
1673 void
1674 wsdisplay_set_cons_kbd(get, poll)
1675 int (*get) __P((dev_t));
1676 void (*poll) __P((dev_t, int));
1677 {
1678 wsdisplay_cons.cn_getc = get;
1679 wsdisplay_cons.cn_pollc = poll;
1680 }
1681