1 /* $NetBSD: wsmux.c,v 1.9 2000/05/28 10:33:14 takemura Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Author: Lennart Augustsson <augustss@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 = 0; 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 /* Nothing to do, because open didn't do anything. */ 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 case FIOASYNC: 606 sc->sc_events.async = *(int *)data != 0; 607 return (0); 608 case TIOCSPGRP: 609 if (*(int *)data != sc->sc_events.io->p_pgid) 610 return (EPERM); 611 return (0); 612 default: 613 break; 614 } 615 616 if (sc->sc_events.io == NULL && sc->sc_displaydv == NULL) 617 return (EACCES); 618 619 /* Return 0 if any of the ioctl() succeeds, otherwise the last error */ 620 error = 0; 621 ok = 0; 622 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) { 623 DPRINTF(("wsmuxdoioctl: m=%p *m->sc_muxp=%p sc=%p\n", 624 m, *m->sc_muxp, sc)); 625 if (*m->sc_muxp == sc) { 626 DPRINTF(("wsmuxdoioctl: %s: m=%p dev=%s\n", 627 sc->sc_dv.dv_xname, m, m->sc->dv_xname)); 628 error = m->sc_ops->dioctl(m->sc, cmd, data, flag, p); 629 if (!error) 630 ok = 1; 631 } 632 } 633 if (ok) 634 error = 0; 635 636 return (error); 637 } 638 639 int 640 wsmux_displayioctl(dv, cmd, data, flag, p) 641 struct device *dv; 642 u_long cmd; 643 caddr_t data; 644 int flag; 645 struct proc *p; 646 { 647 struct wsmux_softc *sc = (struct wsmux_softc *)dv; 648 struct wsplink *m; 649 int error, ok; 650 651 DPRINTF(("wsmux_displayioctl: %s: sc=%p, cmd=%08lx\n", 652 sc->sc_dv.dv_xname, sc, cmd)); 653 654 #ifdef WSDISPLAY_COMPAT_RAWKBD 655 if (cmd == WSKBDIO_SETMODE) { 656 sc->sc_rawkbd = *(int *)data; 657 DPRINTF(("wsmux_displayioctl: rawkbd = %d\n", sc->sc_rawkbd)); 658 } 659 #endif 660 661 /* 662 * Return 0 if any of the ioctl() succeeds, otherwise the last error. 663 * Return -1 if no mux component accepts the ioctl. 664 */ 665 error = -1; 666 ok = 0; 667 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) { 668 DPRINTF(("wsmux_displayioctl: m=%p sc=%p sc_muxp=%p\n", 669 m, sc, *m->sc_muxp)); 670 if (m->sc_ops->ddispioctl && *m->sc_muxp == sc) { 671 error = m->sc_ops->ddispioctl(m->sc, cmd, data, 672 flag, p); 673 DPRINTF(("wsmux_displayioctl: m=%p dev=%s ==> %d\n", 674 m, m->sc->dv_xname, error)); 675 if (!error) 676 ok = 1; 677 } 678 } 679 if (ok) 680 error = 0; 681 682 return (error); 683 } 684 685 int 686 wsmux_set_display(dv, muxsc) 687 struct device *dv; 688 struct wsmux_softc *muxsc; 689 { 690 struct wsmux_softc *sc = (struct wsmux_softc *)dv; 691 struct wsmux_softc *nsc = muxsc ? sc : 0; 692 struct device *displaydv = muxsc ? muxsc->sc_displaydv : 0; 693 struct device *odisplaydv; 694 struct wsplink *m; 695 int error, ok; 696 697 DPRINTF(("wsmux_set_display: %s: displaydv=%p\n", 698 sc->sc_dv.dv_xname, displaydv)); 699 700 if (displaydv) { 701 if (sc->sc_displaydv) 702 return (EBUSY); 703 } else { 704 if (sc->sc_displaydv == NULL) 705 return (ENXIO); 706 } 707 708 odisplaydv = sc->sc_displaydv; 709 sc->sc_displaydv = displaydv; 710 711 if (displaydv) 712 printf("%s: connecting to %s\n", 713 sc->sc_dv.dv_xname, displaydv->dv_xname); 714 ok = 0; 715 error = 0; 716 for (m = LIST_FIRST(&sc->sc_reals); m; m = LIST_NEXT(m, next)) { 717 if (m->sc_ops->dsetdisplay && 718 (nsc ? m->sc_mevents->io == 0 && *m->sc_muxp == 0 : 719 *m->sc_muxp == sc)) { 720 error = m->sc_ops->dsetdisplay(m->sc, nsc); 721 DPRINTF(("wsmux_set_display: m=%p dev=%s error=%d\n", 722 m, m->sc->dv_xname, error)); 723 if (!error) { 724 ok = 1; 725 *m->sc_muxp = nsc; 726 #ifdef WSDISPLAY_COMPAT_RAWKBD 727 DPRINTF(("wsmux_set_display: on %s set rawkbd=%d\n", 728 m->sc->dv_xname, sc->sc_rawkbd)); 729 (void)m->sc_ops->dioctl(m->sc, 730 WSKBDIO_SETMODE, 731 (caddr_t)&sc->sc_rawkbd, 732 0, 0); 733 #endif 734 } 735 } 736 } 737 if (ok) 738 error = 0; 739 740 if (displaydv == NULL) 741 printf("%s: disconnecting from %s\n", 742 sc->sc_dv.dv_xname, odisplaydv->dv_xname); 743 744 return (error); 745 } 746 747 #endif /* NWSMUX > 0 || (NWSDISPLAY > 0 && NWSKBD > 0) */ 748