1 /* $NetBSD: wsmouse.c,v 1.38 2005/12/11 12:24:12 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1992, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * This software was developed by the Computer Systems Engineering group 38 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 39 * contributed to Berkeley. 40 * 41 * All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed by the University of 44 * California, Lawrence Berkeley Laboratory. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)ms.c 8.1 (Berkeley) 6/11/93 71 */ 72 73 /* 74 * Mouse driver. 75 */ 76 77 #include <sys/cdefs.h> 78 __KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v 1.38 2005/12/11 12:24:12 christos Exp $"); 79 80 #include "wsmouse.h" 81 #include "wsdisplay.h" 82 #include "wsmux.h" 83 84 #include <sys/param.h> 85 #include <sys/conf.h> 86 #include <sys/ioctl.h> 87 #include <sys/poll.h> 88 #include <sys/fcntl.h> 89 #include <sys/kernel.h> 90 #include <sys/proc.h> 91 #include <sys/syslog.h> 92 #include <sys/systm.h> 93 #include <sys/tty.h> 94 #include <sys/signalvar.h> 95 #include <sys/device.h> 96 #include <sys/vnode.h> 97 98 #include <dev/wscons/wsconsio.h> 99 #include <dev/wscons/wsmousevar.h> 100 #include <dev/wscons/wseventvar.h> 101 #include <dev/wscons/wsmuxvar.h> 102 103 #if defined(WSMUX_DEBUG) && NWSMUX > 0 104 #define DPRINTF(x) if (wsmuxdebug) printf x 105 #define DPRINTFN(n,x) if (wsmuxdebug > (n)) printf x 106 extern int wsmuxdebug; 107 #else 108 #define DPRINTF(x) 109 #define DPRINTFN(n,x) 110 #endif 111 112 #define INVALID_X INT_MAX 113 #define INVALID_Y INT_MAX 114 #define INVALID_Z INT_MAX 115 116 struct wsmouse_softc { 117 struct wsevsrc sc_base; 118 119 const struct wsmouse_accessops *sc_accessops; 120 void *sc_accesscookie; 121 122 u_int sc_mb; /* mouse button state */ 123 u_int sc_ub; /* user button state */ 124 int sc_dx; /* delta-x */ 125 int sc_dy; /* delta-y */ 126 int sc_dz; /* delta-z */ 127 int sc_dw; /* delta-w */ 128 int sc_x; /* absolute-x */ 129 int sc_y; /* absolute-y */ 130 int sc_z; /* absolute-z */ 131 int sc_w; /* absolute-w */ 132 133 int sc_refcnt; 134 u_char sc_dying; /* device is being detached */ 135 }; 136 137 static int wsmouse_match(struct device *, struct cfdata *, void *); 138 static void wsmouse_attach(struct device *, struct device *, void *); 139 static int wsmouse_detach(struct device *, int); 140 static int wsmouse_activate(struct device *, enum devact); 141 142 static int wsmouse_do_ioctl(struct wsmouse_softc *, u_long, caddr_t, 143 int, struct lwp *); 144 145 #if NWSMUX > 0 146 static int wsmouse_mux_open(struct wsevsrc *, struct wseventvar *); 147 static int wsmouse_mux_close(struct wsevsrc *); 148 #endif 149 150 static int wsmousedoioctl(struct device *, u_long, caddr_t, int, struct lwp *); 151 152 static int wsmousedoopen(struct wsmouse_softc *, struct wseventvar *); 153 154 CFATTACH_DECL(wsmouse, sizeof (struct wsmouse_softc), 155 wsmouse_match, wsmouse_attach, wsmouse_detach, wsmouse_activate); 156 157 extern struct cfdriver wsmouse_cd; 158 159 dev_type_open(wsmouseopen); 160 dev_type_close(wsmouseclose); 161 dev_type_read(wsmouseread); 162 dev_type_ioctl(wsmouseioctl); 163 dev_type_poll(wsmousepoll); 164 dev_type_kqfilter(wsmousekqfilter); 165 166 const struct cdevsw wsmouse_cdevsw = { 167 wsmouseopen, wsmouseclose, wsmouseread, nowrite, wsmouseioctl, 168 nostop, notty, wsmousepoll, nommap, wsmousekqfilter, 169 }; 170 171 #if NWSMUX > 0 172 struct wssrcops wsmouse_srcops = { 173 WSMUX_MOUSE, 174 wsmouse_mux_open, wsmouse_mux_close, wsmousedoioctl, NULL, NULL 175 }; 176 #endif 177 178 /* 179 * Print function (for parent devices). 180 */ 181 int 182 wsmousedevprint(void *aux, const char *pnp) 183 { 184 185 if (pnp) 186 aprint_normal("wsmouse at %s", pnp); 187 return (UNCONF); 188 } 189 190 int 191 wsmouse_match(struct device *parent, struct cfdata *match, void *aux) 192 { 193 return (1); 194 } 195 196 void 197 wsmouse_attach(struct device *parent, struct device *self, void *aux) 198 { 199 struct wsmouse_softc *sc = (struct wsmouse_softc *)self; 200 struct wsmousedev_attach_args *ap = aux; 201 #if NWSMUX > 0 202 int mux, error; 203 #endif 204 205 sc->sc_accessops = ap->accessops; 206 sc->sc_accesscookie = ap->accesscookie; 207 208 #if NWSMUX > 0 209 sc->sc_base.me_ops = &wsmouse_srcops; 210 mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux; 211 if (mux >= 0) { 212 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 213 if (error) 214 printf(" attach error=%d", error); 215 else 216 printf(" mux %d", mux); 217 } 218 #else 219 if (sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux >= 0) 220 printf(" (mux ignored)"); 221 #endif 222 223 printf("\n"); 224 } 225 226 int 227 wsmouse_activate(struct device *self, enum devact act) 228 { 229 struct wsmouse_softc *sc = (struct wsmouse_softc *)self; 230 231 if (act == DVACT_DEACTIVATE) 232 sc->sc_dying = 1; 233 return (0); 234 } 235 236 /* 237 * Detach a mouse. To keep track of users of the softc we keep 238 * a reference count that's incremented while inside, e.g., read. 239 * If the mouse is active and the reference count is > 0 (0 is the 240 * normal state) we post an event and then wait for the process 241 * that had the reference to wake us up again. Then we blow away the 242 * vnode and return (which will deallocate the softc). 243 */ 244 int 245 wsmouse_detach(struct device *self, int flags) 246 { 247 struct wsmouse_softc *sc = (struct wsmouse_softc *)self; 248 struct wseventvar *evar; 249 int maj, mn; 250 int s; 251 252 #if NWSMUX > 0 253 /* Tell parent mux we're leaving. */ 254 if (sc->sc_base.me_parent != NULL) { 255 DPRINTF(("wsmouse_detach:\n")); 256 wsmux_detach_sc(&sc->sc_base); 257 } 258 #endif 259 260 /* If we're open ... */ 261 evar = sc->sc_base.me_evp; 262 if (evar != NULL && evar->io != NULL) { 263 s = spltty(); 264 if (--sc->sc_refcnt >= 0) { 265 /* Wake everyone by generating a dummy event. */ 266 if (++evar->put >= WSEVENT_QSIZE) 267 evar->put = 0; 268 WSEVENT_WAKEUP(evar); 269 /* Wait for processes to go away. */ 270 if (tsleep(sc, PZERO, "wsmdet", hz * 60)) 271 printf("wsmouse_detach: %s didn't detach\n", 272 sc->sc_base.me_dv.dv_xname); 273 } 274 splx(s); 275 } 276 277 /* locate the major number */ 278 maj = cdevsw_lookup_major(&wsmouse_cdevsw); 279 280 /* Nuke the vnodes for any open instances (calls close). */ 281 mn = self->dv_unit; 282 vdevgone(maj, mn, mn, VCHR); 283 284 return (0); 285 } 286 287 void 288 wsmouse_input_xyzw(struct device *wsmousedev, u_int btns /* 0 is up */, 289 int x, int y, int z, int w, u_int flags) 290 { 291 struct wsmouse_softc *sc = (struct wsmouse_softc *)wsmousedev; 292 struct wscons_event *ev; 293 struct wseventvar *evar; 294 int mb, ub, d, get, put, any; 295 296 /* 297 * Discard input if not open. 298 */ 299 evar = sc->sc_base.me_evp; 300 if (evar == NULL) 301 return; 302 303 #ifdef DIAGNOSTIC 304 if (evar->q == NULL) { 305 printf("wsmouse_input: evar->q=NULL\n"); 306 return; 307 } 308 #endif 309 310 #if NWSMUX > 0 311 DPRINTFN(5,("wsmouse_input: %s mux=%p, evar=%p\n", 312 sc->sc_base.me_dv.dv_xname, sc->sc_base.me_parent, evar)); 313 #endif 314 315 sc->sc_mb = btns; 316 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X)) 317 sc->sc_dx += x; 318 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y)) 319 sc->sc_dy += y; 320 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Z)) 321 sc->sc_dz += z; 322 if (!(flags & WSMOUSE_INPUT_ABSOLUTE_W)) 323 sc->sc_dw += w; 324 325 /* 326 * We have at least one event (mouse button, delta-X, or 327 * delta-Y; possibly all three, and possibly three separate 328 * button events). Deliver these events until we are out 329 * of changes or out of room. As events get delivered, 330 * mark them `unchanged'. 331 */ 332 ub = sc->sc_ub; 333 any = 0; 334 get = evar->get; 335 put = evar->put; 336 ev = &evar->q[put]; 337 338 /* NEXT prepares to put the next event, backing off if necessary */ 339 #define NEXT \ 340 if ((++put) % WSEVENT_QSIZE == get) { \ 341 put--; \ 342 goto out; \ 343 } 344 /* ADVANCE completes the `put' of the event */ 345 #define ADVANCE \ 346 ev++; \ 347 if (put >= WSEVENT_QSIZE) { \ 348 put = 0; \ 349 ev = &evar->q[0]; \ 350 } \ 351 any = 1 352 /* TIMESTAMP sets `time' field of the event to the current time */ 353 #define TIMESTAMP \ 354 do { \ 355 int s; \ 356 s = splhigh(); \ 357 TIMEVAL_TO_TIMESPEC(&time, &ev->time); \ 358 splx(s); \ 359 } while (0) 360 361 if (flags & WSMOUSE_INPUT_ABSOLUTE_X) { 362 if (sc->sc_x != x) { 363 NEXT; 364 ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_X; 365 ev->value = x; 366 TIMESTAMP; 367 ADVANCE; 368 sc->sc_x = x; 369 } 370 } else { 371 if (sc->sc_dx) { 372 NEXT; 373 ev->type = WSCONS_EVENT_MOUSE_DELTA_X; 374 ev->value = sc->sc_dx; 375 TIMESTAMP; 376 ADVANCE; 377 sc->sc_dx = 0; 378 } 379 } 380 if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) { 381 if (sc->sc_y != y) { 382 NEXT; 383 ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y; 384 ev->value = y; 385 TIMESTAMP; 386 ADVANCE; 387 sc->sc_y = y; 388 } 389 } else { 390 if (sc->sc_dy) { 391 NEXT; 392 ev->type = WSCONS_EVENT_MOUSE_DELTA_Y; 393 ev->value = sc->sc_dy; 394 TIMESTAMP; 395 ADVANCE; 396 sc->sc_dy = 0; 397 } 398 } 399 if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) { 400 if (sc->sc_z != z) { 401 NEXT; 402 ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z; 403 ev->value = z; 404 TIMESTAMP; 405 ADVANCE; 406 sc->sc_z = z; 407 } 408 } else { 409 if (sc->sc_dz) { 410 NEXT; 411 ev->type = WSCONS_EVENT_MOUSE_DELTA_Z; 412 ev->value = sc->sc_dz; 413 TIMESTAMP; 414 ADVANCE; 415 sc->sc_dz = 0; 416 } 417 } 418 if (flags & WSMOUSE_INPUT_ABSOLUTE_W) { 419 if (sc->sc_w != w) { 420 NEXT; 421 ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_W; 422 ev->value = w; 423 TIMESTAMP; 424 ADVANCE; 425 sc->sc_w = w; 426 } 427 } else { 428 if (sc->sc_dw) { 429 NEXT; 430 ev->type = WSCONS_EVENT_MOUSE_DELTA_W; 431 ev->value = sc->sc_dw; 432 TIMESTAMP; 433 ADVANCE; 434 sc->sc_dw = 0; 435 } 436 } 437 438 mb = sc->sc_mb; 439 while ((d = mb ^ ub) != 0) { 440 /* 441 * Mouse button change. Find the first change and drop 442 * it into the event queue. 443 */ 444 NEXT; 445 ev->value = ffs(d) - 1; 446 447 KASSERT(ev->value >= 0); 448 449 d = 1 << ev->value; 450 ev->type = 451 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP; 452 TIMESTAMP; 453 ADVANCE; 454 ub ^= d; 455 } 456 out: 457 if (any) { 458 sc->sc_ub = ub; 459 evar->put = put; 460 WSEVENT_WAKEUP(evar); 461 #if NWSMUX > 0 462 DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n", 463 sc->sc_base.me_dv.dv_xname, evar)); 464 #endif 465 } 466 } 467 468 int 469 wsmouseopen(dev_t dev, int flags, int mode, struct lwp *l) 470 { 471 struct wsmouse_softc *sc; 472 struct wseventvar *evar; 473 int error, unit; 474 475 unit = minor(dev); 476 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */ 477 (sc = wsmouse_cd.cd_devs[unit]) == NULL) 478 return (ENXIO); 479 480 #if NWSMUX > 0 481 DPRINTF(("wsmouseopen: %s mux=%p p=%p\n", sc->sc_base.me_dv.dv_xname, 482 sc->sc_base.me_parent, l)); 483 #endif 484 485 if (sc->sc_dying) 486 return (EIO); 487 488 if ((flags & (FREAD | FWRITE)) == FWRITE) 489 return (0); /* always allow open for write 490 so ioctl() is possible. */ 491 492 if (sc->sc_base.me_evp != NULL) 493 return (EBUSY); 494 495 evar = &sc->sc_base.me_evar; 496 wsevent_init(evar); 497 sc->sc_base.me_evp = evar; 498 evar->io = l->l_proc; 499 500 error = wsmousedoopen(sc, evar); 501 if (error) { 502 DPRINTF(("wsmouseopen: %s open failed\n", 503 sc->sc_base.me_dv.dv_xname)); 504 sc->sc_base.me_evp = NULL; 505 wsevent_fini(evar); 506 } 507 return (error); 508 } 509 510 int 511 wsmouseclose(dev_t dev, int flags, int mode, struct lwp *l) 512 { 513 struct wsmouse_softc *sc = 514 (struct wsmouse_softc *)wsmouse_cd.cd_devs[minor(dev)]; 515 struct wseventvar *evar = sc->sc_base.me_evp; 516 517 if (evar == NULL) 518 /* not open for read */ 519 return (0); 520 sc->sc_base.me_evp = NULL; 521 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 522 wsevent_fini(evar); 523 524 return (0); 525 } 526 527 int 528 wsmousedoopen(struct wsmouse_softc *sc, struct wseventvar *evp) 529 { 530 sc->sc_base.me_evp = evp; 531 sc->sc_x = INVALID_X; 532 sc->sc_y = INVALID_Y; 533 sc->sc_z = INVALID_Z; 534 535 /* enable the device, and punt if that's not possible */ 536 return (*sc->sc_accessops->enable)(sc->sc_accesscookie); 537 } 538 539 int 540 wsmouseread(dev_t dev, struct uio *uio, int flags) 541 { 542 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)]; 543 int error; 544 545 if (sc->sc_dying) 546 return (EIO); 547 548 #ifdef DIAGNOSTIC 549 if (sc->sc_base.me_evp == NULL) { 550 printf("wsmouseread: evp == NULL\n"); 551 return (EINVAL); 552 } 553 #endif 554 555 sc->sc_refcnt++; 556 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 557 if (--sc->sc_refcnt < 0) { 558 wakeup(sc); 559 error = EIO; 560 } 561 return (error); 562 } 563 564 int 565 wsmouseioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 566 { 567 return (wsmousedoioctl(wsmouse_cd.cd_devs[minor(dev)], 568 cmd, data, flag, l)); 569 } 570 571 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 572 int 573 wsmousedoioctl(struct device *dv, u_long cmd, caddr_t data, int flag, 574 struct lwp *l) 575 { 576 struct wsmouse_softc *sc = (struct wsmouse_softc *)dv; 577 int error; 578 579 sc->sc_refcnt++; 580 error = wsmouse_do_ioctl(sc, cmd, data, flag, l); 581 if (--sc->sc_refcnt < 0) 582 wakeup(sc); 583 return (error); 584 } 585 586 int 587 wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, caddr_t data, 588 int flag, struct lwp *l) 589 { 590 int error; 591 592 if (sc->sc_dying) 593 return (EIO); 594 595 /* 596 * Try the generic ioctls that the wsmouse interface supports. 597 */ 598 switch (cmd) { 599 case FIONBIO: /* we will remove this someday (soon???) */ 600 return (0); 601 602 case FIOASYNC: 603 if (sc->sc_base.me_evp == NULL) 604 return (EINVAL); 605 sc->sc_base.me_evp->async = *(int *)data != 0; 606 return (0); 607 608 case FIOSETOWN: 609 if (sc->sc_base.me_evp == NULL) 610 return (EINVAL); 611 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid 612 && *(int *)data != sc->sc_base.me_evp->io->p_pid) 613 return (EPERM); 614 return (0); 615 616 case TIOCSPGRP: 617 if (sc->sc_base.me_evp == NULL) 618 return (EINVAL); 619 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 620 return (EPERM); 621 return (0); 622 } 623 624 /* 625 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1 626 * if it didn't recognize the request. 627 */ 628 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, 629 data, flag, l); 630 return (error); /* may be EPASSTHROUGH */ 631 } 632 633 int 634 wsmousepoll(dev_t dev, int events, struct lwp *l) 635 { 636 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)]; 637 638 if (sc->sc_base.me_evp == NULL) 639 return (POLLERR); 640 return (wsevent_poll(sc->sc_base.me_evp, events, l)); 641 } 642 643 int 644 wsmousekqfilter(dev_t dev, struct knote *kn) 645 { 646 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)]; 647 648 if (sc->sc_base.me_evp == NULL) 649 return (1); 650 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 651 } 652 653 #if NWSMUX > 0 654 int 655 wsmouse_mux_open(struct wsevsrc *me, struct wseventvar *evp) 656 { 657 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 658 659 if (sc->sc_base.me_evp != NULL) 660 return (EBUSY); 661 662 return wsmousedoopen(sc, evp); 663 } 664 665 int 666 wsmouse_mux_close(struct wsevsrc *me) 667 { 668 struct wsmouse_softc *sc = (struct wsmouse_softc *)me; 669 670 sc->sc_base.me_evp = NULL; 671 (*sc->sc_accessops->disable)(sc->sc_accesscookie); 672 673 return (0); 674 } 675 676 int 677 wsmouse_add_mux(int unit, struct wsmux_softc *muxsc) 678 { 679 struct wsmouse_softc *sc; 680 681 if (unit < 0 || unit >= wsmouse_cd.cd_ndevs || 682 (sc = wsmouse_cd.cd_devs[unit]) == NULL) 683 return (ENXIO); 684 685 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 686 return (EBUSY); 687 688 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 689 } 690 #endif /* NWSMUX > 0 */ 691