Home | History | Annotate | Line # | Download | only in wscons
wsdisplay.c revision 1.3
      1 /* $NetBSD: wsdisplay.c,v 1.3 1998/04/07 13:43:17 hannken 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.3 1998/04/07 13:43:17 hannken 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 
     52 #include <dev/wscons/wsconsio.h>
     53 #include <dev/wscons/wsdisplayvar.h>
     54 #include <dev/wscons/wsemulvar.h>
     55 #include <dev/wscons/wscons_callbacks.h>
     56 #include <dev/cons.h>
     57 
     58 struct wsdisplay_conf {
     59 	const struct wsdisplay_emulops *emulops;
     60 	void	*emulcookie;
     61 
     62 	const struct wsscreen_descr *scrdata;
     63 
     64 	const struct wsemul_ops *wsemul;
     65 	void	*wsemulcookie;
     66 };
     67 
     68 struct wsscreen {
     69 	struct wsdisplay_conf *scr_dconf;
     70 
     71 	struct tty *scr_tty;
     72 	int	scr_open;			/* is it open? */
     73 	int	scr_graphics;			/* graphics mode? */
     74 	int	scr_hold_screen;		/* hold tty output */
     75 
     76 	struct wsdisplay_softc *sc;
     77 };
     78 
     79 struct wsscreen *wsscreen_attach __P((struct wsdisplay_softc *, int,
     80 				      const char *,
     81 				      const struct wsscreen_descr *, void *,
     82 				      int, int));
     83 
     84 #define WSDISPLAY_MAXSCREEN 8
     85 
     86 struct wsdisplay_softc {
     87 	struct device sc_dv;
     88 
     89 	const struct wsdisplay_accessops *sc_accessops;
     90 	void	*sc_accesscookie;
     91 
     92 	struct wsscreen *sc_scr[WSDISPLAY_MAXSCREEN];
     93 	struct wsscreen *sc_focus;
     94 
     95 	int	sc_isconsole;
     96 	struct device *sc_kbddv;
     97 };
     98 
     99 extern struct cfdriver wsdisplay_cd;
    100 
    101 /* Autoconfiguration definitions. */
    102 #ifdef __BROKEN_INDIRECT_CONFIG
    103 static int wsdisplay_emul_match __P((struct device *, void *, void *));
    104 #else
    105 static int wsdisplay_emul_match __P((struct device *, struct cfdata *,
    106 	    void *));
    107 #endif
    108 static void wsdisplay_emul_attach __P((struct device *, struct device *,
    109 	    void *));
    110 #ifdef __BROKEN_INDIRECT_CONFIG
    111 static int wsdisplay_noemul_match __P((struct device *, void *, void *));
    112 #else
    113 static int wsdisplay_noemul_match __P((struct device *, struct cfdata *,
    114 	    void *));
    115 #endif
    116 static void wsdisplay_noemul_attach __P((struct device *, struct device *,
    117 	    void *));
    118 
    119 struct cfattach wsdisplay_emul_ca = {
    120 	sizeof (struct wsdisplay_softc),
    121 	wsdisplay_emul_match,
    122 	wsdisplay_emul_attach,
    123 };
    124 
    125 struct cfattach wsdisplay_noemul_ca = {
    126 	sizeof (struct wsdisplay_softc),
    127 	wsdisplay_noemul_match,
    128 	wsdisplay_noemul_attach,
    129 };
    130 
    131 /* Exported tty- and cdevsw-related functions. */
    132 cdev_decl(wsdisplay);
    133 
    134 static void wsdisplaystart __P((struct tty *));
    135 static int wsdisplayparam __P((struct tty *, struct termios *));
    136 
    137 
    138 /* Internal macros, functions, and variables. */
    139 #define	SET(t, f)	(t) |= (f)
    140 #define	CLR(t, f)	(t) &= ~(f)
    141 #define	ISSET(t, f)	((t) & (f))
    142 
    143 #define	WSDISPLAYUNIT(dev)	(minor(dev) >> 8)
    144 #define	WSDISPLAYSCREEN(dev)	(minor(dev) & 0xff)
    145 #define	WSDISPLAYBURST		(OBUFSIZ - 1)
    146 
    147 #define	WSSCREEN_HAS_EMULATOR(scr)	((scr)->scr_dconf->emulops != NULL)
    148 #define	WSSCREEN_GRAPHICS_MODE(scr) \
    149 	    (WSSCREEN_HAS_EMULATOR(scr) && (scr)->scr_graphics != 0)
    150 
    151 static void wsdisplay_common_attach __P((struct wsdisplay_softc *sc,
    152 	    int console, struct wsscreen_list *,
    153 	    const struct wsdisplay_accessops *accessops,
    154 	    void *accesscookie));
    155 
    156 static int wsdisplay_internal_ioctl __P((struct wsdisplay_softc *sc,
    157 					 struct wsscreen *,
    158 					 u_long cmd, caddr_t data,
    159 					 int flag, struct proc *p));
    160 
    161 static int wsdisplay_console_initted;
    162 static struct wsdisplay_softc *wsdisplay_console_device;
    163 static struct wsdisplay_conf wsdisplay_console_conf;
    164 
    165 static int wsdisplay_getc_dummy __P((dev_t));
    166 static void wsdisplay_pollc_dummy __P((dev_t, int));
    167 
    168 static struct consdev wsdisplay_cons = {
    169 	NULL, NULL, wsdisplay_getc_dummy, wsdisplay_cnputc,
    170 	wsdisplay_pollc_dummy, NODEV, CN_NORMAL
    171 };
    172 
    173 struct wsscreen *wsscreen_attach(sc, console, emul, type, cookie, ccol, crow)
    174 	struct wsdisplay_softc *sc;
    175 	int console;
    176 	const char *emul;
    177 	const struct wsscreen_descr *type;
    178 	void *cookie;
    179 	int ccol, crow;
    180 {
    181 	struct wsdisplay_conf *dconf;
    182 	struct wsscreen *scr;
    183 
    184 	scr = malloc(sizeof(struct wsscreen), M_DEVBUF, M_WAITOK);
    185 	if (!scr)
    186 		return (NULL);
    187 
    188 	if (console) {
    189 		dconf = &wsdisplay_console_conf;
    190 		/*
    191 		 * If there's an emulation, tell it about the callback argument.
    192 		 * The other stuff is already there.
    193 		 */
    194 		if (dconf->wsemul != NULL)
    195 			(*dconf->wsemul->attach)(1, 0, 0, 0, 0, scr);
    196 	} else { /* not console */
    197 		dconf = malloc(sizeof(struct wsdisplay_conf),
    198 			       M_DEVBUF, M_NOWAIT);
    199 		dconf->emulops = type->textops;
    200 		dconf->emulcookie = cookie;
    201 		if (dconf->emulops) {
    202 			dconf->wsemul = wsemul_pick(emul);
    203 			dconf->wsemulcookie =
    204 			  (*dconf->wsemul->attach)(0, type, cookie,
    205 						   ccol, crow, scr);
    206 		} else
    207 			dconf->wsemul = NULL;
    208 		dconf->scrdata = type;
    209 	}
    210 
    211 	scr->scr_dconf = dconf;
    212 
    213 	/*
    214 	 * we allocate a tty even for those devices that don't have
    215 	 * emulators, so that e.g. 'getty' can be safely run on the
    216 	 * devices, and so that the interface provided by all wsdisplay
    217 	 * devices is uniform.  This is a bit of a hack.
    218 	 */
    219 	scr->scr_tty = ttymalloc();
    220 	tty_attach(scr->scr_tty);
    221 
    222 	scr->scr_open = 0;
    223 #if 0
    224 	scr->scr_graphics =
    225 	    type->textops ? WSDISPLAYIO_MODE_EMUL : WSDISPLAYIO_MODE_MAPPED;
    226 #else /* XXX again, for getty */
    227 	scr->scr_graphics = WSDISPLAYIO_MODE_EMUL;
    228 #endif
    229 	scr->scr_hold_screen = 0;
    230 	scr->sc = sc;
    231 	return (scr);
    232 }
    233 
    234 /*
    235  * Autoconfiguration functions.
    236  */
    237 int
    238 #ifdef __BROKEN_INDIRECT_CONFIG
    239 wsdisplay_emul_match(parent, matchv, aux)
    240 #else
    241 wsdisplay_emul_match(parent, match, aux)
    242 #endif
    243 	struct device *parent;
    244 #ifdef __BROKEN_INDIRECT_CONFIG
    245 	void *matchv;
    246 #else
    247 	struct cfdata *match;
    248 #endif
    249 	void *aux;
    250 {
    251 #ifdef __BROKEN_INDIRECT_CONFIG
    252 	struct cfdata *match = matchv;
    253 #endif
    254 	struct wsemuldisplaydev_attach_args *ap = aux;
    255 
    256 	if (match->wsemuldisplaydevcf_console !=
    257 	    WSEMULDISPLAYDEVCF_CONSOLE_UNK) {
    258 		/*
    259 		 * If console-ness of device specified, either match
    260 		 * exactly (at high priority), or fail.
    261 		 */
    262 		if (match->wsemuldisplaydevcf_console != 0 &&
    263 		    ap->console != 0)
    264 			return (10);
    265 		else
    266 			return (0);
    267 	}
    268 
    269 	/* If console-ness unspecified, it wins. */
    270 	return (1);
    271 }
    272 
    273 void
    274 wsdisplay_emul_attach(parent, self, aux)
    275 	struct device *parent, *self;
    276 	void *aux;
    277 {
    278 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
    279 	struct wsemuldisplaydev_attach_args *ap = aux;
    280 
    281 	wsdisplay_common_attach(sc, ap->console, ap->scrdata,
    282 				ap->accessops, ap->accesscookie);
    283 
    284 	if (ap->console) {
    285 		int maj;
    286 
    287 		/* locate the major number */
    288 		for (maj = 0; maj < nchrdev; maj++)
    289 			if (cdevsw[maj].d_open == wsdisplayopen)
    290 				break;
    291 
    292 		cn_tab->cn_dev = makedev(maj, self->dv_unit);
    293 	}
    294 }
    295 
    296 /* Print function (for parent devices). */
    297 int
    298 wsemuldisplaydevprint(aux, pnp)
    299 	void *aux;
    300 	const char *pnp;
    301 {
    302 #if 0 /* -Wunused */
    303 	struct wsemuldisplaydev_attach_args *ap = aux;
    304 #endif
    305 
    306 	if (pnp)
    307 		printf("wsdisplay at %s", pnp);
    308 #if 0 /* don't bother; it's ugly */
    309 	printf(" console %d", ap->console);
    310 #endif
    311 
    312 	return (UNCONF);
    313 }
    314 
    315 int
    316 wsdisplay_noemul_match(parent, match, aux)
    317 	struct device *parent;
    318 #ifdef __BROKEN_INDIRECT_CONFIG
    319 	void *match;
    320 #else
    321 	struct cfdata *match;
    322 #endif
    323 	void *aux;
    324 {
    325 #if 0 /* -Wunused */
    326 	struct wsdisplaydev_attach_args *ap = aux;
    327 #endif
    328 
    329 	/* Always match. */
    330 	return (1);
    331 }
    332 
    333 void
    334 wsdisplay_noemul_attach(parent, self, aux)
    335 	struct device *parent, *self;
    336 	void *aux;
    337 {
    338 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)self;
    339 	struct wsdisplaydev_attach_args *ap = aux;
    340 
    341 	wsdisplay_common_attach(sc, 0, NULL, ap->accessops, ap->accesscookie);
    342 }
    343 
    344 /* Print function (for parent devices). */
    345 int
    346 wsdisplaydevprint(aux, pnp)
    347 	void *aux;
    348 	const char *pnp;
    349 {
    350 #if 0 /* -Wunused */
    351 	struct wsdisplaydev_attach_args *ap = aux;
    352 #endif
    353 
    354 	if (pnp)
    355 		printf("wsdisplay at %s", pnp);
    356 
    357 	return (UNCONF);
    358 }
    359 
    360 static void
    361 wsdisplay_common_attach(sc, console, scrdata, accessops, accesscookie)
    362 	struct wsdisplay_softc *sc;
    363 	int console;
    364 	struct wsscreen_list *scrdata;
    365 	const struct wsdisplay_accessops *accessops;
    366 	void *accesscookie;
    367 {
    368 	const struct wsscreen_descr *scr;
    369 	int res, i = 0;
    370 
    371 	if (console) {
    372 		KASSERT(wsdisplay_console_initted);
    373 		KASSERT(wsdisplay_console_device == NULL);
    374 
    375 		sc->sc_scr[0] = wsscreen_attach(sc, 1, 0, 0, 0, 0, 0);
    376 		wsdisplay_console_device = sc;
    377 
    378 		printf(": console (%s, %s emulation)",
    379 		       wsdisplay_console_conf.scrdata->name,
    380 		       wsdisplay_console_conf.wsemul->name);
    381 
    382 		i++;
    383 	}
    384 
    385 	printf("\n");
    386 
    387 #if 1 /* XXX do this in ioctl() - user selects screen type and emulation */
    388 	KASSERT(scrdata->nscreens > 0);
    389 	scr = scrdata->screens[0];
    390 
    391 	for (; i < WSDISPLAY_MAXSCREEN; i++) {
    392 		void *cookie;
    393 		int ccol, crow;
    394 
    395 		res = ((*accessops->alloc_screen)(accesscookie, scr,
    396 						  &cookie, &ccol, &crow));
    397 		if (res)
    398 			break;
    399 
    400 		sc->sc_scr[i] = wsscreen_attach(sc, 0, 0, scr, cookie,
    401 						ccol, crow);
    402 	}
    403 #endif
    404 
    405 	sc->sc_focus = sc->sc_scr[0];
    406 
    407 	sc->sc_accessops = accessops;
    408 	sc->sc_accesscookie = accesscookie;
    409 
    410 	sc->sc_isconsole = console;
    411 	sc->sc_kbddv = NULL;
    412 
    413 	wscons_glue_set_callback();
    414 }
    415 
    416 void
    417 wsdisplay_cnattach(type, cookie, ccol, crow)
    418 	const struct wsscreen_descr *type;
    419 	void *cookie;
    420 	int ccol, crow;
    421 {
    422 	const struct wsemul_ops *wsemul;
    423 
    424 	KASSERT(!wsdisplay_console_initted);
    425 	KASSERT(type->nrows > 0);
    426 	KASSERT(type->ncols > 0);
    427 	KASSERT(crow < type->nrows);
    428 	KASSERT(ccol < type->ncols);
    429 
    430 	wsdisplay_console_conf.emulops = type->textops;
    431 	wsdisplay_console_conf.emulcookie = cookie;
    432 	wsdisplay_console_conf.scrdata = type;
    433 
    434 	wsemul = wsemul_pick(0); /* default */
    435 	wsdisplay_console_conf.wsemul = wsemul;
    436 	wsdisplay_console_conf.wsemulcookie = (*wsemul->cnattach)(type, cookie,
    437 								  ccol, crow);
    438 
    439 	cn_tab = &wsdisplay_cons;
    440 
    441 	wsdisplay_console_initted = 1;
    442 }
    443 
    444 /*
    445  * Tty and cdevsw functions.
    446  */
    447 int
    448 wsdisplayopen(dev, flag, mode, p)
    449 	dev_t dev;
    450 	int flag, mode;
    451 	struct proc *p;
    452 {
    453 	struct wsdisplay_softc *sc;
    454 	struct tty *tp;
    455 	int unit, newopen, error;
    456 	struct wsscreen *scr;
    457 
    458 	unit = WSDISPLAYUNIT(dev);
    459 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    460 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    461 		return (ENXIO);
    462 
    463 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    464 	if (!scr)
    465 		return (ENXIO);
    466 
    467 	tp = scr->scr_tty;
    468 	tp->t_oproc = wsdisplaystart;
    469 	tp->t_param = wsdisplayparam;
    470 	tp->t_dev = dev;
    471 	newopen = (tp->t_state & TS_ISOPEN) == 0;
    472 	if (newopen) {
    473 		ttychars(tp);
    474 		tp->t_iflag = TTYDEF_IFLAG;
    475 		tp->t_oflag = TTYDEF_OFLAG;
    476 		tp->t_cflag = TTYDEF_CFLAG;
    477 		tp->t_lflag = TTYDEF_LFLAG;
    478 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
    479 		wsdisplayparam(tp, &tp->t_termios);
    480 		ttsetwater(tp);
    481 	} else if ((tp->t_state & TS_XCLUDE) != 0 && p->p_ucred->cr_uid != 0)
    482 		return EBUSY;
    483 	tp->t_state |= TS_CARR_ON;
    484 
    485 	error = ((*linesw[tp->t_line].l_open)(dev, tp));
    486 	if (newopen && (error == 0)) {
    487 		scr->scr_open = 1;
    488 
    489 		/* set window sizes as appropriate, and reset the emulation */
    490 		tp->t_winsize.ws_row = scr->scr_dconf->scrdata->nrows;
    491 		tp->t_winsize.ws_col = scr->scr_dconf->scrdata->ncols;
    492 
    493 		/* wsdisplay_set_emulation() */
    494 	}
    495 	return (error);
    496 }
    497 
    498 int
    499 wsdisplayclose(dev, flag, mode, p)
    500 	dev_t dev;
    501 	int flag, mode;
    502 	struct proc *p;
    503 {
    504 	struct wsdisplay_softc *sc;
    505 	struct tty *tp;
    506 	int unit;
    507 	struct wsscreen *scr;
    508 
    509 	unit = WSDISPLAYUNIT(dev);
    510 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    511 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    512 		return (ENXIO);
    513 
    514 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    515 
    516 	if (WSSCREEN_HAS_EMULATOR(scr)) {
    517 		if (scr->scr_hold_screen) {
    518 			int s;
    519 
    520 			/* XXX RESET KEYBOARD LEDS, etc. */
    521 			s = spltty();	/* avoid conflict with keyboard */
    522 			wsdisplay_kbdholdscreen((struct device *)sc, 0);
    523 			splx(s);
    524 		}
    525 		tp = scr->scr_tty;
    526 		(*linesw[tp->t_line].l_close)(tp, flag);
    527 		ttyclose(tp);
    528 	}
    529 	/* XXX RESET EMULATOR? */
    530 #if 0
    531 	scr->scr_graphics =
    532 	    wsemul ? WSDISPLAYIO_MODE_EMUL : WSDISPLAYIO_MODE_MAPPED;
    533 #else /* XXX for getty */
    534 	scr->scr_graphics = WSDISPLAYIO_MODE_EMUL;
    535 #endif
    536 	if (sc->sc_kbddv != NULL)
    537 		wskbd_set_translation(sc->sc_kbddv,
    538 		    scr->scr_graphics == WSDISPLAYIO_MODE_EMUL);
    539 	scr->scr_open = 0;
    540 
    541 	return (0);
    542 }
    543 
    544 int
    545 wsdisplayread(dev, uio, flag)
    546 	dev_t dev;
    547 	struct uio *uio;
    548 	int flag;
    549 {
    550 	struct wsdisplay_softc *sc;
    551 	struct tty *tp;
    552 	int unit;
    553 	struct wsscreen *scr;
    554 
    555 	unit = WSDISPLAYUNIT(dev);
    556 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    557 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    558 		return (ENXIO);
    559 
    560 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    561 
    562 	if (WSSCREEN_GRAPHICS_MODE(scr))
    563 		return (ENODEV);
    564 
    565 	tp = scr->scr_tty;
    566 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
    567 }
    568 
    569 int
    570 wsdisplaywrite(dev, uio, flag)
    571 	dev_t dev;
    572 	struct uio *uio;
    573 	int flag;
    574 {
    575 	struct wsdisplay_softc *sc;
    576 	struct tty *tp;
    577 	int unit;
    578 	struct wsscreen *scr;
    579 
    580 	unit = WSDISPLAYUNIT(dev);
    581 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    582 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    583 		return (ENXIO);
    584 
    585 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    586 
    587 	if (WSSCREEN_GRAPHICS_MODE(scr))
    588 		return (ENODEV);
    589 
    590 	tp = scr->scr_tty;
    591 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    592 }
    593 
    594 struct tty *
    595 wsdisplaytty(dev)
    596 	dev_t dev;
    597 {
    598 	struct wsdisplay_softc *sc;
    599 	int unit;
    600 	struct wsscreen *scr;
    601 
    602 	unit = WSDISPLAYUNIT(dev);
    603 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    604 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    605 		return (NULL);
    606 
    607 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    608 
    609 	return (scr->scr_tty);
    610 }
    611 
    612 int
    613 wsdisplayioctl(dev, cmd, data, flag, p)
    614 	dev_t dev;
    615 	u_long cmd;
    616 	caddr_t data;
    617 	int flag;
    618 	struct proc *p;
    619 {
    620 	struct wsdisplay_softc *sc;
    621 	struct tty *tp;
    622 	int unit, error;
    623 	struct wsscreen *scr;
    624 
    625 	unit = WSDISPLAYUNIT(dev);
    626 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    627 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    628 		return (ENXIO);
    629 
    630 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    631 
    632 	if (!WSSCREEN_GRAPHICS_MODE(scr)) {
    633 		tp = scr->scr_tty;
    634 
    635 /* printf("disc\n"); */
    636 		/* do the line discipline ioctls first */
    637 		error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    638 		if (error >= 0)
    639 			return error;
    640 
    641 /* printf("tty\n"); */
    642 		/* then the tty ioctls */
    643 		error = ttioctl(tp, cmd, data, flag, p);
    644 		if (error >= 0)
    645 			return error;
    646 	}
    647 
    648 	error = wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p);
    649 	return (error != -1 ? error : ENOTTY);
    650 }
    651 
    652 int
    653 wsdisplay_internal_ioctl(sc, scr, cmd, data, flag, p)
    654 	struct wsdisplay_softc *sc;
    655 	struct wsscreen *scr;
    656 	u_long cmd;
    657 	caddr_t data;
    658 	int flag;
    659 	struct proc *p;
    660 {
    661 	int error, flush;
    662 	void *buf;
    663 
    664 	if (!WSSCREEN_GRAPHICS_MODE(scr) && sc->sc_kbddv != NULL) {
    665 		/* check ioctls for keyboard */
    666 /* printf("kbdcallback\n"); */
    667 		error = wskbd_displayioctl(sc->sc_kbddv, cmd, data, flag, p);
    668 		if (error >= 0)
    669 			return error;
    670 	}
    671 
    672 /* printf("display\n"); */
    673 	switch (cmd) {
    674 	case WSDISPLAYIO_GMODE:
    675 		*(u_int *)data = scr->scr_graphics;
    676 		return (0);
    677 
    678 	case WSDISPLAYIO_SMODE:
    679 		if (*(u_int *)data != WSDISPLAYIO_MODE_EMUL &&
    680 		    *(u_int *)data != WSDISPLAYIO_MODE_MAPPED)
    681 			return (EINVAL);
    682 		flush = (scr->scr_graphics != *(u_int *)data);
    683 		scr->scr_graphics = *(u_int *)data;
    684 		if (sc->sc_kbddv != NULL)
    685 			wskbd_set_translation(sc->sc_kbddv,
    686 			    scr->scr_graphics == WSDISPLAYIO_MODE_EMUL);
    687 		if (flush)
    688 			ttyflush(scr->scr_tty, FREAD | FWRITE);
    689 		return (0);
    690 
    691 	case WSDISPLAYIO_SFONT:
    692 #define d ((struct wsdisplay_font *)data)
    693 		if (d->fontheight != scr->scr_dconf->scrdata->fontheight ||
    694 		    d->fontwidth != scr->scr_dconf->scrdata->fontwidth)
    695 			return (EINVAL);
    696 		buf = malloc(d->fontheight * d->stride * d->numchars,
    697 			     M_DEVBUF, M_WAITOK);
    698 		error = copyin(d->data, buf,
    699 			       d->fontheight * d->stride * d->numchars);
    700 		if (error) {
    701 			free(buf, M_DEVBUF);
    702 			return (error);
    703 		}
    704 		error =
    705 		  (*sc->sc_accessops->load_font)(sc->sc_accesscookie,
    706 						 scr->scr_dconf->emulcookie,
    707 						 d->firstchar, d->numchars,
    708 						 d->stride, buf);
    709 		free(buf, M_DEVBUF);
    710 #undef d
    711 		return (error);
    712 	}
    713 
    714 	/* check ioctls for display */
    715 	return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
    716 	    flag, p));
    717 }
    718 
    719 int
    720 wsdisplaymmap(dev, offset, prot)
    721 	dev_t dev;
    722 	int offset;		/* XXX */
    723 	int prot;
    724 {
    725 	struct wsdisplay_softc *sc;
    726 	int unit;
    727 
    728 	unit = WSDISPLAYUNIT(dev);
    729 	if (unit >= wsdisplay_cd.cd_ndevs ||	/* make sure it was attached */
    730 	    (sc = wsdisplay_cd.cd_devs[unit]) == NULL)
    731 		return (ENXIO);
    732 #if 0
    733 	if (!WSDISPLAY_GRAPHICS_MODE(sc) && 0)
    734 		return (-1);
    735 #endif
    736 	/* pass mmap to display */
    737 	return ((*sc->sc_accessops->mmap)(sc->sc_accesscookie, offset, prot));
    738 }
    739 
    740 int
    741 wsdisplaypoll(dev, events, p)
    742 	dev_t dev;
    743 	int events;
    744 	struct proc *p;
    745 {
    746 	struct wsdisplay_softc *sc = wsdisplay_cd.cd_devs[minor(dev)];
    747 	struct wsscreen *scr;
    748 
    749 	scr = sc->sc_scr[WSDISPLAYSCREEN(dev)];
    750 
    751 	if (WSSCREEN_GRAPHICS_MODE(scr))
    752 		return (0);
    753 	else
    754 		return (ttpoll(dev, events, p));
    755 }
    756 
    757 void
    758 wsdisplaystart(tp)
    759 	register struct tty *tp;
    760 {
    761 	struct wsdisplay_softc *sc;
    762 	struct wsscreen *scr;
    763 	register int s, n;
    764 	u_char buf[WSDISPLAYBURST];
    765 
    766 	s = spltty();
    767 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
    768 		splx(s);
    769 		return;
    770 	}
    771 	sc = wsdisplay_cd.cd_devs[WSDISPLAYUNIT(tp->t_dev)];
    772 	scr = sc->sc_scr[WSDISPLAYSCREEN(tp->t_dev)];
    773 	if (scr->scr_hold_screen) {
    774 		tp->t_state |= TS_TIMEOUT;
    775 		splx(s);
    776 		return;
    777 	}
    778 	tp->t_state |= TS_BUSY;
    779 	splx(s);
    780 
    781 	n = q_to_b(&tp->t_outq, buf, sizeof(buf));
    782 
    783 	if (WSSCREEN_HAS_EMULATOR(scr))
    784 		(*scr->scr_dconf->wsemul->output)(scr->scr_dconf->wsemulcookie,
    785 		    buf, n);
    786 
    787 	s = spltty();
    788 	tp->t_state &= ~TS_BUSY;
    789 	/* Come back if there's more to do */
    790 	if (tp->t_outq.c_cc) {
    791 		tp->t_state |= TS_TIMEOUT;
    792 		timeout(ttrstrt, tp, (hz > 128) ? (hz / 128) : 1);
    793 	}
    794 	if (tp->t_outq.c_cc <= tp->t_lowat) {
    795 		if (tp->t_state&TS_ASLEEP) {
    796 			tp->t_state &= ~TS_ASLEEP;
    797 			wakeup((caddr_t)&tp->t_outq);
    798 		}
    799 		selwakeup(&tp->t_wsel);
    800 	}
    801 	splx(s);
    802 }
    803 
    804 void
    805 wsdisplaystop(tp, flag)
    806 	struct tty *tp;
    807 	int flag;
    808 {
    809 	int s;
    810 
    811 	s = spltty();
    812 	if (ISSET(tp->t_state, TS_BUSY))
    813 		if (!ISSET(tp->t_state, TS_TTSTOP))
    814 			SET(tp->t_state, TS_FLUSH);
    815 	splx(s);
    816 }
    817 
    818 /* Set line parameters. */
    819 int
    820 wsdisplayparam(tp, t)
    821 	struct tty *tp;
    822 	struct termios *t;
    823 {
    824 
    825 	tp->t_ispeed = t->c_ispeed;
    826 	tp->t_ospeed = t->c_ospeed;
    827 	tp->t_cflag = t->c_cflag;
    828 	return 0;
    829 }
    830 
    831 /*
    832  * Callbacks for the emulation code.
    833  */
    834 void
    835 wsdisplay_emulbell(v)
    836 	void *v;
    837 {
    838 	struct wsscreen *scr = v;
    839 
    840 	if (scr == NULL)		/* console, before real attach */
    841 		return;
    842 
    843 	if (WSSCREEN_GRAPHICS_MODE(scr)) /* can this happen? */
    844 		return;
    845 
    846 	(void) wsdisplay_internal_ioctl(scr->sc, scr, WSKBDIO_BELL, NULL,
    847 					FWRITE, NULL);
    848 }
    849 
    850 void
    851 wsdisplay_emulinput(v, data, count)
    852 	void *v;
    853 	const u_char *data;
    854 	u_int count;
    855 {
    856 	struct wsscreen *scr = v;
    857 	struct tty *tp;
    858 
    859 	if (v == NULL)			/* console, before real attach */
    860 		return;
    861 
    862 	if (WSSCREEN_GRAPHICS_MODE(scr)) /* XXX can't happen */
    863 		return;
    864 
    865 	tp = scr->scr_tty;
    866 	while (count-- > 0)
    867 		(*linesw[tp->t_line].l_rint)(*data++, tp);
    868 };
    869 
    870 /*
    871  * Calls from the keyboard interface.
    872  */
    873 void
    874 wsdisplay_kbdinput(dev, data, count)
    875 	struct device *dev;
    876 	const u_char *data;
    877 	u_int count;
    878 {
    879 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
    880 	struct wsscreen *scr;
    881 	struct tty *tp;
    882 
    883 	KASSERT(sc != NULL);
    884 	scr = sc->sc_focus;
    885 
    886 	KASSERT(scr != NULL);
    887 
    888 	if (WSSCREEN_GRAPHICS_MODE(scr))
    889 		return;
    890 
    891 	tp = scr->scr_tty;
    892 	while (count-- > 0)
    893 		(*linesw[tp->t_line].l_rint)(*data++, tp);
    894 }
    895 
    896 int
    897 wsdisplay_switch(dev, no)
    898 	struct device *dev;
    899 	int no;
    900 {
    901 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
    902 	struct wsscreen *ws;
    903 	int s;
    904 
    905 	if (no < 0 || no >= WSDISPLAY_MAXSCREEN)
    906 		return (ENXIO);
    907 
    908 	ws = sc->sc_scr[no];
    909 	if (!ws)
    910 		return (ENXIO);
    911 
    912 	s = spltty();
    913 
    914 	(*sc->sc_accessops->show_screen)(sc->sc_accesscookie,
    915 					 ws->scr_dconf->emulcookie);
    916 	sc->sc_focus = ws;
    917 	/* keyboard state??? */
    918 
    919 	splx(s);
    920 
    921 	return (0);
    922 }
    923 
    924 void
    925 wsdisplay_kbdholdscreen(dev, hold)
    926 	struct device *dev;
    927 	int hold;
    928 {
    929 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dev;
    930 	struct wsscreen *scr;
    931 
    932 	scr = sc->sc_focus;
    933 
    934 	if (hold)
    935 		scr->scr_hold_screen = 1;
    936 	else {
    937 		scr->scr_hold_screen = 0;
    938 		timeout(ttrstrt, scr->scr_tty, 0);	/* "immediate" */
    939 	}
    940 }
    941 
    942 /*
    943  * Calls from the glue code.
    944  */
    945 int
    946 wsdisplay_is_console(dv)
    947 	struct device *dv;
    948 {
    949 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
    950 
    951 	KASSERT(sc != NULL);
    952 	return (sc->sc_isconsole);
    953 }
    954 
    955 int
    956 wsdisplay_has_emulator(dv)
    957 	struct device *dv;
    958 {
    959 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
    960 	struct wsscreen *scr;
    961 
    962 	scr = sc->sc_focus; /* ??? */
    963 
    964 	KASSERT(sc != NULL);
    965 	KASSERT(scr != NULL);
    966 	return (WSSCREEN_HAS_EMULATOR(scr)); /* XXX XXX */
    967 }
    968 
    969 struct device *
    970 wsdisplay_kbd(dv)
    971 	struct device *dv;
    972 {
    973 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
    974 
    975 	KASSERT(sc != NULL);
    976 	return (sc->sc_kbddv);
    977 }
    978 
    979 void
    980 wsdisplay_set_kbd(dv, kbddv)
    981 	struct device *dv, *kbddv;
    982 {
    983 	struct wsdisplay_softc *sc = (struct wsdisplay_softc *)dv;
    984 
    985 	KASSERT(sc != NULL);
    986 	sc->sc_kbddv = kbddv;
    987 }
    988 
    989 /*
    990  * Console interface.
    991  */
    992 void
    993 wsdisplay_cnputc(dev, i)
    994 	dev_t dev;
    995 	int i;
    996 {
    997 	struct wsdisplay_conf *dc;
    998 	char c = i;
    999 
   1000 	if (!wsdisplay_console_initted)
   1001 		return;
   1002 
   1003 	if (wsdisplay_console_device != NULL &&
   1004 	    WSSCREEN_GRAPHICS_MODE(wsdisplay_console_device->sc_scr[0]))
   1005 		return;
   1006 
   1007 	dc = &wsdisplay_console_conf;
   1008 	(*dc->wsemul->output)(dc->wsemulcookie, &c, 1);
   1009 }
   1010 
   1011 static int
   1012 wsdisplay_getc_dummy(dev)
   1013 	dev_t dev;
   1014 {
   1015 	/* panic? */
   1016 	return (0);
   1017 }
   1018 
   1019 static void
   1020 wsdisplay_pollc_dummy(dev, on)
   1021 	dev_t dev;
   1022 	int on;
   1023 {
   1024 }
   1025 
   1026 void
   1027 wsdisplay_set_cons_kbd(get, poll)
   1028 	int (*get) __P((dev_t));
   1029 	void (*poll) __P((dev_t, int));
   1030 {
   1031 	wsdisplay_cons.cn_getc = get;
   1032 	wsdisplay_cons.cn_pollc = poll;
   1033 }
   1034