1 /*- 2 * Copyright (C) 2008 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/module.h> 32 #include <sys/bus.h> 33 #include <sys/conf.h> 34 #include <sys/mouse.h> 35 #include <sys/poll.h> 36 #include <sys/condvar.h> 37 #include <sys/selinfo.h> 38 #include <sys/uio.h> 39 #include <sys/fcntl.h> 40 #include <sys/kernel.h> 41 42 #include <machine/bus.h> 43 44 #include <vm/vm.h> 45 #include <vm/pmap.h> 46 47 #include "adb.h" 48 49 #define CDEV_GET_SOFTC(x) devclass_get_softc(adb_mouse_devclass, minor(x) & 0x1f) 50 51 static int adb_mouse_probe(device_t dev); 52 static int adb_mouse_attach(device_t dev); 53 static int adb_mouse_detach(device_t dev); 54 55 static d_open_t ams_open; 56 static d_close_t ams_close; 57 static d_read_t ams_read; 58 static d_ioctl_t ams_ioctl; 59 static d_poll_t ams_poll; 60 61 static u_int adb_mouse_receive_packet(device_t dev, u_char status, 62 u_char command, u_char reg, int len, u_char *data); 63 64 struct adb_mouse_softc { 65 device_t sc_dev; 66 67 struct mtx sc_mtx; 68 struct cv sc_cv; 69 70 int flags; 71 #define AMS_EXTENDED 0x1 72 #define AMS_TOUCHPAD 0x2 73 uint16_t dpi; 74 75 mousehw_t hw; 76 mousemode_t mode; 77 u_char id[4]; 78 79 int buttons; 80 int last_buttons; 81 int xdelta, ydelta; 82 83 int8_t packet[8]; 84 size_t packet_read_len; 85 86 struct cdev *cdev; 87 struct selinfo rsel; 88 }; 89 90 static device_method_t adb_mouse_methods[] = { 91 /* Device interface */ 92 DEVMETHOD(device_probe, adb_mouse_probe), 93 DEVMETHOD(device_attach, adb_mouse_attach), 94 DEVMETHOD(device_detach, adb_mouse_detach), 95 DEVMETHOD(device_shutdown, bus_generic_shutdown), 96 DEVMETHOD(device_suspend, bus_generic_suspend), 97 DEVMETHOD(device_resume, bus_generic_resume), 98 99 /* ADB interface */ 100 DEVMETHOD(adb_receive_packet, adb_mouse_receive_packet), 101 102 { 0, 0 } 103 }; 104 105 static driver_t adb_mouse_driver = { 106 "ams", 107 adb_mouse_methods, 108 sizeof(struct adb_mouse_softc), 109 }; 110 111 static devclass_t adb_mouse_devclass; 112 113 DRIVER_MODULE(ams, adb, adb_mouse_driver, adb_mouse_devclass, 0, 0); 114 115 static struct cdevsw ams_cdevsw = { 116 .d_version = D_VERSION, 117 .d_flags = 0, 118 .d_open = ams_open, 119 .d_close = ams_close, 120 .d_read = ams_read, 121 .d_ioctl = ams_ioctl, 122 .d_poll = ams_poll, 123 .d_name = "ams", 124 }; 125 126 static int 127 adb_mouse_probe(device_t dev) 128 { 129 uint8_t type; 130 131 type = adb_get_device_type(dev); 132 133 if (type != ADB_DEVICE_MOUSE) 134 return (ENXIO); 135 136 device_set_desc(dev,"ADB Mouse"); 137 return (0); 138 } 139 140 static int 141 adb_mouse_attach(device_t dev) 142 { 143 struct adb_mouse_softc *sc; 144 char *description = "Unknown Pointing Device"; 145 146 size_t r1_len; 147 u_char r1[8]; 148 149 sc = device_get_softc(dev); 150 sc->sc_dev = dev; 151 152 mtx_init(&sc->sc_mtx,"ams",MTX_DEF,0); 153 cv_init(&sc->sc_cv,"ams"); 154 155 sc->flags = 0; 156 157 sc->hw.buttons = 2; 158 sc->hw.iftype = MOUSE_IF_UNKNOWN; 159 sc->hw.type = MOUSE_UNKNOWN; 160 sc->hw.model = sc->hw.hwid = 0; 161 162 sc->mode.protocol = MOUSE_PROTO_SYSMOUSE; 163 sc->mode.rate = -1; 164 sc->mode.resolution = 100; 165 sc->mode.accelfactor = 0; 166 sc->mode.level = 0; 167 sc->mode.packetsize = 5; 168 169 sc->buttons = 0; 170 sc->last_buttons = 0; 171 sc->packet_read_len = 0; 172 173 /* Try to switch to extended protocol */ 174 adb_set_device_handler(dev,4); 175 176 switch(adb_get_device_handler(dev)) { 177 case 1: 178 sc->mode.resolution = 100; 179 break; 180 case 2: 181 sc->mode.resolution = 200; 182 break; 183 case 4: 184 r1_len = adb_read_register(dev,1,r1); 185 if (r1_len < 8) 186 break; 187 188 sc->flags |= AMS_EXTENDED; 189 memcpy(&sc->hw.hwid,r1,4); 190 sc->mode.resolution = (r1[4] << 8) | r1[5]; 191 192 switch (r1[6]) { 193 case 0: 194 sc->hw.type = MOUSE_PAD; 195 description = "Tablet"; 196 break; 197 case 1: 198 sc->hw.type = MOUSE_MOUSE; 199 description = "Mouse"; 200 break; 201 case 2: 202 sc->hw.type = MOUSE_TRACKBALL; 203 description = "Trackball"; 204 break; 205 case 3: 206 sc->flags |= AMS_TOUCHPAD; 207 sc->hw.type = MOUSE_PAD; 208 description = "Touchpad"; 209 break; 210 } 211 212 sc->hw.buttons = r1[7]; 213 214 device_printf(dev,"%d-button %d-dpi %s\n", 215 sc->hw.buttons, sc->mode.resolution,description); 216 217 /* 218 * Check for one of MacAlly's non-compliant 2-button mice. 219 * These claim to speak the extended mouse protocol, but 220 * instead speak the standard protocol and only when their 221 * handler is set to 0x42. 222 */ 223 224 if (sc->hw.hwid == 0x4b4f4954) { 225 adb_set_device_handler(dev,0x42); 226 227 if (adb_get_device_handler(dev) == 0x42) { 228 device_printf(dev, "MacAlly 2-Button Mouse\n"); 229 sc->flags &= ~AMS_EXTENDED; 230 } 231 } 232 233 break; 234 } 235 236 sc->cdev = make_dev(&ams_cdevsw, device_get_unit(dev), 237 UID_ROOT, GID_OPERATOR, 0644, "ams%d", 238 device_get_unit(dev)); 239 240 adb_set_autopoll(dev,1); 241 242 return (0); 243 } 244 245 static int 246 adb_mouse_detach(device_t dev) 247 { 248 struct adb_mouse_softc *sc; 249 250 adb_set_autopoll(dev,0); 251 252 sc = device_get_softc(dev); 253 destroy_dev(sc->cdev); 254 255 mtx_destroy(&sc->sc_mtx); 256 cv_destroy(&sc->sc_cv); 257 258 return (0); 259 } 260 261 static u_int 262 adb_mouse_receive_packet(device_t dev, u_char status, u_char command, 263 u_char reg, int len, u_char *data) 264 { 265 struct adb_mouse_softc *sc; 266 int i = 0; 267 int xdelta, ydelta; 268 int buttons; 269 270 sc = device_get_softc(dev); 271 272 if (command != ADB_COMMAND_TALK || reg != 0 || len < 2) 273 return (0); 274 275 ydelta = data[0] & 0x7f; 276 xdelta = data[1] & 0x7f; 277 278 buttons = 0; 279 buttons |= !(data[0] & 0x80); 280 buttons |= !(data[1] & 0x80) << 1; 281 282 if (sc->flags & AMS_EXTENDED) { 283 for (i = 2; i < len && i < 5; i++) { 284 xdelta |= (data[i] & 0x07) << (3*i + 1); 285 ydelta |= (data[i] & 0x70) << (3*i - 3); 286 287 buttons |= !(data[i] & 0x08) << (2*i - 2); 288 buttons |= !(data[i] & 0x80) << (2*i - 1); 289 } 290 } else { 291 len = 2; /* Ignore extra data */ 292 } 293 294 /* Do sign extension as necessary */ 295 if (xdelta & (0x40 << 3*(len-2))) 296 xdelta |= 0xffffffc0 << 3*(len - 2); 297 if (ydelta & (0x40 << 3*(len-2))) 298 ydelta |= 0xffffffc0 << 3*(len - 2); 299 300 /* 301 * Some mice report high-numbered buttons on the wrong button number, 302 * so set the highest-numbered real button as pressed if there are 303 * mysterious high-numbered ones set. 304 * 305 * Don't do this for touchpads, because touchpads also trigger 306 * high button events when they are touched. 307 */ 308 309 if (buttons & ~((1 << sc->hw.buttons) - 1) 310 && !(sc->flags & AMS_TOUCHPAD)) { 311 buttons |= 1 << (sc->hw.buttons - 1); 312 } 313 buttons &= (1 << sc->hw.buttons) - 1; 314 315 mtx_lock(&sc->sc_mtx); 316 317 /* Add in our new deltas, and take into account 318 Apple's opposite meaning for Y axis motion */ 319 320 sc->xdelta += xdelta; 321 sc->ydelta -= ydelta; 322 323 sc->buttons = buttons; 324 325 mtx_unlock(&sc->sc_mtx); 326 327 cv_broadcast(&sc->sc_cv); 328 selwakeuppri(&sc->rsel, PZERO); 329 330 return (0); 331 } 332 333 static int 334 ams_open(struct cdev *dev, int flag, int fmt, struct thread *p) 335 { 336 struct adb_mouse_softc *sc; 337 338 sc = CDEV_GET_SOFTC(dev); 339 if (sc == NULL) 340 return (ENXIO); 341 342 mtx_lock(&sc->sc_mtx); 343 sc->packet_read_len = 0; 344 sc->xdelta = 0; 345 sc->ydelta = 0; 346 sc->buttons = 0; 347 mtx_unlock(&sc->sc_mtx); 348 349 return (0); 350 } 351 352 static int 353 ams_close(struct cdev *dev, int flag, int fmt, struct thread *p) 354 { 355 struct adb_mouse_softc *sc; 356 357 sc = CDEV_GET_SOFTC(dev); 358 359 cv_broadcast(&sc->sc_cv); 360 selwakeuppri(&sc->rsel, PZERO); 361 return (0); 362 } 363 364 static int 365 ams_poll(struct cdev *dev, int events, struct thread *p) 366 { 367 struct adb_mouse_softc *sc; 368 369 sc = CDEV_GET_SOFTC(dev); 370 if (sc == NULL) 371 return (EIO); 372 373 if (events & (POLLIN | POLLRDNORM)) { 374 mtx_lock(&sc->sc_mtx); 375 376 if (sc->xdelta == 0 && sc->ydelta == 0 && 377 sc->buttons == sc->last_buttons) { 378 selrecord(p, &sc->rsel); 379 events = 0; 380 } else { 381 events &= (POLLIN | POLLRDNORM); 382 } 383 384 mtx_unlock(&sc->sc_mtx); 385 } 386 387 return events; 388 } 389 390 static int 391 ams_read(struct cdev *dev, struct uio *uio, int flag) 392 { 393 struct adb_mouse_softc *sc; 394 size_t len; 395 int8_t outpacket[8]; 396 int error; 397 398 sc = CDEV_GET_SOFTC(dev); 399 if (sc == NULL) 400 return (EIO); 401 402 if (uio->uio_resid <= 0) 403 return (0); 404 405 mtx_lock(&sc->sc_mtx); 406 407 if (!sc->packet_read_len) { 408 if (sc->xdelta == 0 && sc->ydelta == 0 && 409 sc->buttons == sc->last_buttons) { 410 411 if (flag & O_NONBLOCK) { 412 mtx_unlock(&sc->sc_mtx); 413 return EWOULDBLOCK; 414 } 415 416 417 /* Otherwise, block on new data */ 418 error = cv_wait_sig(&sc->sc_cv, &sc->sc_mtx); 419 if (error) { 420 mtx_unlock(&sc->sc_mtx); 421 return (error); 422 } 423 } 424 425 sc->packet[0] = 1 << 7; 426 sc->packet[0] |= (!(sc->buttons & 1)) << 2; 427 sc->packet[0] |= (!(sc->buttons & 4)) << 1; 428 sc->packet[0] |= (!(sc->buttons & 2)); 429 430 if (sc->xdelta > 127) { 431 sc->packet[1] = 127; 432 sc->packet[3] = sc->xdelta - 127; 433 } else if (sc->xdelta < -127) { 434 sc->packet[1] = -127; 435 sc->packet[3] = sc->xdelta + 127; 436 } else { 437 sc->packet[1] = sc->xdelta; 438 sc->packet[3] = 0; 439 } 440 441 if (sc->ydelta > 127) { 442 sc->packet[2] = 127; 443 sc->packet[4] = sc->ydelta - 127; 444 } else if (sc->ydelta < -127) { 445 sc->packet[2] = -127; 446 sc->packet[4] = sc->ydelta + 127; 447 } else { 448 sc->packet[2] = sc->ydelta; 449 sc->packet[4] = 0; 450 } 451 452 /* No Z movement */ 453 sc->packet[5] = 0; 454 sc->packet[6] = 0; 455 456 sc->packet[7] = ~((uint8_t)(sc->buttons >> 3)) & 0x7f; 457 458 459 sc->last_buttons = sc->buttons; 460 sc->xdelta = 0; 461 sc->ydelta = 0; 462 463 sc->packet_read_len = sc->mode.packetsize; 464 } 465 466 len = (sc->packet_read_len > uio->uio_resid) ? 467 uio->uio_resid : sc->packet_read_len; 468 469 memcpy(outpacket,sc->packet + 470 (sc->mode.packetsize - sc->packet_read_len),len); 471 sc->packet_read_len -= len; 472 473 mtx_unlock(&sc->sc_mtx); 474 475 uiomove(outpacket,len,uio); 476 477 return (0); 478 } 479 480 481 static int 482 ams_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 483 struct thread *p) 484 { 485 struct adb_mouse_softc *sc; 486 mousemode_t mode; 487 488 sc = CDEV_GET_SOFTC(dev); 489 if (sc == NULL) 490 return (EIO); 491 492 switch (cmd) { 493 case MOUSE_GETHWINFO: 494 *(mousehw_t *)addr = sc->hw; 495 break; 496 case MOUSE_GETMODE: 497 *(mousemode_t *)addr = sc->mode; 498 break; 499 case MOUSE_SETMODE: 500 mode = *(mousemode_t *)addr; 501 addr = (caddr_t)&mode.level; 502 503 /* Fallthrough */ 504 505 case MOUSE_SETLEVEL: 506 if (*(int *)addr == -1) 507 break; 508 else if (*(int *)addr == 1) { 509 sc->mode.level = 1; 510 sc->mode.packetsize = 8; 511 break; 512 } else if (*(int *)addr == 0) { 513 sc->mode.level = 0; 514 sc->mode.packetsize = 5; 515 break; 516 } 517 518 return EINVAL; 519 case MOUSE_GETLEVEL: 520 *(int *)addr = sc->mode.level; 521 break; 522 523 case MOUSE_GETSTATUS: { 524 mousestatus_t *status = (mousestatus_t *) addr; 525 526 mtx_lock(&sc->sc_mtx); 527 528 status->button = sc->buttons; 529 status->obutton = sc->last_buttons; 530 531 status->flags = status->button ^ status->obutton; 532 533 if (sc->xdelta != 0 || sc->ydelta) 534 status->flags |= MOUSE_POSCHANGED; 535 if (status->button != status->obutton) 536 status->flags |= MOUSE_BUTTONSCHANGED; 537 538 status->dx = sc->xdelta; 539 status->dy = sc->ydelta; 540 status->dz = 0; 541 542 sc->xdelta = 0; 543 sc->ydelta = 0; 544 sc->last_buttons = sc->buttons; 545 546 mtx_unlock(&sc->sc_mtx); 547 548 break; } 549 default: 550 return ENOTTY; 551 } 552 553 return (0); 554 } 555 556