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