xref: /openbsd/sys/dev/wscons/wsmux.c (revision 905646f0)
1 /*	$OpenBSD: wsmux.c,v 1.51 2020/07/29 05:53:52 anton Exp $	*/
2 /*      $NetBSD: wsmux.c,v 1.37 2005/04/30 03:47:12 augustss Exp $      */
3 
4 /*
5  * Copyright (c) 1998, 2005 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * Author: Lennart Augustsson <augustss@carlstedt.se>
9  *         Carlstedt Research & Technology
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "wsmux.h"
34 #include "wsdisplay.h"
35 #include "wskbd.h"
36 #include "wsmouse.h"
37 
38 /*
39  * wscons mux device.
40  *
41  * The mux device is a collection of real mice and keyboards and acts as
42  * a merge point for all the events from the different real devices.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/conf.h>
47 #include <sys/ioctl.h>
48 #include <sys/fcntl.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52 #include <sys/queue.h>
53 #include <sys/syslog.h>
54 #include <sys/systm.h>
55 #include <sys/tty.h>
56 #include <sys/signalvar.h>
57 #include <sys/device.h>
58 #include <sys/poll.h>
59 
60 #include <dev/wscons/wsconsio.h>
61 #include <dev/wscons/wsksymdef.h>
62 #include <dev/wscons/wseventvar.h>
63 #include <dev/wscons/wsmuxvar.h>
64 
65 #define WSMUX_MAXDEPTH	8
66 
67 #ifdef WSMUX_DEBUG
68 #define DPRINTF(x)	if (wsmuxdebug) printf x
69 #define DPRINTFN(n,x)	if (wsmuxdebug > (n)) printf x
70 int	wsmuxdebug = 0;
71 #else
72 #define DPRINTF(x)
73 #define DPRINTFN(n,x)
74 #endif
75 
76 /*
77  * The wsmux pseudo device is used to multiplex events from several wsmouse,
78  * wskbd, and/or wsmux devices together.
79  * The devices connected together form a tree with muxes in the interior
80  * and real devices (mouse and kbd) at the leaves.  The special case of
81  * a tree with one node (mux or other) is supported as well.
82  * Only the device at the root of the tree can be opened (if a non-root
83  * device is opened the subtree rooted at that point is severed from the
84  * containing tree).  When the root is opened it allocates a wseventvar
85  * struct which all the nodes in the tree will send their events too.
86  * An ioctl() performed on the root is propagated to all the nodes.
87  * There are also ioctl() operations to add and remove nodes from a tree.
88  */
89 
90 int	wsmux_mux_open(struct wsevsrc *, struct wseventvar *);
91 int	wsmux_mux_close(struct wsevsrc *);
92 
93 int	wsmux_do_open(struct wsmux_softc *, struct wseventvar *);
94 
95 void	wsmux_do_close(struct wsmux_softc *);
96 #if NWSDISPLAY > 0
97 int	wsmux_evsrc_set_display(struct device *, struct device *);
98 #else
99 #define wsmux_evsrc_set_display NULL
100 #endif
101 
102 int	wsmux_do_displayioctl(struct device *dev, u_long cmd, caddr_t data,
103 	    int flag, struct proc *p);
104 int	wsmux_do_ioctl(struct device *, u_long, caddr_t,int,struct proc *);
105 
106 int	wsmux_add_mux(int, struct wsmux_softc *);
107 
108 int	wsmux_depth(struct wsmux_softc *);
109 
110 void	wsmuxattach(int);
111 
112 void	wsmux_detach_sc_locked(struct wsmux_softc *, struct wsevsrc *);
113 
114 struct wssrcops wsmux_srcops = {
115 	.type		= WSMUX_MUX,
116 	.dopen		= wsmux_mux_open,
117 	.dclose		= wsmux_mux_close,
118 	.dioctl		= wsmux_do_ioctl,
119 	.ddispioctl	= wsmux_do_displayioctl,
120 	.dsetdisplay	= wsmux_evsrc_set_display,
121 };
122 
123 /*
124  * Lock used by wsmux_add_mux() to grant exclusive access to the tree of
125  * stacked wsmux devices.
126  */
127 struct rwlock wsmux_tree_lock = RWLOCK_INITIALIZER("wsmuxtreelk");
128 
129 /* From upper level */
130 void
131 wsmuxattach(int n)
132 {
133 }
134 
135 /* Keep track of all muxes that have been allocated */
136 int nwsmux = 0;
137 struct wsmux_softc **wsmuxdevs = NULL;
138 
139 /* Return mux n, create if necessary */
140 struct wsmux_softc *
141 wsmux_getmux(int n)
142 {
143 	struct wsmux_softc *sc;
144 	struct wsmux_softc **new, **old;
145 	int i;
146 
147 	if (n >= WSMUX_MAXDEV)
148 		return (NULL);
149 
150 	/* Make sure there is room for mux n in the table */
151 	if (n >= nwsmux) {
152 		old = wsmuxdevs;
153 		new = mallocarray(n + 1, sizeof (*wsmuxdevs),
154 		    M_DEVBUF, M_NOWAIT);
155 		if (new == NULL) {
156 			printf("wsmux_getmux: no memory for mux %d\n", n);
157 			return (NULL);
158 		}
159 		if (old != NULL)
160 			bcopy(old, new, nwsmux * sizeof(*wsmuxdevs));
161 		for (i = nwsmux; i < (n + 1); i++)
162 			new[i] = NULL;
163 		if (old != NULL)
164 			free(old, M_DEVBUF, nwsmux * sizeof(*wsmuxdevs));
165 		wsmuxdevs = new;
166 		nwsmux = n + 1;
167 	}
168 
169 	sc = wsmuxdevs[n];
170 	if (sc == NULL) {
171 		sc = wsmux_create("wsmux", n);
172 		if (sc == NULL)
173 			printf("wsmux: attach out of memory\n");
174 		wsmuxdevs[n] = sc;
175 	}
176 	return (sc);
177 }
178 
179 /*
180  * open() of the pseudo device from device table.
181  */
182 int
183 wsmuxopen(dev_t dev, int flags, int mode, struct proc *p)
184 {
185 	struct wsmux_softc *sc;
186 	struct wseventvar *evar;
187 	int error, unit;
188 
189 	unit = minor(dev);
190 	sc = wsmux_getmux(unit);
191 	if (sc == NULL)
192 		return (ENXIO);
193 
194 	DPRINTF(("%s: %s: sc=%p\n", __func__, sc->sc_base.me_dv.dv_xname, sc));
195 
196 	if ((flags & (FREAD | FWRITE)) == FWRITE) {
197 		/* Not opening for read, only ioctl is available. */
198 		return (0);
199 	}
200 
201 	if (sc->sc_base.me_parent != NULL) {
202 		/* Grab the mux out of the greedy hands of the parent mux. */
203 		DPRINTF(("%s: detach\n", __func__));
204 		wsmux_detach_sc(&sc->sc_base);
205 	}
206 
207 	if (sc->sc_base.me_evp != NULL)
208 		/* Already open. */
209 		return (EBUSY);
210 
211 	evar = &sc->sc_base.me_evar;
212 	if (wsevent_init(evar))
213 		return (EBUSY);
214 #ifdef WSDISPLAY_COMPAT_RAWKBD
215 	sc->sc_rawkbd = 0;
216 #endif
217 
218 	error = wsmux_do_open(sc, evar);
219 	if (error)
220                 wsevent_fini(evar);
221 	return (error);
222 }
223 
224 /*
225  * Open of a mux via the parent mux.
226  */
227 int
228 wsmux_mux_open(struct wsevsrc *me, struct wseventvar *evar)
229 {
230 	struct wsmux_softc *sc = (struct wsmux_softc *)me;
231 
232 #ifdef DIAGNOSTIC
233 	if (sc->sc_base.me_parent == NULL) {
234 		printf("wsmux_mux_open: no parent\n");
235 		return (EINVAL);
236 	}
237 #endif
238 
239 	return (wsmux_do_open(sc, evar));
240 }
241 
242 /* Common part of opening a mux. */
243 int
244 wsmux_do_open(struct wsmux_softc *sc, struct wseventvar *evar)
245 {
246 	struct wsevsrc *me;
247 #ifdef DIAGNOSTIC
248 	int error;
249 #endif
250 
251 	/* The device could already be attached to a mux. */
252 	if (sc->sc_base.me_evp != NULL)
253 		return (EBUSY);
254 	sc->sc_base.me_evp = evar; /* remember event variable, mark as open */
255 
256 	/* Open all children. */
257 	rw_enter_read(&sc->sc_lock);
258 	TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
259 		DPRINTF(("%s: %s: m=%p dev=%s\n", __func__,
260 			 sc->sc_base.me_dv.dv_xname, me,
261 			 me->me_dv.dv_xname));
262 #ifdef DIAGNOSTIC
263 		if (me->me_evp != NULL) {
264 			printf("wsmuxopen: dev already in use\n");
265 			continue;
266 		}
267 		if (me->me_parent != sc) {
268 			printf("wsmux_do_open: bad child=%p\n", me);
269 			continue;
270 		}
271 		error = wsevsrc_open(me, evar);
272 		if (error) {
273 			DPRINTF(("%s: open failed %d\n", __func__, error));
274 		}
275 #else
276 		/* ignore errors, failing children will not be marked open */
277 		(void)wsevsrc_open(me, evar);
278 #endif
279 	}
280 	rw_exit_read(&sc->sc_lock);
281 
282 	return (0);
283 }
284 
285 /*
286  * close() of the pseudo device from device table.
287  */
288 int
289 wsmuxclose(dev_t dev, int flags, int mode, struct proc *p)
290 {
291 	struct wsmux_softc *sc =
292 	    (struct wsmux_softc *)wsmuxdevs[minor(dev)];
293 	struct wseventvar *evar = sc->sc_base.me_evp;
294 
295 	if ((flags & (FREAD | FWRITE)) == FWRITE)
296 		/* Not open for read */
297 		return (0);
298 
299 	wsmux_do_close(sc);
300 	sc->sc_base.me_evp = NULL;
301 	wsevent_fini(evar);
302 	return (0);
303 }
304 
305 /*
306  * Close of a mux via the parent mux.
307  */
308 int
309 wsmux_mux_close(struct wsevsrc *me)
310 {
311 	struct wsmux_softc *sc = (struct wsmux_softc *)me;
312 
313 	wsmux_do_close(sc);
314 	sc->sc_base.me_evp = NULL;
315 
316 	return (0);
317 }
318 
319 /* Common part of closing a mux. */
320 void
321 wsmux_do_close(struct wsmux_softc *sc)
322 {
323 	struct wsevsrc *me;
324 
325 	DPRINTF(("%s: %s: sc=%p\n", __func__, sc->sc_base.me_dv.dv_xname, sc));
326 
327 	/* Close all the children. */
328 	rw_enter_read(&sc->sc_lock);
329 	TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
330 		DPRINTF(("%s %s: m=%p dev=%s\n", __func__,
331 			 sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname));
332 #ifdef DIAGNOSTIC
333 		if (me->me_parent != sc) {
334 			printf("wsmuxclose: bad child=%p\n", me);
335 			continue;
336 		}
337 #endif
338 		(void)wsevsrc_close(me);
339 	}
340 	rw_exit_read(&sc->sc_lock);
341 }
342 
343 /*
344  * read() of the pseudo device from device table.
345  */
346 int
347 wsmuxread(dev_t dev, struct uio *uio, int flags)
348 {
349 	struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
350 	struct wseventvar *evar;
351 	int error;
352 
353 	evar = sc->sc_base.me_evp;
354 	if (evar == NULL) {
355 #ifdef DIAGNOSTIC
356 		/* XXX can we get here? */
357 		printf("wsmuxread: not open\n");
358 #endif
359 		return (EINVAL);
360 	}
361 
362 	DPRINTFN(5, ("%s: %s event read evar=%p\n", __func__,
363 		     sc->sc_base.me_dv.dv_xname, evar));
364 	error = wsevent_read(evar, uio, flags);
365 	DPRINTFN(5, ("%s: %s event read ==> error=%d\n", __func__,
366 		     sc->sc_base.me_dv.dv_xname, error));
367 	return (error);
368 }
369 
370 /*
371  * ioctl of the pseudo device from device table.
372  */
373 int
374 wsmuxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
375 {
376 	return wsmux_do_ioctl(&wsmuxdevs[minor(dev)]->sc_base.me_dv, cmd, data, flag, p);
377 }
378 
379 /*
380  * ioctl of a mux via the parent mux, continuation of wsmuxioctl().
381  */
382 int
383 wsmux_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
384     struct proc *p)
385 {
386 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
387 	struct wsevsrc *me;
388 	int error, ok;
389 	int s, put, get, n;
390 	struct wseventvar *evar;
391 	struct wscons_event *ev;
392 	struct wsmux_device_list *l;
393 
394 	DPRINTF(("%s: %s: enter sc=%p, cmd=%08lx\n", __func__,
395 		 sc->sc_base.me_dv.dv_xname, sc, cmd));
396 
397 	switch (cmd) {
398 	case WSMUXIO_INJECTEVENT:
399 	case WSMUXIO_ADD_DEVICE:
400 	case WSMUXIO_REMOVE_DEVICE:
401 #ifdef WSDISPLAY_COMPAT_RAWKBD
402 	case WSKBDIO_SETMODE:
403 #endif
404 		if ((flag & FWRITE) == 0)
405 			return (EACCES);
406 	}
407 
408 	switch (cmd) {
409 	case WSMUXIO_INJECTEVENT:
410 		/* Inject an event, e.g., from moused. */
411 		DPRINTF(("%s: inject\n", sc->sc_base.me_dv.dv_xname));
412 		evar = sc->sc_base.me_evp;
413 		if (evar == NULL) {
414 			/* No event sink, so ignore it. */
415 			DPRINTF(("%s: event ignored\n", __func__));
416 			return (0);
417 		}
418 
419 		s = spltty();
420 		get = evar->get;
421 		put = evar->put;
422 		ev = &evar->q[put];
423 		if (++put % WSEVENT_QSIZE == get) {
424 			put--;
425 			splx(s);
426 			return (ENOSPC);
427 		}
428 		if (put >= WSEVENT_QSIZE)
429 			put = 0;
430 		*ev = *(struct wscons_event *)data;
431 		nanotime(&ev->time);
432 		evar->put = put;
433 		WSEVENT_WAKEUP(evar);
434 		splx(s);
435 		return (0);
436 	case WSMUXIO_ADD_DEVICE:
437 #define d ((struct wsmux_device *)data)
438 		DPRINTF(("%s: add type=%d, no=%d\n", sc->sc_base.me_dv.dv_xname,
439 			 d->type, d->idx));
440 		if (d->idx < 0)
441 			return (ENXIO);
442 		switch (d->type) {
443 #if NWSMOUSE > 0
444 		case WSMUX_MOUSE:
445 			return (wsmouse_add_mux(d->idx, sc));
446 #endif
447 #if NWSKBD > 0
448 		case WSMUX_KBD:
449 			return (wskbd_add_mux(d->idx, sc));
450 #endif
451 		case WSMUX_MUX:
452 			return (wsmux_add_mux(d->idx, sc));
453 		default:
454 			return (EINVAL);
455 		}
456 	case WSMUXIO_REMOVE_DEVICE:
457 		DPRINTF(("%s: rem type=%d, no=%d\n", sc->sc_base.me_dv.dv_xname,
458 			 d->type, d->idx));
459 		/* Locate the device */
460 		rw_enter_write(&sc->sc_lock);
461 		TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
462 			if (me->me_ops->type == d->type &&
463 			    me->me_dv.dv_unit == d->idx) {
464 				DPRINTF(("%s: detach\n", __func__));
465 				wsmux_detach_sc_locked(sc, me);
466 				rw_exit_write(&sc->sc_lock);
467 				return (0);
468 			}
469 		}
470 		rw_exit_write(&sc->sc_lock);
471 		return (EINVAL);
472 #undef d
473 
474 	case WSMUXIO_LIST_DEVICES:
475 		DPRINTF(("%s: list\n", sc->sc_base.me_dv.dv_xname));
476 		l = (struct wsmux_device_list *)data;
477 		n = 0;
478 		rw_enter_read(&sc->sc_lock);
479 		TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
480 			if (n >= WSMUX_MAXDEV)
481 				break;
482 			l->devices[n].type = me->me_ops->type;
483 			l->devices[n].idx = me->me_dv.dv_unit;
484 			n++;
485 		}
486 		rw_exit_read(&sc->sc_lock);
487 		l->ndevices = n;
488 		return (0);
489 #ifdef WSDISPLAY_COMPAT_RAWKBD
490 	case WSKBDIO_SETMODE:
491 		sc->sc_rawkbd = *(int *)data;
492 		DPRINTF(("%s: save rawkbd = %d\n", __func__, sc->sc_rawkbd));
493 		break;
494 #endif
495 	case FIONBIO:
496 		DPRINTF(("%s: FIONBIO\n", sc->sc_base.me_dv.dv_xname));
497 		return (0);
498 
499 	case FIOASYNC:
500 		DPRINTF(("%s: FIOASYNC\n", sc->sc_base.me_dv.dv_xname));
501 		evar = sc->sc_base.me_evp;
502 		if (evar == NULL)
503 			return (EINVAL);
504 		evar->async = *(int *)data != 0;
505 		return (0);
506 	case FIOGETOWN:
507 	case TIOCGPGRP:
508 		DPRINTF(("%s: getown (%lu)\n", sc->sc_base.me_dv.dv_xname,
509 			 cmd));
510 		evar = sc->sc_base.me_evp;
511 		if (evar == NULL)
512 			return (EINVAL);
513 		sigio_getown(&evar->sigio, cmd, data);
514 		return (0);
515 	case FIOSETOWN:
516 	case TIOCSPGRP:
517 		DPRINTF(("%s: setown (%lu)\n", sc->sc_base.me_dv.dv_xname,
518 			 cmd));
519 		evar = sc->sc_base.me_evp;
520 		if (evar == NULL)
521 			return (EINVAL);
522 		return (sigio_setown(&evar->sigio, cmd, data));
523 	default:
524 		DPRINTF(("%s: unknown\n", sc->sc_base.me_dv.dv_xname));
525 		break;
526 	}
527 
528 	if (sc->sc_base.me_evp == NULL
529 #if NWSDISPLAY > 0
530 	    && sc->sc_displaydv == NULL
531 #endif
532 	    )
533 		return (EACCES);
534 
535 	/*
536 	 * If children are attached: return 0 if any of the ioctl() succeeds,
537 	 * otherwise the last error.
538 	 */
539 	error = ENOTTY;
540 	ok = 0;
541 	rw_enter_read(&sc->sc_lock);
542 	TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
543 #ifdef DIAGNOSTIC
544 		/* XXX check evp? */
545 		if (me->me_parent != sc) {
546 			printf("wsmux_do_ioctl: bad child %p\n", me);
547 			continue;
548 		}
549 #endif
550 		error = wsevsrc_ioctl(me, cmd, data, flag, p);
551 		DPRINTF(("%s: %s: me=%p dev=%s ==> %d\n", __func__,
552 			 sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname,
553 			 error));
554 		if (!error)
555 			ok = 1;
556 	}
557 	rw_exit_read(&sc->sc_lock);
558 	if (ok)
559 		error = 0;
560 
561 	return (error);
562 }
563 
564 /*
565  * poll() of the pseudo device from device table.
566  */
567 int
568 wsmuxpoll(dev_t dev, int events, struct proc *p)
569 {
570 	struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
571 
572 	if (sc->sc_base.me_evp == NULL) {
573 #ifdef DIAGNOSTIC
574 		printf("wsmuxpoll: not open\n");
575 #endif
576 		return (POLLERR);
577 	}
578 
579 	return (wsevent_poll(sc->sc_base.me_evp, events, p));
580 }
581 
582 int
583 wsmuxkqfilter(dev_t dev, struct knote *kn)
584 {
585 	struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
586 
587 	if (sc->sc_base.me_evp == NULL)
588 		return (ENXIO);
589 	return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
590 }
591 
592 /*
593  * Add mux unit as a child to muxsc.
594  */
595 int
596 wsmux_add_mux(int unit, struct wsmux_softc *muxsc)
597 {
598 	struct wsmux_softc *sc, *m;
599 	int error;
600 	int depth = 0;
601 
602 	sc = wsmux_getmux(unit);
603 	if (sc == NULL)
604 		return (ENXIO);
605 
606 	rw_enter_write(&wsmux_tree_lock);
607 
608 	DPRINTF(("%s: %s(%p) to %s(%p)\n", __func__,
609 		 sc->sc_base.me_dv.dv_xname, sc,
610 		 muxsc->sc_base.me_dv.dv_xname, muxsc));
611 
612 	if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) {
613 		error = EBUSY;
614 		goto out;
615 	}
616 
617 	/* The mux we are adding must not be an ancestor of itself. */
618 	for (m = muxsc; m != NULL; m = m->sc_base.me_parent) {
619 		if (m == sc) {
620 			error = EINVAL;
621 			goto out;
622 		}
623 		depth++;
624 	}
625 
626 	/*
627 	 * Limit the number of stacked wsmux devices to avoid exhausting
628 	 * the kernel stack during wsmux_do_open().
629 	 */
630 	if (depth + wsmux_depth(sc) > WSMUX_MAXDEPTH) {
631 		error = EBUSY;
632 		goto out;
633 	}
634 
635 	error = wsmux_attach_sc(muxsc, &sc->sc_base);
636 out:
637 	rw_exit_write(&wsmux_tree_lock);
638 	return (error);
639 }
640 
641 /* Create a new mux softc. */
642 struct wsmux_softc *
643 wsmux_create(const char *name, int unit)
644 {
645 	struct wsmux_softc *sc;
646 
647 	DPRINTF(("%s: allocating\n", __func__));
648 	sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT | M_ZERO);
649 	if (sc == NULL)
650 		return (NULL);
651 	TAILQ_INIT(&sc->sc_cld);
652 	rw_init_flags(&sc->sc_lock, "wsmuxlk", RWL_DUPOK);
653 	snprintf(sc->sc_base.me_dv.dv_xname, sizeof sc->sc_base.me_dv.dv_xname,
654 		 "%s%d", name, unit);
655 	sc->sc_base.me_dv.dv_unit = unit;
656 	sc->sc_base.me_ops = &wsmux_srcops;
657 	sc->sc_kbd_layout = KB_NONE;
658 	return (sc);
659 }
660 
661 /* Attach me as a child to sc. */
662 int
663 wsmux_attach_sc(struct wsmux_softc *sc, struct wsevsrc *me)
664 {
665 	int error;
666 
667 	if (sc == NULL)
668 		return (EINVAL);
669 
670 	rw_enter_write(&sc->sc_lock);
671 
672 	DPRINTF(("%s: %s(%p): type=%d\n", __func__,
673 		 sc->sc_base.me_dv.dv_xname, sc, me->me_ops->type));
674 
675 #ifdef DIAGNOSTIC
676 	if (me->me_parent != NULL) {
677 		rw_exit_write(&sc->sc_lock);
678 		printf("wsmux_attach_sc: busy\n");
679 		return (EBUSY);
680 	}
681 #endif
682 	me->me_parent = sc;
683 	TAILQ_INSERT_TAIL(&sc->sc_cld, me, me_next);
684 
685 	error = 0;
686 #if NWSDISPLAY > 0
687 	if (sc->sc_displaydv != NULL) {
688 		/* This is a display mux, so attach the new device to it. */
689 		DPRINTF(("%s: %s: set display %p\n", __func__,
690 			 sc->sc_base.me_dv.dv_xname, sc->sc_displaydv));
691 		if (me->me_ops->dsetdisplay != NULL) {
692 			error = wsevsrc_set_display(me, sc->sc_displaydv);
693 			/* Ignore that the console already has a display. */
694 			if (error == EBUSY)
695 				error = 0;
696 			if (!error) {
697 #ifdef WSDISPLAY_COMPAT_RAWKBD
698 				DPRINTF(("%s: %s set rawkbd=%d\n", __func__,
699 					 me->me_dv.dv_xname, sc->sc_rawkbd));
700 				(void)wsevsrc_ioctl(me, WSKBDIO_SETMODE,
701 						    &sc->sc_rawkbd, FWRITE, 0);
702 #endif
703 			}
704 		}
705 	}
706 #endif
707 	if (sc->sc_base.me_evp != NULL) {
708 		/* Mux is open, so open the new subdevice */
709 		DPRINTF(("%s: %s: calling open of %s\n", __func__,
710 			 sc->sc_base.me_dv.dv_xname, me->me_dv.dv_xname));
711 		error = wsevsrc_open(me, sc->sc_base.me_evp);
712 	} else {
713 		DPRINTF(("%s: %s not open\n", __func__,
714 			 sc->sc_base.me_dv.dv_xname));
715 	}
716 
717 	if (error) {
718 		me->me_parent = NULL;
719 		TAILQ_REMOVE(&sc->sc_cld, me, me_next);
720 	}
721 
722 	rw_exit_write(&sc->sc_lock);
723 
724 	DPRINTF(("%s: %s(%p) done, error=%d\n", __func__,
725 		 sc->sc_base.me_dv.dv_xname, sc, error));
726 	return (error);
727 }
728 
729 /* Remove me from the parent. */
730 void
731 wsmux_detach_sc(struct wsevsrc *me)
732 {
733 	struct wsmux_softc *sc = me->me_parent;
734 
735 	if (sc == NULL) {
736 		printf("wsmux_detach_sc: %s has no parent\n",
737 		       me->me_dv.dv_xname);
738 		return;
739 	}
740 
741 	rw_enter_write(&sc->sc_lock);
742 	wsmux_detach_sc_locked(sc, me);
743 	rw_exit_write(&sc->sc_lock);
744 }
745 
746 void
747 wsmux_detach_sc_locked(struct wsmux_softc *sc, struct wsevsrc *me)
748 {
749 	rw_assert_wrlock(&sc->sc_lock);
750 
751 	DPRINTF(("%s: %s(%p) parent=%p\n", __func__,
752 		 me->me_dv.dv_xname, me, sc));
753 
754 	if (me->me_parent != sc) {
755 		/* Device detached or attached to another mux while sleeping. */
756 		return;
757 	}
758 
759 #if NWSDISPLAY > 0
760 	if (sc->sc_displaydv != NULL) {
761 		if (me->me_ops->dsetdisplay != NULL)
762 			/* ignore error, there's nothing we can do */
763 			(void)wsevsrc_set_display(me, NULL);
764 	} else
765 #endif
766 		if (me->me_evp != NULL) {
767 		DPRINTF(("%s: close\n", __func__));
768 		/* mux device is open, so close multiplexee */
769 		(void)wsevsrc_close(me);
770 	}
771 
772 	TAILQ_REMOVE(&sc->sc_cld, me, me_next);
773 	me->me_parent = NULL;
774 
775 	DPRINTF(("%s: done sc=%p\n", __func__, sc));
776 }
777 
778 /*
779  * Display ioctl() of a mux via the parent mux.
780  */
781 int
782 wsmux_do_displayioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
783     struct proc *p)
784 {
785 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
786 	struct wsevsrc *me;
787 	int error, ok;
788 
789 	DPRINTF(("%s: %s: sc=%p, cmd=%08lx\n", __func__,
790 		 sc->sc_base.me_dv.dv_xname, sc, cmd));
791 
792 #ifdef WSDISPLAY_COMPAT_RAWKBD
793 	if (cmd == WSKBDIO_SETMODE) {
794 		sc->sc_rawkbd = *(int *)data;
795 		DPRINTF(("%s: rawkbd = %d\n", __func__, sc->sc_rawkbd));
796 	}
797 #endif
798 
799 	/*
800 	 * Return 0 if any of the ioctl() succeeds, otherwise the last error.
801 	 * Return -1 if no mux component accepts the ioctl.
802 	 */
803 	error = -1;
804 	ok = 0;
805 	rw_enter_read(&sc->sc_lock);
806 	TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
807 		DPRINTF(("%s: me=%p\n", __func__, me));
808 #ifdef DIAGNOSTIC
809 		if (me->me_parent != sc) {
810 			printf("wsmux_displayioctl: bad child %p\n", me);
811 			continue;
812 		}
813 #endif
814 		if (me->me_ops->ddispioctl != NULL) {
815 			error = wsevsrc_display_ioctl(me, cmd, data, flag, p);
816 			DPRINTF(("%s: me=%p dev=%s ==> %d\n", __func__,
817 				 me, me->me_dv.dv_xname, error));
818 			if (!error)
819 				ok = 1;
820 		}
821 	}
822 	rw_exit_read(&sc->sc_lock);
823 	if (ok)
824 		error = 0;
825 
826 	return (error);
827 }
828 
829 #if NWSDISPLAY > 0
830 /*
831  * Set display of a mux via the parent mux.
832  */
833 int
834 wsmux_evsrc_set_display(struct device *dv, struct device *displaydv)
835 {
836 	struct wsmux_softc *sc = (struct wsmux_softc *)dv;
837 
838 	DPRINTF(("%s: %s: displaydv=%p\n", __func__,
839 		 sc->sc_base.me_dv.dv_xname, displaydv));
840 
841 	if (displaydv != NULL) {
842 		if (sc->sc_displaydv != NULL)
843 			return (EBUSY);
844 	} else {
845 		if (sc->sc_displaydv == NULL)
846 			return (ENXIO);
847 	}
848 
849 	return wsmux_set_display(sc, displaydv);
850 }
851 
852 int
853 wsmux_set_display(struct wsmux_softc *sc, struct device *displaydv)
854 {
855 	struct device *odisplaydv;
856 	struct wsevsrc *me;
857 	struct wsmux_softc *nsc = displaydv ? sc : NULL;
858 	int error, ok;
859 
860 	rw_enter_read(&sc->sc_lock);
861 
862 	odisplaydv = sc->sc_displaydv;
863 	sc->sc_displaydv = displaydv;
864 
865 	if (displaydv) {
866 		DPRINTF(("%s: connecting to %s\n",
867 		       sc->sc_base.me_dv.dv_xname, displaydv->dv_xname));
868 	}
869 	ok = 0;
870 	error = 0;
871 	TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
872 #ifdef DIAGNOSTIC
873 		if (me->me_parent != sc) {
874 			printf("wsmux_set_display: bad child parent %p\n", me);
875 			continue;
876 		}
877 #endif
878 		if (me->me_ops->dsetdisplay != NULL) {
879 			error = wsevsrc_set_display(me,
880 			    nsc ? nsc->sc_displaydv : NULL);
881 			DPRINTF(("%s: m=%p dev=%s error=%d\n", __func__,
882 				 me, me->me_dv.dv_xname, error));
883 			if (!error) {
884 				ok = 1;
885 #ifdef WSDISPLAY_COMPAT_RAWKBD
886 				DPRINTF(("%s: %s set rawkbd=%d\n", __func__,
887 					 me->me_dv.dv_xname, sc->sc_rawkbd));
888 				(void)wsevsrc_ioctl(me, WSKBDIO_SETMODE,
889 						    &sc->sc_rawkbd, FWRITE, 0);
890 #endif
891 			}
892 		}
893 	}
894 	if (ok)
895 		error = 0;
896 
897 	if (displaydv == NULL) {
898 		DPRINTF(("%s: disconnecting from %s\n",
899 		       sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname));
900 	}
901 
902 	rw_exit_read(&sc->sc_lock);
903 
904 	return (error);
905 }
906 #endif /* NWSDISPLAY > 0 */
907 
908 uint32_t
909 wsmux_get_layout(struct wsmux_softc *sc)
910 {
911 	return sc->sc_kbd_layout;
912 }
913 
914 void
915 wsmux_set_layout(struct wsmux_softc *sc, uint32_t layout)
916 {
917 	if ((layout & KB_DEFAULT) == 0)
918 		sc->sc_kbd_layout = layout;
919 }
920 
921 /*
922  * Returns the depth of the longest chain of nested wsmux devices starting
923  * from sc.
924  */
925 int
926 wsmux_depth(struct wsmux_softc *sc)
927 {
928 	struct wsevsrc *me;
929 	int depth;
930 	int maxdepth = 0;
931 
932 	rw_assert_anylock(&wsmux_tree_lock);
933 
934 	rw_enter_read(&sc->sc_lock);
935 	TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
936 		if (me->me_ops->type != WSMUX_MUX)
937 			continue;
938 
939 		depth = wsmux_depth((struct wsmux_softc *)me);
940 		if (depth > maxdepth)
941 			maxdepth = depth;
942 	}
943 	rw_exit_read(&sc->sc_lock);
944 
945 	return (maxdepth + 1);
946 }
947