Home | History | Annotate | Line # | Download | only in wscons
wsmux.c revision 1.2
      1 /*	$NetBSD: wsmux.c,v 1.2 1999/07/30 20:52:28 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Author: Lennart Augustsson <augustss (at) carlstedt.se>
      8  *         Carlstedt Research & Technology
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include "wsmux.h"
     40 #include "wsdisplay.h"
     41 #include "wskbd.h"
     42 
     43 #if NWSMUX > 0 || (NWSDISPLAY > 0 && NWSKBD > 0)
     44 
     45 /*
     46  * wscons mux device.
     47  *
     48  * The mux device is a collection of real mice and keyboards and acts as
     49  * a merge point for all the events from the different real devices.
     50  */
     51 
     52 #include <sys/param.h>
     53 #include <sys/conf.h>
     54 #include <sys/ioctl.h>
     55 #include <sys/fcntl.h>
     56 #include <sys/kernel.h>
     57 #include <sys/malloc.h>
     58 #include <sys/proc.h>
     59 #include <sys/queue.h>
     60 #include <sys/syslog.h>
     61 #include <sys/systm.h>
     62 #include <sys/tty.h>
     63 #include <sys/signalvar.h>
     64 #include <sys/device.h>
     65 
     66 #include "opt_wsdisplay_compat.h"
     67 
     68 #include <dev/wscons/wsconsio.h>
     69 #include <dev/wscons/wseventvar.h>
     70 #include <dev/wscons/wscons_callbacks.h>
     71 #include <dev/wscons/wsmuxvar.h>
     72 
     73 #ifdef WSMUX_DEBUG
     74 #define DPRINTF(x)	if (wsmuxdebug) printf x
     75 int	wsmuxdebug = 0;
     76 #else
     77 #define DPRINTF(x)
     78 #endif
     79 
     80 struct wsplink {
     81 	LIST_ENTRY(wsplink) next;
     82 	int type;
     83 	struct wsmux_softc *mux; /* our mux device */
     84 	/* The rest of the fields reflect a value in the multiplexee. */
     85 	struct device *sc;	/* softc */
     86 	struct wseventvar *sc_mevents; /* event var */
     87 	struct wsmux_softc **sc_muxp; /* pointer to us */
     88 	struct wsmuxops *sc_ops;
     89 };
     90 
     91 int wsmuxdoclose __P((struct device *, int, int, struct proc *));
     92 int wsmux_set_display __P((struct device *, struct wsmux_softc *));
     93 
     94 #if NWSMUX > 0
     95 cdev_decl(wsmux);
     96 
     97 void wsmuxattach __P((int));
     98 
     99 struct wsmuxops wsmux_muxops = {
    100 	wsmuxopen, wsmuxdoclose, wsmuxdoioctl, wsmux_displayioctl,
    101 	wsmux_set_display
    102 };
    103 
    104 void wsmux_setmax __P((int n));
    105 
    106 int nwsmux = 0;
    107 struct wsmux_softc **wsmuxdevs;
    108 
    109 void
    110 wsmux_setmax(n)
    111 	int n;
    112 {
    113 	int i;
    114 
    115 	if (n >= nwsmux) {
    116 		i = nwsmux;
    117 		nwsmux = n + 1;
    118 		if (nwsmux != 0)
    119 			wsmuxdevs = realloc(wsmuxdevs,
    120 					    nwsmux * sizeof (*wsmuxdevs),
    121 					    M_DEVBUF, M_NOWAIT);
    122 		else
    123 			wsmuxdevs = malloc(nwsmux * sizeof (*wsmuxdevs),
    124 					   M_DEVBUF, M_NOWAIT);
    125 		if (wsmuxdevs == 0)
    126 			panic("wsmux_setmax: no memory\n");
    127 		for (; i < nwsmux; i++)
    128 			wsmuxdevs[i] = 0;
    129 	}
    130 }
    131 
    132 /* From upper level */
    133 void
    134 wsmuxattach(n)
    135 	int n;
    136 {
    137 	int i;
    138 
    139 	wsmux_setmax(n);	/* Make sure we have room for all muxes. */
    140 
    141 	/* Make sure all muxes are there. */
    142 	for (i = 0; i < nwsmux; i++)
    143 		if (!wsmuxdevs[i])
    144 			wsmuxdevs[i] = wsmux_create("wsmux", i);
    145 }
    146 
    147 /* From mouse or keyboard. */
    148 void
    149 wsmux_attach(n, type, dsc, ev, psp, ops)
    150 	int n;
    151 	int type;
    152         struct device *dsc;
    153 	struct wseventvar *ev;
    154 	struct wsmux_softc **psp;
    155 	struct wsmuxops *ops;
    156 {
    157 	struct wsmux_softc *sc;
    158 	int error;
    159 
    160 	DPRINTF(("wsmux_attach: n=%d\n", n));
    161 	wsmux_setmax(n);
    162 	sc = wsmuxdevs[n];
    163 	if (sc == 0) {
    164 		sc = wsmux_create("wsmux", n);
    165 		if (sc == 0) {
    166 			printf("wsmux: attach out of memory\n");
    167 			return;
    168 		}
    169 		wsmuxdevs[n] = sc;
    170 	}
    171 	error = wsmux_attach_sc(sc, type, dsc, ev, psp, ops);
    172 	if (error)
    173 		printf("wsmux_attach: error=%d\n", error);
    174 }
    175 
    176 /* From mouse or keyboard. */
    177 void
    178 wsmux_detach(n, dsc)
    179 	int n;
    180         struct device *dsc;
    181 {
    182 #ifdef DIAGNOSTIC
    183 	int error;
    184 
    185 	if (n >= nwsmux || n < 0) {
    186 		printf("wsmux_detach: detach is out of range\n");
    187 		return;
    188 	}
    189 	if ((error = wsmux_detach_sc(wsmuxdevs[n], dsc)))
    190 		printf("wsmux_detach: error=%d\n", error);
    191 #else
    192 	(void)wsmux_detach_sc(wsmuxdevs[n], dsc);
    193 #endif
    194 }
    195 
    196 int
    197 wsmuxopen(dev, flags, mode, p)
    198 	dev_t dev;
    199 	int flags, mode;
    200 	struct proc *p;
    201 {
    202 	struct wsmux_softc *sc;
    203 	struct wsplink *m;
    204 	int unit, error, nopen, lasterror;
    205 
    206 	unit = minor(dev);
    207 	if (unit >= nwsmux ||	/* make sure it was attached */
    208 	    (sc = wsmuxdevs[unit]) == NULL)
    209 		return (ENXIO);
    210 
    211 	DPRINTF(("wsmuxopen: %s: sc=%p\n", sc->sc_dv.dv_xname, sc));
    212 	if (!(flags & FREAD)) {
    213 		/* Not opening for read, only ioctl is available. */
    214 		return (0);
    215 	}
    216 
    217 	if (sc->sc_events.io)
    218 		return (EBUSY);
    219 
    220 	sc->sc_events.io = p;
    221 	sc->sc_flags = flags;
    222 	sc->sc_mode = mode;
    223 	sc->sc_p = p;
    224 	wsevent_init(&sc->sc_events);		/* may cause sleep */
    225 
    226 	nopen = 0;
    227 	lasterror = 0;
    228 	for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
    229 		if (!m->sc_mevents->io && !*m->sc_muxp) {
    230 			DPRINTF(("wsmuxopen: %s: m=%p dev=%s\n",
    231 				 sc->sc_dv.dv_xname, m, m->sc->dv_xname));
    232 			error = m->sc_ops->dopen(makedev(0, m->sc->dv_unit),
    233 						 flags, mode, p);
    234 			if (error) {
    235 				/* Ignore opens that fail */
    236 				lasterror = error;
    237 				DPRINTF(("wsmuxopen: open failed %d\n",
    238 					 error));
    239 			} else {
    240 				nopen++;
    241 				*m->sc_muxp = sc;
    242 			}
    243 		}
    244 	}
    245 
    246 	if (nopen == 0 && lasterror != 0) {
    247 		wsevent_fini(&sc->sc_events);
    248 		sc->sc_events.io = NULL;
    249 		return (lasterror);
    250 	}
    251 
    252 	return (0);
    253 }
    254 
    255 int
    256 wsmuxclose(dev, flags, mode, p)
    257 	dev_t dev;
    258 	int flags, mode;
    259 	struct proc *p;
    260 {
    261 	return wsmuxdoclose(&wsmuxdevs[minor(dev)]->sc_dv, flags, mode, p);
    262 }
    263 
    264 int
    265 wsmuxread(dev, uio, flags)
    266 	dev_t dev;
    267 	struct uio *uio;
    268 	int flags;
    269 {
    270 	struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
    271 
    272 	if (!sc->sc_events.io)
    273 		return (EACCES);
    274 
    275 	return (wsevent_read(&sc->sc_events, uio, flags));
    276 }
    277 
    278 int
    279 wsmuxioctl(dev, cmd, data, flag, p)
    280 	dev_t dev;
    281 	u_long cmd;
    282 	caddr_t data;
    283 	int flag;
    284 	struct proc *p;
    285 {
    286 	return wsmuxdoioctl(&wsmuxdevs[minor(dev)]->sc_dv, cmd, data, flag, p);
    287 }
    288 
    289 int
    290 wsmuxpoll(dev, events, p)
    291 	dev_t dev;
    292 	int events;
    293 	struct proc *p;
    294 {
    295 	struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
    296 
    297 	if (!sc->sc_events.io)
    298 		return (EACCES);
    299 
    300 	return (wsevent_poll(&sc->sc_events, events, p));
    301 }
    302 
    303 int
    304 wsmux_add_mux(unit, muxsc)
    305 	int unit;
    306 	struct wsmux_softc *muxsc;
    307 {
    308 	struct wsmux_softc *sc, *m;
    309 
    310 	if (unit < 0 || unit >= nwsmux || (sc = wsmuxdevs[unit]) == NULL)
    311 		return (ENXIO);
    312 
    313 	DPRINTF(("wsmux_add_mux: %s to %s\n", sc->sc_dv.dv_xname,
    314 		 muxsc->sc_dv.dv_xname));
    315 
    316 	if (sc->sc_mux || sc->sc_events.io)
    317 		return (EBUSY);
    318 
    319 	/* The mux we are adding must not be an ancestor of it. */
    320 	for (m = muxsc->sc_mux; m; m = m->sc_mux)
    321 		if (m == sc)
    322 			return (EINVAL);
    323 
    324 	return (wsmux_attach_sc(muxsc, WSMUX_MUX, &sc->sc_dv, &sc->sc_events,
    325 				&sc->sc_mux, &wsmux_muxops));
    326 }
    327 
    328 int
    329 wsmux_rem_mux(unit, muxsc)
    330 	int unit;
    331 	struct wsmux_softc *muxsc;
    332 {
    333 	struct wsmux_softc *sc;
    334 
    335 	if (unit < 0 || unit >= nwsmux || (sc = wsmuxdevs[unit]) == NULL)
    336 		return (ENXIO);
    337 
    338 	DPRINTF(("wsmux_rem_mux: %s from %s\n", sc->sc_dv.dv_xname,
    339 		 muxsc->sc_dv.dv_xname));
    340 
    341 	return (wsmux_detach_sc(muxsc, &sc->sc_dv));
    342 }
    343 
    344 #endif /* NWSMUX > 0 */
    345 
    346 struct wsmux_softc *
    347 wsmux_create(name, unit)
    348 	const char *name;
    349 	int unit;
    350 {
    351 	struct wsmux_softc *sc;
    352 
    353 	DPRINTF(("wsmux_create: allocating\n"));
    354 	sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
    355 	if (!sc)
    356 		return (0);
    357 	memset(sc, 0, sizeof *sc);
    358 	LIST_INIT(&sc->sc_reals);
    359 	snprintf(sc->sc_dv.dv_xname, sizeof sc->sc_dv.dv_xname,
    360 		 "%s%d", name, unit);
    361 	sc->sc_dv.dv_unit = unit;
    362 	return (sc);
    363 }
    364 
    365 int
    366 wsmux_attach_sc(sc, type, dsc, ev, psp, ops)
    367 	struct wsmux_softc *sc;
    368 	int type;
    369         struct device *dsc;
    370 	struct wseventvar *ev;
    371 	struct wsmux_softc **psp;
    372 	struct wsmuxops *ops;
    373 {
    374 	struct wsplink *m;
    375 	int error;
    376 
    377 	DPRINTF(("wsmux_attach_sc: %s: type=%d dsc=%p, *psp=%p\n",
    378 		 sc->sc_dv.dv_xname, type, dsc, *psp));
    379 	m = malloc(sizeof *m, M_DEVBUF, M_NOWAIT);
    380 	if (m == 0)
    381 		return (ENOMEM);
    382 	m->type = type;
    383 	m->mux = sc;
    384 	m->sc = dsc;
    385 	m->sc_mevents = ev;
    386 	m->sc_muxp = psp;
    387 	m->sc_ops = ops;
    388 	LIST_INSERT_HEAD(&sc->sc_reals, m, next);
    389 
    390 	if (sc->sc_displaydv) {
    391 		/* This is a display mux, so attach the new device to it. */
    392 		DPRINTF(("wsmux_attach_sc: %s: set display %p\n",
    393 			 sc->sc_dv.dv_xname, sc->sc_displaydv));
    394 		error = 0;
    395 		if (m->sc_ops->dsetdisplay) {
    396 			error = m->sc_ops->dsetdisplay(m->sc, sc);
    397 			/* Ignore that the console already has a display. */
    398 			if (error == EBUSY)
    399 				error = 0;
    400 			if (!error) {
    401 				*m->sc_muxp = sc;
    402 #ifdef WSDISPLAY_COMPAT_RAWKBD
    403 				DPRINTF(("wsmux_attach_sc: on %s set rawkbd=%d\n",
    404 					 m->sc->dv_xname, sc->sc_rawkbd));
    405 				(void)m->sc_ops->dioctl(m->sc,
    406 					     WSKBDIO_SETMODE,
    407 					     (caddr_t)&sc->sc_rawkbd,
    408 					     0, 0);
    409 #endif
    410 			}
    411 		}
    412 	} else if (sc->sc_events.io) {
    413 		/* Mux is open, so open the new subdevice */
    414 		DPRINTF(("wsmux_attach_sc: %s: calling open of %s\n",
    415 			 sc->sc_dv.dv_xname, m->sc->dv_xname));
    416 		/* mux already open, join in */
    417 		error = m->sc_ops->dopen(makedev(0, m->sc->dv_unit),
    418 					 sc->sc_flags, sc->sc_mode, sc->sc_p);
    419 		if (!error)
    420 			*m->sc_muxp = sc;
    421 	} else {
    422 		DPRINTF(("wsmux_attach_sc: %s not open\n",
    423 			 sc->sc_dv.dv_xname));
    424 		error = 0;
    425 	}
    426 	DPRINTF(("wsmux_attach_sc: done sc=%p psp=%p *psp=%p\n",
    427 		 sc, psp, *psp));
    428 
    429 	return (error);
    430 }
    431 
    432 int
    433 wsmux_detach_sc(sc, dsc)
    434 	struct wsmux_softc *sc;
    435         struct device *dsc;
    436 {
    437 	struct wsplink *m;
    438 	int error;
    439 
    440 	DPRINTF(("wsmux_detach_sc: %s: dsc=%p\n", sc->sc_dv.dv_xname, dsc));
    441 #ifdef DIAGNOSTIC
    442 	if (sc == 0) {
    443 		printf("wsmux_detach_sc: not allocated\n");
    444 		return (ENXIO);
    445 	}
    446 #endif
    447 
    448 	for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
    449 		if (m->sc == dsc)
    450 			break;
    451 	}
    452 #ifdef DIAGNOSTIC
    453 	if (!m) {
    454 		printf("wsmux_detach_sc: not found\n");
    455 		return (ENXIO);
    456 	}
    457 #endif
    458 	if (sc->sc_displaydv) {
    459 		if (m->sc_ops->dsetdisplay)
    460 			error = m->sc_ops->dsetdisplay(m->sc, 0);
    461 		if (error)
    462 			return (error);
    463 		*m->sc_muxp = 0;
    464 	} else if (*m->sc_muxp) {
    465 		DPRINTF(("wsmux_detach_sc: close\n"));
    466 		/* mux device is open, so close multiplexee */
    467 		m->sc_ops->dclose(m->sc, FREAD, 0, 0);
    468 		*m->sc_muxp = 0;
    469 	}
    470 
    471 	LIST_REMOVE(m, next);
    472 
    473 	free(m, M_DEVBUF);
    474 	DPRINTF(("wsmux_detach_sc: done sc=%p\n", sc));
    475 	return (0);
    476 }
    477 
    478 int wsmuxdoclose(dv, flags, mode, p)
    479 	struct device *dv;
    480 	int flags, mode;
    481 	struct proc *p;
    482 {
    483 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
    484 	struct wsplink *m;
    485 
    486 	DPRINTF(("wsmuxclose: %s: sc=%p\n", sc->sc_dv.dv_xname, sc));
    487 	if (!(flags & FREAD)) {
    488 		/* Not closing read, so read still allowed. */
    489 		return 0;
    490 	}
    491 
    492 	for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
    493 		if (*m->sc_muxp == sc) {
    494 			DPRINTF(("wsmuxclose %s: m=%p dev=%s\n",
    495 				 sc->sc_dv.dv_xname, m, m->sc->dv_xname));
    496 			m->sc_ops->dclose(m->sc, flags, mode, p);
    497 			*m->sc_muxp = 0;
    498 		}
    499 	}
    500 
    501 	wsevent_fini(&sc->sc_events);
    502 	sc->sc_events.io = NULL;
    503 
    504 	return (0);
    505 }
    506 
    507 int
    508 wsmuxdoioctl(dv, cmd, data, flag, p)
    509 	struct device *dv;
    510 	u_long cmd;
    511 	caddr_t data;
    512 	int flag;
    513 	struct proc *p;
    514 {
    515 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
    516 	struct wsplink *m;
    517 	int error, ok;
    518 	int s, put, get, n;
    519 	struct wseventvar *evar;
    520 	struct wscons_event *ev;
    521 	struct timeval xxxtime;
    522 	struct wsmux_device_list *l;
    523 
    524 	DPRINTF(("wsmuxdoioctl: %s: sc=%p, cmd=%08lx\n",
    525 		 sc->sc_dv.dv_xname, sc, cmd));
    526 
    527 	switch (cmd) {
    528 	case WSMUX_INJECTEVENT:
    529 		/* Inject an event, e.g., from moused. */
    530 		if (!sc->sc_events.io)
    531 			return (EACCES);
    532 
    533 		evar = &sc->sc_events;
    534 		s = spltty();
    535 		get = evar->get;
    536 		put = evar->put;
    537 		if (++put % WSEVENT_QSIZE == get) {
    538 			put--;
    539 			splx(s);
    540 			return (ENOSPC);
    541 		}
    542 		if (put >= WSEVENT_QSIZE)
    543 			put = 0;
    544 		ev = &evar->q[put];
    545 		*ev = *(struct wscons_event *)data;
    546 		microtime(&xxxtime);
    547 		TIMEVAL_TO_TIMESPEC(&xxxtime, &ev->time);
    548 		evar->put = put;
    549 		WSEVENT_WAKEUP(evar);
    550 		splx(s);
    551 		return (0);
    552 	case WSMUX_ADD_DEVICE:
    553 #define d ((struct wsmux_device *)data)
    554 		switch (d->type) {
    555 #if NWSMOUSE > 0
    556 		case WSMUX_MOUSE:
    557 			return (wsmouse_add_mux(d->idx, sc));
    558 #endif
    559 #if NWSKBD > 0
    560 		case WSMUX_KBD:
    561 			return (wskbd_add_mux(d->idx, sc));
    562 #endif
    563 #if NWSMUX > 0
    564 		case WSMUX_MUX:
    565 			return (wsmux_add_mux(d->idx, sc));
    566 #endif
    567 		default:
    568 			return (EINVAL);
    569 		}
    570 	case WSMUX_REMOVE_DEVICE:
    571 		switch (d->type) {
    572 #if NWSMOUSE > 0
    573 		case WSMUX_MOUSE:
    574 			return (wsmouse_rem_mux(d->idx, sc));
    575 #endif
    576 #if NWSKBD > 0
    577 		case WSMUX_KBD:
    578 			return (wskbd_rem_mux(d->idx, sc));
    579 #endif
    580 #if NWSMUX > 0
    581 		case WSMUX_MUX:
    582 			return (wsmux_rem_mux(d->idx, sc));
    583 #endif
    584 		default:
    585 			return (EINVAL);
    586 		}
    587 #undef d
    588 	case WSMUX_LIST_DEVICES:
    589 		l = (struct wsmux_device_list *)data;
    590 		for (n = 0, m = LIST_FIRST(&sc->sc_reals);
    591 		     n < WSMUX_MAXDEV && m != NULL;
    592 		     m = LIST_NEXT(m, next)) {
    593 			l->devices[n].type = m->type;
    594 			l->devices[n].idx = m->sc->dv_unit;
    595 			n++;
    596 		}
    597 		l->ndevices = n;
    598 		return (0);
    599 #ifdef WSDISPLAY_COMPAT_RAWKBD
    600 	case WSKBDIO_SETMODE:
    601 		sc->sc_rawkbd = *(int *)data;
    602 		DPRINTF(("wsmuxdoioctl: save rawkbd = %d\n", sc->sc_rawkbd));
    603 		break;
    604 #endif
    605 	default:
    606 		break;
    607 	}
    608 
    609 	if (sc->sc_events.io == NULL && sc->sc_displaydv == NULL)
    610 		return (EACCES);
    611 
    612 	/* Return 0 if any of the ioctl() succeeds, otherwise the last error */
    613 	error = 0;
    614 	ok = 0;
    615 	for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
    616 		DPRINTF(("wsmuxdoioctl: m=%p *m->sc_muxp=%p sc=%p\n",
    617 			 m, *m->sc_muxp, sc));
    618 		if (*m->sc_muxp == sc) {
    619 			DPRINTF(("wsmuxdoioctl: %s: m=%p dev=%s\n",
    620 				 sc->sc_dv.dv_xname, m, m->sc->dv_xname));
    621 			error = m->sc_ops->dioctl(m->sc, cmd, data, flag, p);
    622 			if (!error)
    623 				ok = 1;
    624 		}
    625 	}
    626 	if (ok)
    627 		error = 0;
    628 
    629 	return (error);
    630 }
    631 
    632 int
    633 wsmux_displayioctl(dv, cmd, data, flag, p)
    634 	struct device *dv;
    635 	u_long cmd;
    636 	caddr_t data;
    637 	int flag;
    638 	struct proc *p;
    639 {
    640 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
    641 	struct wsplink *m;
    642 	int error, ok;
    643 
    644 	DPRINTF(("wsmux_displayioctl: %s: sc=%p, cmd=%08lx\n",
    645 		 sc->sc_dv.dv_xname, sc, cmd));
    646 
    647 #ifdef WSDISPLAY_COMPAT_RAWKBD
    648 	if (cmd == WSKBDIO_SETMODE) {
    649 		sc->sc_rawkbd = *(int *)data;
    650 		DPRINTF(("wsmux_displayioctl: rawkbd = %d\n", sc->sc_rawkbd));
    651 	}
    652 #endif
    653 
    654 	/* Return 0 if any of the ioctl() succeeds, otherwise the last error */
    655 	error = 0;
    656 	ok = 0;
    657 	for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
    658 		DPRINTF(("wsmux_displayioctl: m=%p sc=%p sc_muxp=%p\n",
    659 			 m, sc, *m->sc_muxp));
    660 		if (m->sc_ops->ddispioctl && *m->sc_muxp == sc) {
    661 			error = m->sc_ops->ddispioctl(m->sc, cmd, data,
    662 						      flag, p);
    663 			DPRINTF(("wsmux_displayioctl: m=%p dev=%s ==> %d\n",
    664 				 m, m->sc->dv_xname, error));
    665 			if (!error)
    666 				ok = 1;
    667 		}
    668 	}
    669 	if (ok)
    670 		error = 0;
    671 
    672 	return (error);
    673 }
    674 
    675 int
    676 wsmux_set_display(dv, muxsc)
    677 	struct device *dv;
    678 	struct wsmux_softc *muxsc;
    679 {
    680 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
    681 	struct wsmux_softc *nsc = muxsc ? sc : 0;
    682 	struct device *displaydv = muxsc ? muxsc->sc_displaydv : 0;
    683 	struct device *odisplaydv;
    684 	struct wsplink *m;
    685 	int error, ok;
    686 
    687 	DPRINTF(("wsmux_set_display: %s: displaydv=%p\n",
    688 		 sc->sc_dv.dv_xname, displaydv));
    689 
    690 	if (displaydv) {
    691 		if (sc->sc_displaydv)
    692 			return (EBUSY);
    693 	} else {
    694 		if (sc->sc_displaydv == NULL)
    695 			return (ENXIO);
    696 	}
    697 
    698 	odisplaydv = sc->sc_displaydv;
    699 	sc->sc_displaydv = displaydv;
    700 
    701 	if (displaydv)
    702 		printf("%s: connecting to %s\n",
    703 		       sc->sc_dv.dv_xname, displaydv->dv_xname);
    704 	ok = 0;
    705 	error = 0;
    706 	for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
    707 		if (m->sc_ops->dsetdisplay &&
    708 		    (nsc ? m->sc_mevents->io == 0 && *m->sc_muxp == 0 :
    709 		           *m->sc_muxp == sc)) {
    710 			error = m->sc_ops->dsetdisplay(m->sc, nsc);
    711 			DPRINTF(("wsmux_set_display: m=%p dev=%s error=%d\n",
    712 				 m, m->sc->dv_xname, error));
    713 			if (!error) {
    714 				ok = 1;
    715 				*m->sc_muxp = nsc;
    716 #ifdef WSDISPLAY_COMPAT_RAWKBD
    717 				DPRINTF(("wsmux_set_display: on %s set rawkbd=%d\n",
    718 					 m->sc->dv_xname, sc->sc_rawkbd));
    719 				(void)m->sc_ops->dioctl(m->sc,
    720 					     WSKBDIO_SETMODE,
    721 					     (caddr_t)&sc->sc_rawkbd,
    722 					     0, 0);
    723 #endif
    724 			}
    725 		}
    726 	}
    727 	if (ok)
    728 		error = 0;
    729 
    730 	if (displaydv == NULL)
    731 		printf("%s: disconnecting from %s\n",
    732 		       sc->sc_dv.dv_xname, odisplaydv->dv_xname);
    733 
    734 	return (error);
    735 }
    736 
    737 #endif /* NWSMUX > 0 || (NWSDISPLAY > 0 && NWSKBD > 0) */
    738