wsmux.c revision 1.12 1 /* $NetBSD: wsmux.c,v 1.12 2001/10/13 20:03:38 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 #include "wsmouse.h"
43
44 #if NWSMUX > 0 || (NWSDISPLAY > 0 && NWSKBD > 0)
45
46 /*
47 * wscons mux device.
48 *
49 * The mux device is a collection of real mice and keyboards and acts as
50 * a merge point for all the events from the different real devices.
51 */
52
53 #include <sys/param.h>
54 #include <sys/conf.h>
55 #include <sys/ioctl.h>
56 #include <sys/fcntl.h>
57 #include <sys/kernel.h>
58 #include <sys/malloc.h>
59 #include <sys/proc.h>
60 #include <sys/queue.h>
61 #include <sys/syslog.h>
62 #include <sys/systm.h>
63 #include <sys/tty.h>
64 #include <sys/signalvar.h>
65 #include <sys/device.h>
66
67 #include "opt_wsdisplay_compat.h"
68
69 #include <dev/wscons/wsconsio.h>
70 #include <dev/wscons/wseventvar.h>
71 #include <dev/wscons/wscons_callbacks.h>
72 #include <dev/wscons/wsmuxvar.h>
73
74 #ifdef WSMUX_DEBUG
75 #define DPRINTF(x) if (wsmuxdebug) printf x
76 int wsmuxdebug = 0;
77 #else
78 #define DPRINTF(x)
79 #endif
80
81 struct wsplink {
82 LIST_ENTRY(wsplink) next;
83 int type;
84 struct wsmux_softc *mux; /* our mux device */
85 /* The rest of the fields reflect a value in the multiplexee. */
86 struct device *sc; /* softc */
87 struct wseventvar *sc_mevents; /* event var */
88 struct wsmux_softc **sc_muxp; /* pointer to us */
89 struct wsmuxops *sc_ops;
90 };
91
92 int wsmuxdoclose(struct device *, int, int, struct proc *);
93 int wsmux_set_display(struct device *, struct wsmux_softc *);
94
95 #if NWSMUX > 0
96
97 #define WSMUXDEV(n) ((n) & 0x7f)
98 #define WSMUXCTL(n) ((n) & 0x80)
99
100 cdev_decl(wsmux);
101
102 void wsmuxattach(int);
103
104 struct wsmuxops wsmux_muxops = {
105 wsmuxopen, wsmuxdoclose, wsmuxdoioctl, wsmux_displayioctl,
106 wsmux_set_display
107 };
108
109 void wsmux_setmax(int n);
110
111 int nwsmux = 0;
112 struct wsmux_softc **wsmuxdevs;
113
114 void
115 wsmux_setmax(int n)
116 {
117 int i;
118
119 if (n >= nwsmux) {
120 i = nwsmux;
121 nwsmux = n + 1;
122 if (i != 0)
123 wsmuxdevs = realloc(wsmuxdevs,
124 nwsmux * sizeof (*wsmuxdevs),
125 M_DEVBUF, M_NOWAIT);
126 else
127 wsmuxdevs = malloc(nwsmux * sizeof (*wsmuxdevs),
128 M_DEVBUF, M_NOWAIT);
129 if (wsmuxdevs == NULL)
130 panic("wsmux_setmax: no memory\n");
131 for (; i < nwsmux; i++)
132 wsmuxdevs[i] = 0;
133 }
134 }
135
136 /* From upper level */
137 void
138 wsmuxattach(int n)
139 {
140 }
141
142 /* Return mux n, create if necessary */
143 struct wsmux_softc *
144 wsmux_getmux(int n)
145 {
146 struct wsmux_softc *sc;
147
148 wsmux_setmax(n);
149 sc = wsmuxdevs[n];
150 if (sc == 0) {
151 sc = wsmux_create("wsmux", n);
152 if (sc == 0) {
153 printf("wsmux: attach out of memory\n");
154 return (NULL);
155 }
156 wsmuxdevs[n] = sc;
157 }
158 return (sc);
159 }
160
161 /* From mouse or keyboard. */
162 void
163 wsmux_attach(int n, int type, struct device *dsc, struct wseventvar *ev,
164 struct wsmux_softc **psp, struct wsmuxops *ops)
165 {
166 struct wsmux_softc *sc;
167 int error;
168
169 DPRINTF(("wsmux_attach: n=%d\n", n));
170 sc = wsmux_getmux(n);
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(int n, struct device *dsc)
179 {
180 #ifdef DIAGNOSTIC
181 int error;
182
183 if (n >= nwsmux || n < 0) {
184 printf("wsmux_detach: detach is out of range\n");
185 return;
186 }
187 if ((error = wsmux_detach_sc(wsmuxdevs[n], dsc)))
188 printf("wsmux_detach: error=%d\n", error);
189 #else
190 (void)wsmux_detach_sc(wsmuxdevs[n], dsc);
191 #endif
192 }
193
194 int
195 wsmuxopen(dev_t dev, int flags, int mode, struct proc *p)
196 {
197 struct wsmux_softc *sc;
198 struct wsplink *m;
199 int munit, unit, error, nopen, lasterror;
200
201 munit = minor(dev);
202 unit = WSMUXDEV(munit);
203 sc = wsmux_getmux(unit);
204 if (sc == NULL)
205 return (ENXIO);
206
207 DPRINTF(("wsmuxopen: %s: sc=%p\n", sc->sc_dv.dv_xname, sc));
208 if (WSMUXCTL(munit)) {
209 /* This is the control device which does not allow reads. */
210 if (flags & FREAD)
211 return (EINVAL);
212 return (0);
213 }
214
215 if (sc->sc_mux) {
216 /* Grab the mux out of the greedy hands of the parent mux. */
217 int error = wsmux_rem_mux(unit, sc->sc_mux);
218 if (error)
219 return (error);
220 }
221
222 if (sc->sc_events.io)
223 return (EBUSY);
224
225 sc->sc_events.io = p;
226 sc->sc_flags = flags;
227 sc->sc_mode = mode;
228 sc->sc_p = p;
229 wsevent_init(&sc->sc_events); /* may cause sleep */
230
231 nopen = 0;
232 lasterror = 0;
233 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
234 if (!m->sc_mevents->io && !*m->sc_muxp) {
235 DPRINTF(("wsmuxopen: %s: m=%p dev=%s\n",
236 sc->sc_dv.dv_xname, m, m->sc->dv_xname));
237 error = m->sc_ops->dopen(makedev(0, m->sc->dv_unit),
238 flags, mode, p);
239 if (error) {
240 /* Ignore opens that fail */
241 lasterror = error;
242 DPRINTF(("wsmuxopen: open failed %d\n",
243 error));
244 } else {
245 nopen++;
246 *m->sc_muxp = sc;
247 }
248 }
249 }
250
251 if (nopen == 0 && lasterror != 0) {
252 wsevent_fini(&sc->sc_events);
253 sc->sc_events.io = NULL;
254 return (lasterror);
255 }
256
257 return (0);
258 }
259
260 int
261 wsmuxclose(dev_t dev, int flags, int mode, struct proc *p)
262 {
263 int munit = minor(dev);
264
265 if (WSMUXCTL(munit)) {
266 /* control device */
267 return (0);
268 }
269 return wsmuxdoclose(&wsmuxdevs[WSMUXDEV(munit)]->sc_dv, flags, mode, p);
270 }
271
272 int
273 wsmuxread(dev_t dev, struct uio *uio, int flags)
274 {
275 int munit = minor(dev);
276 struct wsmux_softc *sc = wsmuxdevs[WSMUXDEV(munit)];
277
278 if (WSMUXCTL(munit)) {
279 /* control device */
280 return (EINVAL);
281 }
282
283 if (!sc->sc_events.io)
284 return (EACCES);
285
286 return (wsevent_read(&sc->sc_events, uio, flags));
287 }
288
289 int
290 wsmuxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
291 {
292 int unit = WSMUXDEV(minor(dev));
293
294 return wsmuxdoioctl(&wsmuxdevs[unit]->sc_dv, cmd, data, flag, p);
295 }
296
297 int
298 wsmuxpoll(dev_t dev, int events, struct proc *p)
299 {
300 int munit = minor(dev);
301 struct wsmux_softc *sc = wsmuxdevs[WSMUXDEV(munit)];
302
303 if (WSMUXCTL(munit)) {
304 /* control device */
305 return (EINVAL);
306 }
307
308 if (!sc->sc_events.io)
309 return (EACCES);
310
311 return (wsevent_poll(&sc->sc_events, events, p));
312 }
313
314 int
315 wsmux_add_mux(int unit, struct wsmux_softc *muxsc)
316 {
317 struct wsmux_softc *sc, *m;
318
319 sc = wsmux_getmux(unit);
320 if (sc == NULL)
321 return (ENXIO);
322
323 DPRINTF(("wsmux_add_mux: %s(%p) to %s(%p)\n", sc->sc_dv.dv_xname, sc,
324 muxsc->sc_dv.dv_xname, muxsc));
325
326 if (sc->sc_mux || sc->sc_events.io)
327 return (EBUSY);
328
329 /* The mux we are adding must not be an ancestor of itself. */
330 for (m = muxsc; m; m = m->sc_mux)
331 if (m == sc)
332 return (EINVAL);
333
334 return (wsmux_attach_sc(muxsc, WSMUX_MUX, &sc->sc_dv, &sc->sc_events,
335 &sc->sc_mux, &wsmux_muxops));
336 }
337
338 int
339 wsmux_rem_mux(int unit, struct wsmux_softc *muxsc)
340 {
341 struct wsmux_softc *sc;
342
343 if (unit < 0 || unit >= nwsmux || (sc = wsmuxdevs[unit]) == NULL)
344 return (ENXIO);
345
346 DPRINTF(("wsmux_rem_mux: %s from %s\n", sc->sc_dv.dv_xname,
347 muxsc->sc_dv.dv_xname));
348
349 return (wsmux_detach_sc(muxsc, &sc->sc_dv));
350 }
351
352 #endif /* NWSMUX > 0 */
353
354 struct wsmux_softc *
355 wsmux_create(const char *name, int unit)
356 {
357 struct wsmux_softc *sc;
358
359 DPRINTF(("wsmux_create: allocating\n"));
360 sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
361 if (sc == NULL)
362 return (NULL);
363 memset(sc, 0, sizeof *sc);
364 LIST_INIT(&sc->sc_reals);
365 snprintf(sc->sc_dv.dv_xname, sizeof sc->sc_dv.dv_xname,
366 "%s%d", name, unit);
367 sc->sc_dv.dv_unit = unit;
368 return (sc);
369 }
370
371 int
372 wsmux_attach_sc(struct wsmux_softc *sc, int type, struct device *dsc,
373 struct wseventvar *ev, struct wsmux_softc **psp, struct wsmuxops *ops)
374 {
375 struct wsplink *m;
376 int error;
377
378 DPRINTF(("wsmux_attach_sc: %s: type=%d dsc=%p, *psp=%p\n",
379 sc->sc_dv.dv_xname, type, dsc, *psp));
380 m = malloc(sizeof *m, M_DEVBUF, M_NOWAIT);
381 if (m == NULL)
382 return (ENOMEM);
383 m->type = type;
384 m->mux = sc;
385 m->sc = dsc;
386 m->sc_mevents = ev;
387 m->sc_muxp = psp;
388 m->sc_ops = ops;
389 LIST_INSERT_HEAD(&sc->sc_reals, m, next);
390
391 if (sc->sc_displaydv) {
392 /* This is a display mux, so attach the new device to it. */
393 DPRINTF(("wsmux_attach_sc: %s: set display %p\n",
394 sc->sc_dv.dv_xname, sc->sc_displaydv));
395 error = 0;
396 if (m->sc_ops->dsetdisplay) {
397 error = m->sc_ops->dsetdisplay(m->sc, sc);
398 /* Ignore that the console already has a display. */
399 if (error == EBUSY)
400 error = 0;
401 if (!error) {
402 *m->sc_muxp = sc;
403 #ifdef WSDISPLAY_COMPAT_RAWKBD
404 DPRINTF(("wsmux_attach_sc: on %s set rawkbd=%d\n",
405 m->sc->dv_xname, sc->sc_rawkbd));
406 (void)m->sc_ops->dioctl(m->sc,
407 WSKBDIO_SETMODE,
408 (caddr_t)&sc->sc_rawkbd,
409 0, 0);
410 #endif
411 }
412 }
413 } else if (sc->sc_events.io) {
414 /* Mux is open, so open the new subdevice */
415 DPRINTF(("wsmux_attach_sc: %s: calling open of %s\n",
416 sc->sc_dv.dv_xname, m->sc->dv_xname));
417 /* mux already open, join in */
418 error = m->sc_ops->dopen(makedev(0, m->sc->dv_unit),
419 sc->sc_flags, sc->sc_mode, sc->sc_p);
420 if (!error)
421 *m->sc_muxp = sc;
422 } else {
423 DPRINTF(("wsmux_attach_sc: %s not open\n",
424 sc->sc_dv.dv_xname));
425 error = 0;
426 }
427 DPRINTF(("wsmux_attach_sc: done sc=%p psp=%p *psp=%p\n",
428 sc, psp, *psp));
429
430 return (error);
431 }
432
433 int
434 wsmux_detach_sc(struct wsmux_softc *sc, struct device *dsc)
435 {
436 struct wsplink *m;
437 int error = 0;
438
439 DPRINTF(("wsmux_detach_sc: %s: dsc=%p\n", sc->sc_dv.dv_xname, dsc));
440 #ifdef DIAGNOSTIC
441 if (sc == 0) {
442 printf("wsmux_detach_sc: not allocated\n");
443 return (ENXIO);
444 }
445 #endif
446
447 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
448 if (m->sc == dsc)
449 break;
450 }
451 #ifdef DIAGNOSTIC
452 if (!m) {
453 printf("wsmux_detach_sc: not found\n");
454 return (ENXIO);
455 }
456 #endif
457 if (sc->sc_displaydv) {
458 if (m->sc_ops->dsetdisplay)
459 error = m->sc_ops->dsetdisplay(m->sc, 0);
460 if (error)
461 return (error);
462 *m->sc_muxp = 0;
463 } else if (*m->sc_muxp) {
464 DPRINTF(("wsmux_detach_sc: close\n"));
465 /* mux device is open, so close multiplexee */
466 m->sc_ops->dclose(m->sc, FREAD, 0, 0);
467 *m->sc_muxp = 0;
468 }
469
470 LIST_REMOVE(m, next);
471
472 free(m, M_DEVBUF);
473 DPRINTF(("wsmux_detach_sc: done sc=%p\n", sc));
474 return (0);
475 }
476
477 int
478 wsmuxdoclose(struct device *dv, int flags, int mode, struct proc *p)
479 {
480 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
481 struct wsplink *m;
482
483 DPRINTF(("wsmuxclose: %s: sc=%p\n", sc->sc_dv.dv_xname, sc));
484
485 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
486 if (*m->sc_muxp == sc) {
487 DPRINTF(("wsmuxclose %s: m=%p dev=%s\n",
488 sc->sc_dv.dv_xname, m, m->sc->dv_xname));
489 m->sc_ops->dclose(m->sc, flags, mode, p);
490 *m->sc_muxp = 0;
491 }
492 }
493
494 wsevent_fini(&sc->sc_events);
495 sc->sc_events.io = NULL;
496
497 return (0);
498 }
499
500 int
501 wsmuxdoioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
502 struct proc *p)
503 {
504 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
505 struct wsplink *m;
506 int error, ok;
507 int s, put, get, n;
508 struct wseventvar *evar;
509 struct wscons_event *ev;
510 struct timeval xxxtime;
511 struct wsmux_device_list *l;
512
513 DPRINTF(("wsmuxdoioctl: %s: sc=%p, cmd=%08lx\n",
514 sc->sc_dv.dv_xname, sc, cmd));
515
516 switch (cmd) {
517 case WSMUX_INJECTEVENT:
518 /* Inject an event, e.g., from moused. */
519 if (!sc->sc_events.io)
520 return (EACCES);
521
522 evar = &sc->sc_events;
523 s = spltty();
524 get = evar->get;
525 put = evar->put;
526 if (++put % WSEVENT_QSIZE == get) {
527 put--;
528 splx(s);
529 return (ENOSPC);
530 }
531 if (put >= WSEVENT_QSIZE)
532 put = 0;
533 ev = &evar->q[put];
534 *ev = *(struct wscons_event *)data;
535 microtime(&xxxtime);
536 TIMEVAL_TO_TIMESPEC(&xxxtime, &ev->time);
537 evar->put = put;
538 WSEVENT_WAKEUP(evar);
539 splx(s);
540 return (0);
541 case WSMUX_ADD_DEVICE:
542 #define d ((struct wsmux_device *)data)
543 switch (d->type) {
544 #if NWSMOUSE > 0
545 case WSMUX_MOUSE:
546 return (wsmouse_add_mux(d->idx, sc));
547 #endif
548 #if NWSKBD > 0
549 case WSMUX_KBD:
550 return (wskbd_add_mux(d->idx, sc));
551 #endif
552 #if NWSMUX > 0
553 case WSMUX_MUX:
554 return (wsmux_add_mux(d->idx, sc));
555 #endif
556 default:
557 return (EINVAL);
558 }
559 case WSMUX_REMOVE_DEVICE:
560 switch (d->type) {
561 #if NWSMOUSE > 0
562 case WSMUX_MOUSE:
563 return (wsmouse_rem_mux(d->idx, sc));
564 #endif
565 #if NWSKBD > 0
566 case WSMUX_KBD:
567 return (wskbd_rem_mux(d->idx, sc));
568 #endif
569 #if NWSMUX > 0
570 case WSMUX_MUX:
571 return (wsmux_rem_mux(d->idx, sc));
572 #endif
573 default:
574 return (EINVAL);
575 }
576 #undef d
577 case WSMUX_LIST_DEVICES:
578 l = (struct wsmux_device_list *)data;
579 for (n = 0, m = LIST_FIRST(&sc->sc_reals);
580 n < WSMUX_MAXDEV && m != NULL;
581 m = LIST_NEXT(m, next)) {
582 l->devices[n].type = m->type;
583 l->devices[n].idx = m->sc->dv_unit;
584 n++;
585 }
586 l->ndevices = n;
587 return (0);
588 #ifdef WSDISPLAY_COMPAT_RAWKBD
589 case WSKBDIO_SETMODE:
590 sc->sc_rawkbd = *(int *)data;
591 DPRINTF(("wsmuxdoioctl: save rawkbd = %d\n", sc->sc_rawkbd));
592 break;
593 #endif
594 case FIOASYNC:
595 sc->sc_events.async = *(int *)data != 0;
596 return (0);
597 case TIOCSPGRP:
598 if (*(int *)data != sc->sc_events.io->p_pgid)
599 return (EPERM);
600 return (0);
601 default:
602 break;
603 }
604
605 if (sc->sc_events.io == NULL && sc->sc_displaydv == NULL)
606 return (EACCES);
607
608 /* Return 0 if any of the ioctl() succeeds, otherwise the last error */
609 error = 0;
610 ok = 0;
611 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
612 DPRINTF(("wsmuxdoioctl: m=%p *m->sc_muxp=%p sc=%p\n",
613 m, *m->sc_muxp, sc));
614 if (*m->sc_muxp == sc) {
615 DPRINTF(("wsmuxdoioctl: %s: m=%p dev=%s\n",
616 sc->sc_dv.dv_xname, m, m->sc->dv_xname));
617 error = m->sc_ops->dioctl(m->sc, cmd, data, flag, p);
618 if (!error)
619 ok = 1;
620 }
621 }
622 if (ok)
623 error = 0;
624
625 return (error);
626 }
627
628 int
629 wsmux_displayioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
630 struct proc *p)
631 {
632 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
633 struct wsplink *m;
634 int error, ok;
635
636 DPRINTF(("wsmux_displayioctl: %s: sc=%p, cmd=%08lx\n",
637 sc->sc_dv.dv_xname, sc, cmd));
638
639 #ifdef WSDISPLAY_COMPAT_RAWKBD
640 if (cmd == WSKBDIO_SETMODE) {
641 sc->sc_rawkbd = *(int *)data;
642 DPRINTF(("wsmux_displayioctl: rawkbd = %d\n", sc->sc_rawkbd));
643 }
644 #endif
645
646 /*
647 * Return 0 if any of the ioctl() succeeds, otherwise the last error.
648 * Return -1 if no mux component accepts the ioctl.
649 */
650 error = -1;
651 ok = 0;
652 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
653 DPRINTF(("wsmux_displayioctl: m=%p sc=%p sc_muxp=%p\n",
654 m, sc, *m->sc_muxp));
655 if (m->sc_ops->ddispioctl && *m->sc_muxp == sc) {
656 error = m->sc_ops->ddispioctl(m->sc, cmd, data,
657 flag, p);
658 DPRINTF(("wsmux_displayioctl: m=%p dev=%s ==> %d\n",
659 m, m->sc->dv_xname, error));
660 if (!error)
661 ok = 1;
662 }
663 }
664 if (ok)
665 error = 0;
666
667 return (error);
668 }
669
670 int
671 wsmux_set_display(struct device *dv, struct wsmux_softc *muxsc)
672 {
673 struct wsmux_softc *sc = (struct wsmux_softc *)dv;
674 struct wsmux_softc *nsc = muxsc ? sc : 0;
675 struct device *displaydv = muxsc ? muxsc->sc_displaydv : 0;
676 struct device *odisplaydv;
677 struct wsplink *m;
678 int error, ok;
679
680 DPRINTF(("wsmux_set_display: %s: displaydv=%p\n",
681 sc->sc_dv.dv_xname, displaydv));
682
683 if (displaydv) {
684 if (sc->sc_displaydv)
685 return (EBUSY);
686 } else {
687 if (sc->sc_displaydv == NULL)
688 return (ENXIO);
689 }
690
691 odisplaydv = sc->sc_displaydv;
692 sc->sc_displaydv = displaydv;
693
694 if (displaydv)
695 printf("%s: connecting to %s\n",
696 sc->sc_dv.dv_xname, displaydv->dv_xname);
697 ok = 0;
698 error = 0;
699 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) {
700 if (m->sc_ops->dsetdisplay &&
701 (nsc ? m->sc_mevents->io == 0 && *m->sc_muxp == 0 :
702 *m->sc_muxp == sc)) {
703 error = m->sc_ops->dsetdisplay(m->sc, nsc);
704 DPRINTF(("wsmux_set_display: m=%p dev=%s error=%d\n",
705 m, m->sc->dv_xname, error));
706 if (!error) {
707 ok = 1;
708 *m->sc_muxp = nsc;
709 #ifdef WSDISPLAY_COMPAT_RAWKBD
710 DPRINTF(("wsmux_set_display: on %s set rawkbd=%d\n",
711 m->sc->dv_xname, sc->sc_rawkbd));
712 (void)m->sc_ops->dioctl(m->sc,
713 WSKBDIO_SETMODE,
714 (caddr_t)&sc->sc_rawkbd,
715 0, 0);
716 #endif
717 }
718 }
719 }
720 if (ok)
721 error = 0;
722
723 if (displaydv == NULL)
724 printf("%s: disconnecting from %s\n",
725 sc->sc_dv.dv_xname, odisplaydv->dv_xname);
726
727 return (error);
728 }
729
730 #endif /* NWSMUX > 0 || (NWSDISPLAY > 0 && NWSKBD > 0) */
731