1 /* $NetBSD: wsmux.c,v 1.52 2009/01/15 04:22:11 yamt Exp $ */
4 * Copyright (c) 1998, 2005 The NetBSD Foundation, Inc.
7 * Author: Lennart Augustsson <lennart@augustsson.net>
8 * Carlstedt Research & Technology
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
35 * The mux device is a collection of real mice and keyboards and acts as
36 * a merge point for all the events from the different real devices.
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: wsmux.c,v 1.52 2009/01/15 04:22:11 yamt Exp $");
42 #include "opt_compat_netbsd.h"
43 #include "opt_modular.h"
45 #include "wsdisplay.h"
50 #include <sys/param.h>
52 #include <sys/ioctl.h>
54 #include <sys/fcntl.h>
55 #include <sys/kernel.h>
56 #include <sys/malloc.h>
58 #include <sys/queue.h>
59 #include <sys/syslog.h>
60 #include <sys/systm.h>
62 #include <sys/signalvar.h>
63 #include <sys/device.h>
65 #include "opt_wsdisplay_compat.h"
67 #include <dev/wscons/wsconsio.h>
68 #include <dev/wscons/wsksymdef.h>
69 #include <dev/wscons/wseventvar.h>
70 #include <dev/wscons/wscons_callbacks.h>
71 #include <dev/wscons/wsmuxvar.h>
74 #define DPRINTF(x) if (wsmuxdebug) printf x
75 #define DPRINTFN(n,x) if (wsmuxdebug > (n)) printf x
83 * The wsmux pseudo device is used to multiplex events from several wsmouse,
84 * wskbd, and/or wsmux devices together.
85 * The devices connected together form a tree with muxes in the interior
86 * and real devices (mouse and kbd) at the leaves. The special case of
87 * a tree with one node (mux or other) is supported as well.
88 * Only the device at the root of the tree can be opened (if a non-root
89 * device is opened the subtree rooted at that point is severed from the
90 * containing tree). When the root is opened it allocates a wseventvar
91 * struct which all the nodes in the tree will send their events too.
92 * An ioctl() performed on the root is propagated to all the nodes.
93 * There are also ioctl() operations to add and remove nodes from a tree.
96 static int wsmux_mux_open(struct wsevsrc
*, struct wseventvar
*);
97 static int wsmux_mux_close(struct wsevsrc
*);
99 static void wsmux_do_open(struct wsmux_softc
*, struct wseventvar
*);
101 static void wsmux_do_close(struct wsmux_softc
*);
103 static int wsmux_evsrc_set_display(device_t
, struct wsevsrc
*);
105 #define wsmux_evsrc_set_display NULL
108 static int wsmux_do_displayioctl(device_t dev
, u_long cmd
,
109 void *data
, int flag
, struct lwp
*l
);
110 static int wsmux_do_ioctl(device_t
, u_long
, void *,int,struct lwp
*);
112 static int wsmux_add_mux(int, struct wsmux_softc
*);
114 void wsmuxattach(int);
116 #define WSMUXDEV(n) ((n) & 0x7f)
117 #define WSMUXCTL(n) ((n) & 0x80)
119 dev_type_open(wsmuxopen
);
120 dev_type_close(wsmuxclose
);
121 dev_type_read(wsmuxread
);
122 dev_type_ioctl(wsmuxioctl
);
123 dev_type_poll(wsmuxpoll
);
124 dev_type_kqfilter(wsmuxkqfilter
);
126 const struct cdevsw wsmux_cdevsw
= {
127 wsmuxopen
, wsmuxclose
, wsmuxread
, nowrite
, wsmuxioctl
,
128 nostop
, notty
, wsmuxpoll
, nommap
, wsmuxkqfilter
, D_OTHER
131 struct wssrcops wsmux_srcops
= {
133 wsmux_mux_open
, wsmux_mux_close
, wsmux_do_ioctl
, wsmux_do_displayioctl
,
134 wsmux_evsrc_set_display
137 /* From upper level */
143 /* Keep track of all muxes that have been allocated */
144 static int nwsmux
= 0;
145 static struct wsmux_softc
**wsmuxdevs
;
147 /* Return mux n, create if necessary */
151 struct wsmux_softc
*sc
;
155 n
= WSMUXDEV(n
); /* limit range */
157 /* Make sure there is room for mux n in the table */
162 new = realloc(wsmuxdevs
, nwsmux
* sizeof (*wsmuxdevs
),
165 new = malloc(nwsmux
* sizeof (*wsmuxdevs
),
168 printf("wsmux_getmux: no memory for mux %d\n", n
);
172 for (; i
< nwsmux
; i
++)
178 sc
= wsmux_create("wsmux", n
);
180 printf("wsmux: attach out of memory\n");
187 * open() of the pseudo device from device table.
190 wsmuxopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
192 struct wsmux_softc
*sc
;
193 struct wseventvar
*evar
;
197 unit
= WSMUXDEV(minr
);
198 sc
= wsmux_getmux(unit
);
202 DPRINTF(("wsmuxopen: %s: sc=%p l=%p\n",
203 device_xname(sc
->sc_base
.me_dv
), sc
, l
));
205 if (WSMUXCTL(minr
)) {
206 /* This is the control device which does not allow reads. */
211 if ((flags
& (FREAD
| FWRITE
)) == FWRITE
)
212 /* Allow write only open */
215 if (sc
->sc_base
.me_parent
!= NULL
) {
216 /* Grab the mux out of the greedy hands of the parent mux. */
217 DPRINTF(("wsmuxopen: detach\n"));
218 wsmux_detach_sc(&sc
->sc_base
);
221 if (sc
->sc_base
.me_evp
!= NULL
)
225 evar
= &sc
->sc_base
.me_evar
;
226 wsevent_init(evar
, l
->l_proc
);
227 #ifdef WSDISPLAY_COMPAT_RAWKBD
231 wsmux_do_open(sc
, evar
);
237 * Open of a mux via the parent mux.
240 wsmux_mux_open(struct wsevsrc
*me
, struct wseventvar
*evar
)
242 struct wsmux_softc
*sc
= (struct wsmux_softc
*)me
;
245 if (sc
->sc_base
.me_evp
!= NULL
) {
246 printf("wsmux_mux_open: busy\n");
249 if (sc
->sc_base
.me_parent
== NULL
) {
250 printf("wsmux_mux_open: no parent\n");
255 wsmux_do_open(sc
, evar
);
260 /* Common part of opening a mux. */
262 wsmux_do_open(struct wsmux_softc
*sc
, struct wseventvar
*evar
)
266 sc
->sc_base
.me_evp
= evar
; /* remember event variable, mark as open */
268 /* Open all children. */
269 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
, me_next
) {
270 DPRINTF(("wsmuxopen: %s: m=%p dev=%s\n",
271 device_xname(sc
->sc_base
.me_dv
), me
,
272 device_xname(me
->me_dv
)));
274 if (me
->me_evp
!= NULL
) {
275 printf("wsmuxopen: dev already in use\n");
278 if (me
->me_parent
!= sc
) {
279 printf("wsmux_do_open: bad child=%p\n", me
);
283 int error
= wsevsrc_open(me
, evar
);
285 DPRINTF(("wsmuxopen: open failed %d\n", error
));
289 /* ignore errors, failing children will not be marked open */
290 (void)wsevsrc_open(me
, evar
);
296 * close() of the pseudo device from device table.
299 wsmuxclose(dev_t dev
, int flags
, int mode
,
302 int minr
= minor(dev
);
303 struct wsmux_softc
*sc
= wsmuxdevs
[WSMUXDEV(minr
)];
304 struct wseventvar
*evar
= sc
->sc_base
.me_evp
;
310 /* Not open for read */
314 sc
->sc_base
.me_evp
= NULL
;
320 * Close of a mux via the parent mux.
323 wsmux_mux_close(struct wsevsrc
*me
)
326 wsmux_do_close((struct wsmux_softc
*)me
);
330 /* Common part of closing a mux. */
332 wsmux_do_close(struct wsmux_softc
*sc
)
336 DPRINTF(("wsmuxclose: %s: sc=%p\n",
337 device_xname(sc
->sc_base
.me_dv
), sc
));
339 /* Close all the children. */
340 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
, me_next
) {
341 DPRINTF(("wsmuxclose %s: m=%p dev=%s\n",
342 device_xname(sc
->sc_base
.me_dv
), me
,
343 device_xname(me
->me_dv
)));
345 if (me
->me_parent
!= sc
) {
346 printf("wsmuxclose: bad child=%p\n", me
);
350 (void)wsevsrc_close(me
);
356 * read() of the pseudo device from device table.
359 wsmuxread(dev_t dev
, struct uio
*uio
, int flags
)
361 int minr
= minor(dev
);
362 struct wsmux_softc
*sc
= wsmuxdevs
[WSMUXDEV(minr
)];
363 struct wseventvar
*evar
;
366 if (WSMUXCTL(minr
)) {
371 evar
= sc
->sc_base
.me_evp
;
374 /* XXX can we get here? */
375 printf("wsmuxread: not open\n");
380 DPRINTFN(5,("wsmuxread: %s event read evar=%p\n",
381 device_xname(sc
->sc_base
.me_dv
), evar
));
382 error
= wsevent_read(evar
, uio
, flags
);
383 DPRINTFN(5,("wsmuxread: %s event read ==> error=%d\n",
384 device_xname(sc
->sc_base
.me_dv
), error
));
389 * ioctl of the pseudo device from device table.
392 wsmuxioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
394 int u
= WSMUXDEV(minor(dev
));
396 return wsmux_do_ioctl(wsmuxdevs
[u
]->sc_base
.me_dv
, cmd
, data
, flag
, l
);
400 * ioctl of a mux via the parent mux, continuation of wsmuxioctl().
403 wsmux_do_ioctl(device_t dv
, u_long cmd
, void *data
, int flag
,
406 struct wsmux_softc
*sc
= device_private(dv
);
410 struct wseventvar
*evar
;
411 struct wscons_event event
;
412 struct wsmux_device_list
*l
;
414 DPRINTF(("wsmux_do_ioctl: %s: enter sc=%p, cmd=%08lx\n",
415 device_xname(sc
->sc_base
.me_dv
), sc
, cmd
));
418 #if defined(COMPAT_50) || defined(MODULAR)
419 case WSMUXIO_OINJECTEVENT
:
420 #endif /* defined(COMPAT_50) || defined(MODULAR) */
421 case WSMUXIO_INJECTEVENT
:
422 /* Inject an event, e.g., from moused. */
423 DPRINTF(("%s: inject\n", device_xname(sc
->sc_base
.me_dv
)));
425 evar
= sc
->sc_base
.me_evp
;
427 /* No event sink, so ignore it. */
428 DPRINTF(("wsmux_do_ioctl: event ignored\n"));
433 event
.type
= ((struct wscons_event
*)data
)->type
;
434 event
.value
= ((struct wscons_event
*)data
)->value
;
435 error
= wsevent_inject(evar
, &event
, 1);
439 case WSMUXIO_ADD_DEVICE
:
440 #define d ((struct wsmux_device *)data)
441 DPRINTF(("%s: add type=%d, no=%d\n",
442 device_xname(sc
->sc_base
.me_dv
), d
->type
, d
->idx
));
446 return (wsmouse_add_mux(d
->idx
, sc
));
450 return (wskbd_add_mux(d
->idx
, sc
));
453 return (wsmux_add_mux(d
->idx
, sc
));
457 case WSMUXIO_REMOVE_DEVICE
:
458 DPRINTF(("%s: rem type=%d, no=%d\n",
459 device_xname(sc
->sc_base
.me_dv
), d
->type
, d
->idx
));
460 /* Locate the device */
461 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
, me_next
) {
462 if (me
->me_ops
->type
== d
->type
&&
463 device_unit(me
->me_dv
) == d
->idx
) {
464 DPRINTF(("wsmux_do_ioctl: detach\n"));
472 case WSMUXIO_LIST_DEVICES
:
473 DPRINTF(("%s: list\n", device_xname(sc
->sc_base
.me_dv
)));
474 l
= (struct wsmux_device_list
*)data
;
476 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
, me_next
) {
477 if (n
>= WSMUX_MAXDEV
)
479 l
->devices
[n
].type
= me
->me_ops
->type
;
480 l
->devices
[n
].idx
= device_unit(me
->me_dv
);
485 #ifdef WSDISPLAY_COMPAT_RAWKBD
486 case WSKBDIO_SETMODE
:
487 sc
->sc_rawkbd
= *(int *)data
;
488 DPRINTF(("wsmux_do_ioctl: save rawkbd = %d\n", sc
->sc_rawkbd
));
492 DPRINTF(("%s: FIONBIO\n", device_xname(sc
->sc_base
.me_dv
)));
496 DPRINTF(("%s: FIOASYNC\n", device_xname(sc
->sc_base
.me_dv
)));
497 evar
= sc
->sc_base
.me_evp
;
500 evar
->async
= *(int *)data
!= 0;
503 DPRINTF(("%s: FIOSETOWN\n", device_xname(sc
->sc_base
.me_dv
)));
504 evar
= sc
->sc_base
.me_evp
;
507 if (-*(int *)data
!= evar
->io
->p_pgid
508 && *(int *)data
!= evar
->io
->p_pid
)
512 DPRINTF(("%s: TIOCSPGRP\n", device_xname(sc
->sc_base
.me_dv
)));
513 evar
= sc
->sc_base
.me_evp
;
516 if (*(int *)data
!= evar
->io
->p_pgid
)
520 DPRINTF(("%s: unknown\n", device_xname(sc
->sc_base
.me_dv
)));
524 if (sc
->sc_base
.me_evp
== NULL
526 && sc
->sc_base
.me_dispdv
== NULL
531 /* Return 0 if any of the ioctl() succeeds, otherwise the last error */
534 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
, me_next
) {
537 if (me
->me_parent
!= sc
) {
538 printf("wsmux_do_ioctl: bad child %p\n", me
);
542 error
= wsevsrc_ioctl(me
, cmd
, data
, flag
, lwp
);
543 DPRINTF(("wsmux_do_ioctl: %s: me=%p dev=%s ==> %d\n",
544 device_xname(sc
->sc_base
.me_dv
), me
,
545 device_xname(me
->me_dv
), error
));
551 if (cmd
== WSKBDIO_SETENCODING
) {
552 sc
->sc_kbd_layout
= *((kbd_t
*)data
);
561 * poll() of the pseudo device from device table.
564 wsmuxpoll(dev_t dev
, int events
, struct lwp
*l
)
566 int minr
= minor(dev
);
567 struct wsmux_softc
*sc
= wsmuxdevs
[WSMUXDEV(minr
)];
569 if (WSMUXCTL(minr
)) {
574 if (sc
->sc_base
.me_evp
== NULL
) {
576 printf("wsmuxpoll: not open\n");
581 return (wsevent_poll(sc
->sc_base
.me_evp
, events
, l
));
585 * kqfilter() of the pseudo device from device table.
588 wsmuxkqfilter(dev_t dev
, struct knote
*kn
)
590 int minr
= minor(dev
);
591 struct wsmux_softc
*sc
= wsmuxdevs
[WSMUXDEV(minr
)];
593 if (WSMUXCTL(minr
)) {
598 if (sc
->sc_base
.me_evp
== NULL
) {
600 printf("wsmuxkqfilter: not open\n");
605 return (wsevent_kqfilter(sc
->sc_base
.me_evp
, kn
));
609 * Add mux unit as a child to muxsc.
612 wsmux_add_mux(int unit
, struct wsmux_softc
*muxsc
)
614 struct wsmux_softc
*sc
, *m
;
616 sc
= wsmux_getmux(unit
);
620 DPRINTF(("wsmux_add_mux: %s(%p) to %s(%p)\n",
621 device_xname(sc
->sc_base
.me_dv
), sc
,
622 device_xname(muxsc
->sc_base
.me_dv
), muxsc
));
624 if (sc
->sc_base
.me_parent
!= NULL
|| sc
->sc_base
.me_evp
!= NULL
)
627 /* The mux we are adding must not be an ancestor of itself. */
628 for (m
= muxsc
; m
!= NULL
; m
= m
->sc_base
.me_parent
)
632 return (wsmux_attach_sc(muxsc
, &sc
->sc_base
));
635 /* Create a new mux softc. */
637 wsmux_create(const char *name
, int unit
)
639 struct wsmux_softc
*sc
;
641 /* XXX This is wrong -- should use autoconfiguraiton framework */
643 DPRINTF(("wsmux_create: allocating\n"));
644 sc
= malloc(sizeof *sc
, M_DEVBUF
, M_NOWAIT
|M_ZERO
);
647 sc
->sc_base
.me_dv
= malloc(sizeof(struct device
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
648 if (sc
->sc_base
.me_dv
== NULL
) {
652 CIRCLEQ_INIT(&sc
->sc_cld
);
653 snprintf(sc
->sc_base
.me_dv
->dv_xname
, sizeof sc
->sc_base
.me_dv
->dv_xname
,
655 sc
->sc_base
.me_dv
->dv_private
= sc
;
656 sc
->sc_base
.me_dv
->dv_unit
= unit
;
657 sc
->sc_base
.me_ops
= &wsmux_srcops
;
658 sc
->sc_kbd_layout
= KB_NONE
;
662 /* Attach me as a child to sc. */
664 wsmux_attach_sc(struct wsmux_softc
*sc
, struct wsevsrc
*me
)
671 DPRINTF(("wsmux_attach_sc: %s(%p): type=%d\n",
672 device_xname(sc
->sc_base
.me_dv
), sc
, me
->me_ops
->type
));
675 if (me
->me_parent
!= NULL
) {
676 printf("wsmux_attach_sc: busy\n");
681 CIRCLEQ_INSERT_TAIL(&sc
->sc_cld
, me
, me_next
);
685 if (sc
->sc_base
.me_dispdv
!= NULL
) {
686 /* This is a display mux, so attach the new device to it. */
687 DPRINTF(("wsmux_attach_sc: %s: set display %p\n",
688 device_xname(sc
->sc_base
.me_dv
),
689 sc
->sc_base
.me_dispdv
));
690 if (me
->me_ops
->dsetdisplay
!= NULL
) {
691 error
= wsevsrc_set_display(me
, &sc
->sc_base
);
692 /* Ignore that the console already has a display. */
696 #ifdef WSDISPLAY_COMPAT_RAWKBD
697 DPRINTF(("wsmux_attach_sc: %s set rawkbd=%d\n",
698 device_xname(me
->me_dv
),
700 (void)wsevsrc_ioctl(me
, WSKBDIO_SETMODE
,
701 &sc
->sc_rawkbd
, 0, 0);
703 if (sc
->sc_kbd_layout
!= KB_NONE
)
704 (void)wsevsrc_ioctl(me
,
706 &sc
->sc_kbd_layout
, FWRITE
, 0);
711 if (sc
->sc_base
.me_evp
!= NULL
) {
712 /* Mux is open, so open the new subdevice */
713 DPRINTF(("wsmux_attach_sc: %s: calling open of %s\n",
714 device_xname(sc
->sc_base
.me_dv
),
715 device_xname(me
->me_dv
)));
716 error
= wsevsrc_open(me
, sc
->sc_base
.me_evp
);
718 DPRINTF(("wsmux_attach_sc: %s not open\n",
719 device_xname(sc
->sc_base
.me_dv
)));
723 me
->me_parent
= NULL
;
724 CIRCLEQ_REMOVE(&sc
->sc_cld
, me
, me_next
);
727 DPRINTF(("wsmux_attach_sc: %s(%p) done, error=%d\n",
728 device_xname(sc
->sc_base
.me_dv
), sc
, error
));
732 /* Remove me from the parent. */
734 wsmux_detach_sc(struct wsevsrc
*me
)
736 struct wsmux_softc
*sc
= me
->me_parent
;
738 DPRINTF(("wsmux_detach_sc: %s(%p) parent=%p\n",
739 device_xname(me
->me_dv
), me
, sc
));
743 printf("wsmux_detach_sc: %s has no parent\n",
744 device_xname(me
->me_dv
));
750 if (sc
->sc_base
.me_dispdv
!= NULL
) {
751 if (me
->me_ops
->dsetdisplay
!= NULL
)
752 /* ignore error, there's nothing we can do */
753 (void)wsevsrc_set_display(me
, NULL
);
756 if (me
->me_evp
!= NULL
) {
757 DPRINTF(("wsmux_detach_sc: close\n"));
758 /* mux device is open, so close multiplexee */
759 (void)wsevsrc_close(me
);
762 CIRCLEQ_REMOVE(&sc
->sc_cld
, me
, me_next
);
763 me
->me_parent
= NULL
;
765 DPRINTF(("wsmux_detach_sc: done sc=%p\n", sc
));
769 * Display ioctl() of a mux via the parent mux.
772 wsmux_do_displayioctl(device_t dv
, u_long cmd
, void *data
, int flag
,
775 struct wsmux_softc
*sc
= device_private(dv
);
779 DPRINTF(("wsmux_displayioctl: %s: sc=%p, cmd=%08lx\n",
780 device_xname(sc
->sc_base
.me_dv
), sc
, cmd
));
782 #ifdef WSDISPLAY_COMPAT_RAWKBD
783 if (cmd
== WSKBDIO_SETMODE
) {
784 sc
->sc_rawkbd
= *(int *)data
;
785 DPRINTF(("wsmux_displayioctl: rawkbd = %d\n", sc
->sc_rawkbd
));
790 * Return 0 if any of the ioctl() succeeds, otherwise the last error.
791 * Return EPASSTHROUGH if no mux component accepts the ioctl.
793 error
= EPASSTHROUGH
;
795 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
, me_next
) {
796 DPRINTF(("wsmux_displayioctl: me=%p\n", me
));
798 if (me
->me_parent
!= sc
) {
799 printf("wsmux_displayioctl: bad child %p\n", me
);
803 if (me
->me_ops
->ddispioctl
!= NULL
) {
804 error
= wsevsrc_display_ioctl(me
, cmd
, data
, flag
, l
);
805 DPRINTF(("wsmux_displayioctl: me=%p dev=%s ==> %d\n",
806 me
, device_xname(me
->me_dv
), error
));
819 * Set display of a mux via the parent mux.
822 wsmux_evsrc_set_display(device_t dv
, struct wsevsrc
*ame
)
824 struct wsmux_softc
*muxsc
= (struct wsmux_softc
*)ame
;
825 struct wsmux_softc
*sc
= device_private(dv
);
826 device_t displaydv
= muxsc
? muxsc
->sc_base
.me_dispdv
: NULL
;
828 DPRINTF(("wsmux_set_display: %s: displaydv=%p\n",
829 device_xname(sc
->sc_base
.me_dv
), displaydv
));
831 if (displaydv
!= NULL
) {
832 if (sc
->sc_base
.me_dispdv
!= NULL
)
835 if (sc
->sc_base
.me_dispdv
== NULL
)
839 return wsmux_set_display(sc
, displaydv
);
843 wsmux_set_display(struct wsmux_softc
*sc
, device_t displaydv
)
847 struct wsmux_softc
*nsc
= displaydv
? sc
: NULL
;
850 odisplaydv
= sc
->sc_base
.me_dispdv
;
851 sc
->sc_base
.me_dispdv
= displaydv
;
854 aprint_verbose_dev(sc
->sc_base
.me_dv
, "connecting to %s\n",
855 device_xname(displaydv
));
858 CIRCLEQ_FOREACH(me
, &sc
->sc_cld
,me_next
) {
860 if (me
->me_parent
!= sc
) {
861 printf("wsmux_set_display: bad child parent %p\n", me
);
865 if (me
->me_ops
->dsetdisplay
!= NULL
) {
866 error
= wsevsrc_set_display(me
, &nsc
->sc_base
);
867 DPRINTF(("wsmux_set_display: m=%p dev=%s error=%d\n",
868 me
, device_xname(me
->me_dv
), error
));
871 #ifdef WSDISPLAY_COMPAT_RAWKBD
872 DPRINTF(("wsmux_set_display: %s set rawkbd=%d\n",
873 device_xname(me
->me_dv
), sc
->sc_rawkbd
));
874 (void)wsevsrc_ioctl(me
, WSKBDIO_SETMODE
,
875 &sc
->sc_rawkbd
, 0, 0);
883 if (displaydv
== NULL
)
884 aprint_verbose("%s: disconnecting from %s\n",
885 device_xname(sc
->sc_base
.me_dv
),
886 device_xname(odisplaydv
));
890 #endif /* NWSDISPLAY > 0 */