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