1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004 M. Warner Losh 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 /* 32 * Copyright 1992 by the University of Guelph 33 * 34 * Permission to use, copy and modify this 35 * software and its documentation for any purpose and without 36 * fee is hereby granted, provided that the above copyright 37 * notice appear in all copies and that both that copyright 38 * notice and this permission notice appear in supporting 39 * documentation. 40 * University of Guelph makes no representations about the suitability of 41 * this software for any purpose. It is provided "as is" 42 * without express or implied warranty. 43 */ 44 /* 45 * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 46 * the X386 port, courtesy of 47 * Rick Macklem, [email protected] 48 * Caveats: The driver currently uses spltty(), but doesn't use any 49 * generic tty code. It could use splmse() (that only masks off the 50 * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 51 * (This may be worth the effort, since the Logitech generates 30/60 52 * interrupts/sec continuously while it is open.) 53 * NB: The ATI has NOT been tested yet! 54 */ 55 56 /* 57 * Modification history: 58 * Sep 6, 1994 -- Lars Fredriksen([email protected]) 59 * improved probe based on input from Logitech. 60 * 61 * Oct 19, 1992 -- E. Stark ([email protected]) 62 * fixes to make it work with Microsoft InPort busmouse 63 * 64 * Jan, 1993 -- E. Stark ([email protected]) 65 * added patches for new "select" interface 66 * 67 * May 4, 1993 -- E. Stark ([email protected]) 68 * changed position of some spl()'s in mseread 69 * 70 * October 8, 1993 -- E. Stark ([email protected]) 71 * limit maximum negative x/y value to -127 to work around XFree problem 72 * that causes spurious button pushes. 73 */ 74 75 #include <sys/param.h> 76 #include <sys/systm.h> 77 #include <sys/conf.h> 78 #include <sys/kernel.h> 79 #include <sys/module.h> 80 #include <sys/bus.h> 81 #include <sys/poll.h> 82 #include <sys/selinfo.h> 83 #include <sys/uio.h> 84 #include <sys/mouse.h> 85 86 #include <machine/bus.h> 87 #include <machine/resource.h> 88 #include <sys/rman.h> 89 90 #include <isa/isavar.h> 91 92 #include <dev/mse/msevar.h> 93 94 devclass_t mse_devclass; 95 96 static d_open_t mseopen; 97 static d_close_t mseclose; 98 static d_read_t mseread; 99 static d_ioctl_t mseioctl; 100 static d_poll_t msepoll; 101 102 static struct cdevsw mse_cdevsw = { 103 .d_version = D_VERSION, 104 .d_open = mseopen, 105 .d_close = mseclose, 106 .d_read = mseread, 107 .d_ioctl = mseioctl, 108 .d_poll = msepoll, 109 .d_name = "mse", 110 }; 111 112 static void mseintr(void *); 113 static void mseintr_locked(mse_softc_t *sc); 114 static void msetimeout(void *); 115 116 #define MSE_NBLOCKIO(dev) (dev2unit(dev) != 0) 117 118 #define MSEPRI (PZERO + 3) 119 120 int 121 mse_common_attach(device_t dev) 122 { 123 mse_softc_t *sc; 124 int unit, flags, rid; 125 126 sc = device_get_softc(dev); 127 unit = device_get_unit(dev); 128 mtx_init(&sc->sc_lock, "mse", NULL, MTX_DEF); 129 callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0); 130 131 rid = 0; 132 sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 133 RF_ACTIVE); 134 if (sc->sc_intr == NULL) { 135 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 136 mtx_destroy(&sc->sc_lock); 137 return ENXIO; 138 } 139 140 if (bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_TTY | INTR_MPSAFE, 141 NULL, mseintr, sc, &sc->sc_ih)) { 142 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 143 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 144 mtx_destroy(&sc->sc_lock); 145 return ENXIO; 146 } 147 flags = device_get_flags(dev); 148 sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4; 149 150 sc->sc_dev = make_dev(&mse_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 151 "mse%d", unit); 152 sc->sc_dev->si_drv1 = sc; 153 sc->sc_ndev = make_dev(&mse_cdevsw, 1, UID_ROOT, GID_WHEEL, 0600, 154 "nmse%d", unit); 155 sc->sc_ndev->si_drv1 = sc; 156 gone_in_dev(dev, 12, "mse(4) driver"); 157 158 return 0; 159 } 160 161 int 162 mse_detach(device_t dev) 163 { 164 mse_softc_t *sc; 165 int rid; 166 167 sc = device_get_softc(dev); 168 MSE_LOCK(sc); 169 if (sc->sc_flags & MSESC_OPEN) { 170 MSE_UNLOCK(sc); 171 return EBUSY; 172 } 173 174 /* Sabotage subsequent opens. */ 175 sc->sc_mousetype = MSE_NONE; 176 MSE_UNLOCK(sc); 177 178 destroy_dev(sc->sc_dev); 179 destroy_dev(sc->sc_ndev); 180 181 rid = 0; 182 bus_teardown_intr(dev, sc->sc_intr, sc->sc_ih); 183 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 184 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 185 186 callout_drain(&sc->sc_callout); 187 mtx_destroy(&sc->sc_lock); 188 189 return 0; 190 } 191 192 /* 193 * Exclusive open the mouse, initialize it and enable interrupts. 194 */ 195 static int 196 mseopen(struct cdev *dev, int flags, int fmt, struct thread *td) 197 { 198 mse_softc_t *sc = dev->si_drv1; 199 200 MSE_LOCK(sc); 201 if (sc->sc_mousetype == MSE_NONE) { 202 MSE_UNLOCK(sc); 203 return (ENXIO); 204 } 205 if (sc->sc_flags & MSESC_OPEN) { 206 MSE_UNLOCK(sc); 207 return (EBUSY); 208 } 209 sc->sc_flags |= MSESC_OPEN; 210 sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS; 211 sc->sc_deltax = sc->sc_deltay = 0; 212 sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE; 213 sc->sc_watchdog = FALSE; 214 callout_reset(&sc->sc_callout, hz * 2, msetimeout, dev); 215 sc->mode.level = 0; 216 sc->status.flags = 0; 217 sc->status.button = sc->status.obutton = 0; 218 sc->status.dx = sc->status.dy = sc->status.dz = 0; 219 220 /* 221 * Initialize mouse interface and enable interrupts. 222 */ 223 (*sc->sc_enablemouse)(sc->sc_port); 224 MSE_UNLOCK(sc); 225 return (0); 226 } 227 228 /* 229 * mseclose: just turn off mouse innterrupts. 230 */ 231 static int 232 mseclose(struct cdev *dev, int flags, int fmt, struct thread *td) 233 { 234 mse_softc_t *sc = dev->si_drv1; 235 236 MSE_LOCK(sc); 237 callout_stop(&sc->sc_callout); 238 (*sc->sc_disablemouse)(sc->sc_port); 239 sc->sc_flags &= ~MSESC_OPEN; 240 MSE_UNLOCK(sc); 241 return(0); 242 } 243 244 /* 245 * mseread: return mouse info using the MSC serial protocol, but without 246 * using bytes 4 and 5. 247 * (Yes this is cheesy, but it makes the X386 server happy, so...) 248 */ 249 static int 250 mseread(struct cdev *dev, struct uio *uio, int ioflag) 251 { 252 mse_softc_t *sc = dev->si_drv1; 253 int xfer, error; 254 255 /* 256 * If there are no protocol bytes to be read, set up a new protocol 257 * packet. 258 */ 259 MSE_LOCK(sc); 260 while (sc->sc_flags & MSESC_READING) { 261 if (MSE_NBLOCKIO(dev)) { 262 MSE_UNLOCK(sc); 263 return (0); 264 } 265 sc->sc_flags |= MSESC_WANT; 266 error = mtx_sleep(sc, &sc->sc_lock, MSEPRI | PCATCH, "mseread", 267 0); 268 if (error) { 269 MSE_UNLOCK(sc); 270 return (error); 271 } 272 } 273 sc->sc_flags |= MSESC_READING; 274 xfer = 0; 275 if (sc->sc_bytesread >= sc->mode.packetsize) { 276 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 277 (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 278 if (MSE_NBLOCKIO(dev)) 279 goto out; 280 sc->sc_flags |= MSESC_WANT; 281 error = mtx_sleep(sc, &sc->sc_lock, MSEPRI | PCATCH, 282 "mseread", 0); 283 if (error) 284 goto out; 285 } 286 287 /* 288 * Generate protocol bytes. 289 * For some reason X386 expects 5 bytes but never uses 290 * the fourth or fifth? 291 */ 292 sc->sc_bytes[0] = sc->mode.syncmask[1] 293 | (sc->sc_buttons & ~sc->mode.syncmask[0]); 294 if (sc->sc_deltax > 127) 295 sc->sc_deltax = 127; 296 if (sc->sc_deltax < -127) 297 sc->sc_deltax = -127; 298 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 299 if (sc->sc_deltay > 127) 300 sc->sc_deltay = 127; 301 if (sc->sc_deltay < -127) 302 sc->sc_deltay = -127; 303 sc->sc_bytes[1] = sc->sc_deltax; 304 sc->sc_bytes[2] = sc->sc_deltay; 305 sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 306 sc->sc_bytes[5] = sc->sc_bytes[6] = 0; 307 sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS; 308 sc->sc_obuttons = sc->sc_buttons; 309 sc->sc_deltax = sc->sc_deltay = 0; 310 sc->sc_bytesread = 0; 311 } 312 xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread); 313 MSE_UNLOCK(sc); 314 error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio); 315 MSE_LOCK(sc); 316 out: 317 sc->sc_flags &= ~MSESC_READING; 318 if (error == 0) 319 sc->sc_bytesread += xfer; 320 if (sc->sc_flags & MSESC_WANT) { 321 sc->sc_flags &= ~MSESC_WANT; 322 MSE_UNLOCK(sc); 323 wakeup(sc); 324 } else 325 MSE_UNLOCK(sc); 326 return (error); 327 } 328 329 /* 330 * mseioctl: process ioctl commands. 331 */ 332 static int 333 mseioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 334 { 335 mse_softc_t *sc = dev->si_drv1; 336 mousestatus_t status; 337 int err = 0; 338 339 switch (cmd) { 340 341 case MOUSE_GETHWINFO: 342 MSE_LOCK(sc); 343 *(mousehw_t *)addr = sc->hw; 344 if (sc->mode.level == 0) 345 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 346 MSE_UNLOCK(sc); 347 break; 348 349 case MOUSE_GETMODE: 350 MSE_LOCK(sc); 351 *(mousemode_t *)addr = sc->mode; 352 switch (sc->mode.level) { 353 case 0: 354 break; 355 case 1: 356 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 357 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 358 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 359 break; 360 } 361 MSE_UNLOCK(sc); 362 break; 363 364 case MOUSE_SETMODE: 365 switch (((mousemode_t *)addr)->level) { 366 case 0: 367 case 1: 368 break; 369 default: 370 return (EINVAL); 371 } 372 MSE_LOCK(sc); 373 if (((mousemode_t *)addr)->accelfactor < -1) { 374 MSE_UNLOCK(sc); 375 return (EINVAL); 376 } else if (((mousemode_t *)addr)->accelfactor >= 0) 377 sc->mode.accelfactor = 378 ((mousemode_t *)addr)->accelfactor; 379 sc->mode.level = ((mousemode_t *)addr)->level; 380 switch (sc->mode.level) { 381 case 0: 382 sc->sc_bytesread = sc->mode.packetsize 383 = MOUSE_MSC_PACKETSIZE; 384 break; 385 case 1: 386 sc->sc_bytesread = sc->mode.packetsize 387 = MOUSE_SYS_PACKETSIZE; 388 break; 389 } 390 MSE_UNLOCK(sc); 391 break; 392 393 case MOUSE_GETLEVEL: 394 MSE_LOCK(sc); 395 *(int *)addr = sc->mode.level; 396 MSE_UNLOCK(sc); 397 break; 398 399 case MOUSE_SETLEVEL: 400 switch (*(int *)addr) { 401 case 0: 402 MSE_LOCK(sc); 403 sc->mode.level = *(int *)addr; 404 sc->sc_bytesread = sc->mode.packetsize 405 = MOUSE_MSC_PACKETSIZE; 406 MSE_UNLOCK(sc); 407 break; 408 case 1: 409 MSE_LOCK(sc); 410 sc->mode.level = *(int *)addr; 411 sc->sc_bytesread = sc->mode.packetsize 412 = MOUSE_SYS_PACKETSIZE; 413 MSE_UNLOCK(sc); 414 break; 415 default: 416 return (EINVAL); 417 } 418 break; 419 420 case MOUSE_GETSTATUS: 421 MSE_LOCK(sc); 422 status = sc->status; 423 sc->status.flags = 0; 424 sc->status.obutton = sc->status.button; 425 sc->status.button = 0; 426 sc->status.dx = 0; 427 sc->status.dy = 0; 428 sc->status.dz = 0; 429 MSE_UNLOCK(sc); 430 *(mousestatus_t *)addr = status; 431 break; 432 433 case MOUSE_READSTATE: 434 case MOUSE_READDATA: 435 return (ENODEV); 436 437 #if (defined(MOUSE_GETVARS)) 438 case MOUSE_GETVARS: 439 case MOUSE_SETVARS: 440 return (ENODEV); 441 #endif 442 443 default: 444 return (ENOTTY); 445 } 446 return (err); 447 } 448 449 /* 450 * msepoll: check for mouse input to be processed. 451 */ 452 static int 453 msepoll(struct cdev *dev, int events, struct thread *td) 454 { 455 mse_softc_t *sc = dev->si_drv1; 456 int revents = 0; 457 458 MSE_LOCK(sc); 459 if (events & (POLLIN | POLLRDNORM)) { 460 if (sc->sc_bytesread != sc->mode.packetsize || 461 sc->sc_deltax != 0 || sc->sc_deltay != 0 || 462 (sc->sc_obuttons ^ sc->sc_buttons) != 0) 463 revents |= events & (POLLIN | POLLRDNORM); 464 else 465 selrecord(td, &sc->sc_selp); 466 } 467 MSE_UNLOCK(sc); 468 return (revents); 469 } 470 471 /* 472 * msetimeout: watchdog timer routine. 473 */ 474 static void 475 msetimeout(void *arg) 476 { 477 struct cdev *dev; 478 mse_softc_t *sc; 479 480 dev = (struct cdev *)arg; 481 sc = dev->si_drv1; 482 MSE_ASSERT_LOCKED(sc); 483 if (sc->sc_watchdog) { 484 if (bootverbose) 485 printf("%s: lost interrupt?\n", devtoname(dev)); 486 mseintr_locked(sc); 487 } 488 sc->sc_watchdog = TRUE; 489 callout_schedule(&sc->sc_callout, hz); 490 } 491 492 /* 493 * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 494 */ 495 static void 496 mseintr(void *arg) 497 { 498 mse_softc_t *sc = arg; 499 500 MSE_LOCK(sc); 501 mseintr_locked(sc); 502 MSE_UNLOCK(sc); 503 } 504 505 static void 506 mseintr_locked(mse_softc_t *sc) 507 { 508 /* 509 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP) 510 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 511 */ 512 static int butmap[8] = { 513 0, 514 MOUSE_BUTTON3DOWN, 515 MOUSE_BUTTON2DOWN, 516 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 517 MOUSE_BUTTON1DOWN, 518 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 519 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 520 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 521 }; 522 int dx, dy, but; 523 int sign; 524 525 #ifdef DEBUG 526 static int mse_intrcnt = 0; 527 if((mse_intrcnt++ % 10000) == 0) 528 printf("mseintr\n"); 529 #endif /* DEBUG */ 530 if ((sc->sc_flags & MSESC_OPEN) == 0) 531 return; 532 533 (*sc->sc_getmouse)(sc->sc_port, &dx, &dy, &but); 534 if (sc->mode.accelfactor > 0) { 535 sign = (dx < 0); 536 dx = dx * dx / sc->mode.accelfactor; 537 if (dx == 0) 538 dx = 1; 539 if (sign) 540 dx = -dx; 541 sign = (dy < 0); 542 dy = dy * dy / sc->mode.accelfactor; 543 if (dy == 0) 544 dy = 1; 545 if (sign) 546 dy = -dy; 547 } 548 sc->sc_deltax += dx; 549 sc->sc_deltay += dy; 550 sc->sc_buttons = but; 551 552 but = butmap[~but & MOUSE_MSC_BUTTONS]; 553 sc->status.dx += dx; 554 sc->status.dy += dy; 555 sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0) 556 | (sc->status.button ^ but); 557 sc->status.button = but; 558 559 sc->sc_watchdog = FALSE; 560 561 /* 562 * If mouse state has changed, wake up anyone wanting to know. 563 */ 564 if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 565 (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 566 if (sc->sc_flags & MSESC_WANT) { 567 sc->sc_flags &= ~MSESC_WANT; 568 wakeup(sc); 569 } 570 selwakeuppri(&sc->sc_selp, MSEPRI); 571 } 572 } 573