1 /* $NetBSD: alps.c,v 1.14 2020/02/10 16:12:58 ryoon Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 Ryo ONODERA <ryo@tetera.org> 5 * Copyright (c) 2008 Jared D. McNeill <jmcneill@invisible.ca> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "opt_pms.h" 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: alps.c,v 1.14 2020/02/10 16:12:58 ryoon Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/kernel.h> 39 #include <sys/sysctl.h> 40 #include <sys/bus.h> 41 #include <sys/bitops.h> 42 43 #include <dev/wscons/wsconsio.h> 44 #include <dev/wscons/wsmousevar.h> 45 46 #include <dev/pckbport/pckbportvar.h> 47 #include <dev/pckbport/pmsreg.h> 48 #include <dev/pckbport/pmsvar.h> 49 #include <dev/pckbport/alpsreg.h> 50 #include <dev/pckbport/alpsvar.h> 51 52 /* #define ALPS_DEBUG */ 53 54 static int alps_touchpad_movement_threshold_nodenum; 55 static int alps_touchpad_xy_unprecision_nodenum; 56 static int alps_trackstick_xy_precision_nodenum; 57 58 static int alps_touchpad_movement_threshold = 4; 59 static int alps_touchpad_xy_unprecision = 2; 60 static int alps_trackstick_xy_precision = 1; 61 62 static void pms_alps_input_v7(void *, int); 63 static void pms_alps_input_v2(void *, int); 64 65 static int 66 pms_sysctl_alps_verify(SYSCTLFN_ARGS) 67 { 68 int error, t; 69 struct sysctlnode node; 70 71 node = *rnode; 72 t = *(int *)rnode->sysctl_data; 73 node.sysctl_data = &t; 74 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 75 if (error || newp == NULL) 76 return error; 77 78 if (node.sysctl_num == alps_touchpad_xy_unprecision_nodenum || 79 node.sysctl_num == alps_trackstick_xy_precision_nodenum) { 80 if (t < 0 || t > 7) 81 return EINVAL; 82 } else if (node.sysctl_num == alps_touchpad_movement_threshold_nodenum) { 83 if (t < 0) 84 return EINVAL; 85 } else 86 return EINVAL; 87 88 *(int *)rnode->sysctl_data = t; 89 90 return 0; 91 92 } 93 94 static void 95 pms_sysctl_alps(struct sysctllog **clog) 96 { 97 const struct sysctlnode *node; 98 int rc, root_num; 99 100 if ((rc = sysctl_createv(clog, 0, NULL, &node, 101 CTLFLAG_PERMANENT, CTLTYPE_NODE, "alps", 102 SYSCTL_DESCR("ALPS touchpad controls"), 103 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 104 goto err; 105 106 root_num = node->sysctl_num; 107 108 if ((rc = sysctl_createv(clog, 0, NULL, &node, 109 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 110 CTLTYPE_INT, "touchpad_xy_precision_shift", 111 SYSCTL_DESCR("Touchpad X/Y-axis precision shift value"), 112 pms_sysctl_alps_verify, 0, 113 &alps_touchpad_xy_unprecision, 114 0, CTL_HW, root_num, CTL_CREATE, 115 CTL_EOL)) != 0) 116 goto err; 117 alps_touchpad_xy_unprecision_nodenum = node->sysctl_num; 118 119 if ((rc = sysctl_createv(clog, 0, NULL, &node, 120 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 121 CTLTYPE_INT, "trackstick_xy_precision_shift", 122 SYSCTL_DESCR("Trackstick X/Y-axis precision value"), 123 pms_sysctl_alps_verify, 0, 124 &alps_trackstick_xy_precision, 125 0, CTL_HW, root_num, CTL_CREATE, 126 CTL_EOL)) != 0) 127 goto err; 128 alps_trackstick_xy_precision_nodenum = node->sysctl_num; 129 130 if ((rc = sysctl_createv(clog, 0, NULL, &node, 131 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 132 CTLTYPE_INT, "touchpad_movement_threshold", 133 SYSCTL_DESCR("Minimum reported movement threshold"), 134 pms_sysctl_alps_verify, 0, 135 &alps_touchpad_movement_threshold, 136 0, CTL_HW, root_num, CTL_CREATE, 137 CTL_EOL)) != 0) 138 goto err; 139 alps_touchpad_movement_threshold_nodenum = node->sysctl_num; 140 141 return; 142 143 err: 144 aprint_error("%s: sysctl_createv failed (rc = %d)\n", 145 __func__, rc); 146 } 147 148 /* 149 * Publish E6 report command and get E6 signature, 150 * then check the signature 151 */ 152 static int 153 pms_alps_e6sig(struct pms_softc *psc, uint8_t *e6sig) 154 { 155 uint8_t cmd[2]; 156 int res; 157 158 e6sig[0] = 0; 159 cmd[0] = PMS_SET_RES; /* E8 */ 160 cmd[1] = 0; 161 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 162 cmd, 2, 0, NULL, 0)) != 0) 163 goto err; 164 cmd[0] = PMS_SET_SCALE11; /* E6 */ 165 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 166 cmd, 1, 0, NULL, 0)) != 0) 167 goto err; 168 cmd[0] = PMS_SET_SCALE11; /* E6 */ 169 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 170 cmd, 1, 0, NULL, 0)) != 0) 171 goto err; 172 cmd[0] = PMS_SET_SCALE11; /* E6 */ 173 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 174 cmd, 1, 0, NULL, 0)) != 0) 175 goto err; 176 e6sig[0] = e6sig[1] = e6sig[2] = 0; 177 /* Get E6 signature */ 178 cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */ 179 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 180 cmd, 1, 3, e6sig, 0)) != 0) 181 goto err; 182 183 /* ALPS input device returns 00-00-64 as E6 signature */ 184 if ((e6sig[0] & ~0x07u) != 0x00 || /* ignore buttons */ 185 e6sig[1] != 0x00 || 186 e6sig[2] != 0x64) 187 { 188 return ENODEV; /* This is not an ALPS device */ 189 } 190 191 aprint_debug_dev(psc->sc_dev, 192 "ALPS PS/2 E6 signature: 0x%X 0x%X 0x%X\n", 193 e6sig[0], e6sig[1], e6sig[2]); 194 195 return 0; 196 err: 197 aprint_error_dev(psc->sc_dev, "Failed to get E6 signature.\n"); 198 return res; 199 } 200 201 /* 202 * Publish E7 report command and get E7 signature 203 */ 204 static int 205 pms_alps_e7sig(struct pms_softc *psc, uint8_t *e7sig) 206 { 207 uint8_t cmd[2]; 208 int res; 209 210 cmd[0] = PMS_SET_RES; /* E8 */ 211 cmd[1] = 0; 212 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 213 cmd, 2, 0, NULL, 0)) != 0) 214 goto err; 215 cmd[0] = PMS_SET_SCALE21; /* E7 */ 216 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 217 cmd, 1, 0, NULL, 0)) != 0) 218 goto err; 219 cmd[0] = PMS_SET_SCALE21; /* E7 */ 220 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 221 cmd, 1, 0, NULL, 0)) != 0) 222 goto err; 223 cmd[0] = PMS_SET_SCALE21; /* E7 */ 224 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 225 cmd, 1, 0, NULL, 0)) != 0) 226 goto err; 227 e7sig[0] = e7sig[1] = e7sig[2] = 0; 228 cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */ 229 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 230 cmd, 1, 3, e7sig, 0)) != 0) 231 goto err; 232 233 aprint_debug_dev(psc->sc_dev, 234 "ALPS PS/2 E7 signature: 0x%X 0x%X 0x%X\n", 235 e7sig[0], e7sig[1], e7sig[2]); 236 237 if (e7sig[0] != 0x73) 238 return ENODEV; /* This is not an ALPS device */ 239 240 return 0; 241 err: 242 aprint_error_dev(psc->sc_dev, "Failed to get E7 signature.\n"); 243 return res; 244 } 245 246 /* 247 * Publish EC command and get EC signature 248 */ 249 static int 250 pms_alps_ecsig(struct pms_softc *psc, uint8_t *ecsig) 251 { 252 uint8_t cmd[2]; 253 int res; 254 255 cmd[0] = PMS_SET_RES; /* E8 */ 256 cmd[1] = 0; 257 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 258 cmd, 2, 0, NULL, 0)) != 0) 259 goto err; 260 cmd[0] = PMS_RESET_WRAP_MODE; /* EC */ 261 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 262 cmd, 1, 0, NULL, 0)) != 0) 263 goto err; 264 cmd[0] = PMS_RESET_WRAP_MODE; /* EC */ 265 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 266 cmd, 1, 0, NULL, 0)) != 0) 267 goto err; 268 cmd[0] = PMS_RESET_WRAP_MODE; /* EC */ 269 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 270 cmd, 1, 0, NULL, 0)) != 0) 271 goto err; 272 ecsig[0] = ecsig[1] = ecsig[2] = 0; 273 cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */ 274 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 275 cmd, 1, 3, ecsig, 0)) != 0) 276 goto err; 277 278 aprint_debug_dev(psc->sc_dev, 279 "ALPS PS/2 EC signature: 0x%X 0x%X 0x%X\n", 280 ecsig[0], ecsig[1], ecsig[2]); 281 282 return 0; 283 284 err: 285 aprint_debug_dev(psc->sc_dev, "Failed to get EC signature.\n"); 286 return res; 287 } 288 289 /* 290 * Enter to command mode 291 */ 292 static int 293 pms_alps_start_command_mode(struct pms_softc *psc) 294 { 295 uint8_t cmd[1]; 296 uint8_t resp[3]; 297 int res; 298 299 cmd[0] = PMS_RESET_WRAP_MODE; /* EC */ 300 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 301 cmd, 1, 0, NULL, 0)) != 0) 302 goto err; 303 cmd[0] = PMS_RESET_WRAP_MODE; /* EC */ 304 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 305 cmd, 1, 0, NULL, 0)) != 0) 306 goto err; 307 cmd[0] = PMS_RESET_WRAP_MODE; /* EC */ 308 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 309 cmd, 1, 0, NULL, 0)) != 0) 310 goto err; 311 resp[0] = resp[1] = resp[2] = 0; 312 cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */ 313 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 314 cmd, 1, 3, resp, 0)) != 0) 315 goto err; 316 317 aprint_debug_dev(psc->sc_dev, "ALPS Firmware ID: 0x%x 0x%X 0x%X\n", 318 resp[0], resp[1], resp[2]); 319 320 if (resp[0] != 0x88 || (resp[1] & __BITS(7, 4)) != 0xb0) 321 return EINVAL; 322 323 return 0; 324 err: 325 aprint_error_dev(psc->sc_dev, "Failed to start command mode.\n"); 326 return res; 327 } 328 329 /* 330 * End command mode 331 */ 332 static int 333 pms_alps_end_command_mode(struct pms_softc *psc) 334 { 335 int res; 336 uint8_t cmd[1]; 337 338 cmd[0] = PMS_SET_STREAM; /* EA */ 339 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 340 cmd, 1, 0, NULL, 0)) != 0) 341 goto err; 342 343 return res; 344 345 err: 346 aprint_error_dev(psc->sc_dev, "Failed to end command mode.\n"); 347 return res; 348 } 349 350 /* 351 * Write nibble (4-bit) data 352 */ 353 static int 354 pms_alps_cm_write_nibble(pckbport_tag_t tag, pckbport_slot_t slot, uint8_t nibble) 355 { 356 uint8_t cmd[2]; 357 uint8_t resp[3]; 358 int sendparam; 359 int receive; 360 int res; 361 362 sendparam = alps_v7_nibble_command_data_arr[nibble].sendparam; 363 receive= alps_v7_nibble_command_data_arr[nibble].receive; 364 cmd[0] = alps_v7_nibble_command_data_arr[nibble].command; 365 if (receive) { 366 if ((res = pckbport_poll_cmd(tag, slot, cmd, 1, 3, resp, 0)) != 0) { 367 aprint_error("send nibble error: %d\n", res); 368 } 369 } else if (sendparam) { 370 cmd[1] = alps_v7_nibble_command_data_arr[nibble].data; 371 if ((res = pckbport_poll_cmd(tag, slot, cmd, 2, 0, NULL, 0)) != 0) { 372 aprint_error("send nibble error: %d\n", res); 373 } 374 } else { 375 if ((res = pckbport_poll_cmd(tag, slot, cmd, 1, 0, NULL, 0)) != 0) { 376 aprint_error("send nibble error: %d\n", res); 377 } 378 } 379 380 return res; 381 } 382 383 /* 384 * Set an register address for read and write 385 */ 386 static int 387 pms_alps_set_address(pckbport_tag_t tag, pckbport_slot_t slot, uint16_t reg) 388 { 389 uint8_t cmd[1]; 390 uint8_t nibble; 391 int res; 392 393 cmd[0] = PMS_RESET_WRAP_MODE; 394 if ((res = pckbport_poll_cmd(tag, slot, cmd, 1, 0, NULL, 0)) != 0) 395 goto err; 396 397 /* Set address */ 398 nibble = (reg >> 12) & __BITS(3, 0); 399 if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) { 400 goto err; 401 } 402 nibble = (reg >> 8) & __BITS(3, 0); 403 if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) { 404 goto err; 405 } 406 nibble = (reg >> 4) & __BITS(3, 0); 407 if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) { 408 goto err; 409 } 410 nibble = (reg >> 0) & __BITS(3, 0); 411 if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) { 412 goto err; 413 } 414 return res; 415 416 err: 417 aprint_error("Failed to set addess.\n"); 418 return res; 419 } 420 421 /* 422 * Read one byte from register 423 */ 424 static int 425 pms_alps_cm_read_1(pckbport_tag_t tag, pckbport_slot_t slot, uint16_t reg, 426 uint8_t *val) 427 { 428 uint8_t cmd[1]; 429 uint8_t resp[3]; 430 int res; 431 432 if ((res = pms_alps_set_address(tag, slot, reg)) != 0) 433 goto err; 434 435 cmd[0] = PMS_SEND_DEV_STATUS; 436 if ((res = pckbport_poll_cmd(tag, slot, 437 cmd, 1, 3, resp, 0)) != 0) { 438 goto err; 439 } 440 441 if (reg != ((resp[0] << 8) | resp[1])) { 442 return EINVAL; 443 } 444 445 *val = resp[2]; 446 return res; 447 448 err: 449 aprint_error("Failed to read a value.\n"); 450 *val = 0; 451 return res; 452 } 453 454 /* 455 * Write one byte to register 456 */ 457 static int 458 pms_alps_cm_write_1(pckbport_tag_t tag, pckbport_slot_t slot, uint16_t reg, 459 uint8_t val) 460 { 461 uint8_t nibble; 462 int res; 463 464 if ((res = pms_alps_set_address(tag, slot, reg)) != 0) 465 goto err; 466 467 nibble = __SHIFTOUT(val, __BITS(7, 4)); 468 if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) { 469 goto err; 470 } 471 472 nibble = __SHIFTOUT(val, __BITS(3, 0)); 473 if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) { 474 goto err; 475 } 476 477 return res; 478 err: 479 aprint_error("Failed to write a value.\n"); 480 return res; 481 } 482 483 /* 484 * Not used practically for initialization 485 */ 486 static int 487 pms_alps_get_resolution_v7(struct pms_softc *psc) 488 { 489 #if 0 490 struct alps_softc *sc = &psc->u.alps; 491 #endif 492 pckbport_tag_t tag = psc->sc_kbctag; 493 pckbport_slot_t slot = psc->sc_kbcslot; 494 495 int res; 496 uint8_t ret; 497 #if 0 498 uint32_t x_pitch, y_pitch; 499 uint32_t x_elec, y_elec; 500 uint32_t x_phy, y_phy; 501 #endif 502 /* X/Y pitch */ 503 if ((res = pms_alps_cm_read_1(tag, slot, 0xc397, &ret)) != 0) { 504 goto err; 505 } 506 #if 0 507 /* X pitch */ 508 x_pitch = __SHIFTOUT(ret, __BITS(7, 4)); /* Higher 4-bit */ 509 x_pitch = x_pitch * 2 + 50; /* Unit = 0.1mm */ 510 511 /* Y pitch */ 512 y_pitch = ret & __BITS(3, 0); /* Lower 4-bit */ 513 y_pitch = y_pitch * 2 + 36; /* Unit = 0.1mm */ 514 515 /* X/Y electrode */ 516 if ((res = pms_alps_cm_read_1(tag, slot, 0xc397 + 1, &ret)) != 0) { 517 goto err; 518 } 519 520 /* X electrode */ 521 x_elec = __SHIFTOUT(ret, __BITS(7, 4)); /* Higher 4-bit */ 522 x_elec = x_elec + 17; 523 524 /* Y electrode */ 525 y_elec = ret & __BITS(3, 0); /* Lower 4-bit */ 526 y_elec = y_elec + 13; 527 528 /* X/Y physical in unit = 0.1mm */ 529 /* X physical */ 530 x_phy = (x_elec - 1) * x_pitch; 531 y_phy = (y_elec - 1) * y_pitch; 532 533 /* X/Y resolution (unit) */ 534 sc->res_x = 0xfff * 10 / x_phy; 535 sc->res_y = 0x7ff * 10 / y_phy; 536 #endif 537 return res; 538 539 err: 540 aprint_error("Failed to get resolution.\n"); 541 return res; 542 } 543 544 /* 545 * Enable tap mode for V2 device 546 */ 547 static int 548 pms_alps_enable_tap_mode_v2(struct pms_softc *psc) 549 { 550 uint8_t cmd[2]; 551 uint8_t resp[3]; 552 int res; 553 554 resp[0] = resp[1] = resp[2] = 0; 555 cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */ 556 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 557 cmd, 1, 3, resp, 0)) != 0) 558 goto err; 559 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 560 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 561 cmd, 1, 0, NULL, 0)) != 0) 562 goto err; 563 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 564 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 565 cmd, 1, 0, NULL, 0)) != 0) 566 goto err; 567 cmd[0] = PMS_SET_SAMPLE; 568 cmd[1] = 0x0a; /* argument */ 569 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 570 cmd, 2, 0, NULL, 0)) != 0) 571 goto err; 572 573 /* Get status */ 574 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 575 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 576 cmd, 1, 0, NULL, 0)) != 0) 577 goto err; 578 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 579 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 580 cmd, 1, 0, NULL, 0)) != 0) 581 goto err; 582 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 583 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 584 cmd, 1, 0, NULL, 0)) != 0) 585 goto err; 586 resp[0] = resp[1] = resp[2] = 0; 587 cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */ 588 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 589 cmd, 1, 3, resp, 0)) != 0) 590 goto err; 591 592 aprint_debug_dev(psc->sc_dev, "Tap mode is enabled.\n"); 593 594 return 0; 595 err: 596 aprint_error_dev(psc->sc_dev, "Failed to enable tap mode.\n"); 597 return res; 598 } 599 600 static int 601 pms_alps_init_v2(struct pms_softc *psc) 602 { 603 uint8_t cmd[1]; 604 int res; 605 606 if ((res = pms_alps_enable_tap_mode_v2(psc)) != 0) 607 goto err; 608 609 /* Enable absolute mode */ 610 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 611 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 612 cmd, 1, 0, NULL, 0)) != 0) 613 goto err; 614 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 615 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 616 cmd, 1, 0, NULL, 0)) != 0) 617 goto err; 618 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 619 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 620 cmd, 1, 0, NULL, 0)) != 0) 621 goto err; 622 cmd[0] = PMS_DEV_DISABLE; /* F5 */ 623 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 624 cmd, 1, 0, NULL, 0)) != 0) 625 goto err; 626 cmd[0] = PMS_DEV_ENABLE; /* F4 */ 627 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 628 cmd, 1, 0, NULL, 0)) != 0) 629 goto err; 630 631 /* Enable remote mode */ 632 cmd[0] = PMS_SET_REMOTE_MODE; /* F0 */ 633 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 634 cmd, 1, 0, NULL, 0)) != 0) 635 goto err; 636 637 /* Start stream mode to get data */ 638 cmd[0] = PMS_SET_STREAM; /* EA */ 639 if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 640 cmd, 1, 0, NULL, 0)) != 0) 641 goto err; 642 643 644 return 0; 645 646 err: 647 aprint_error_dev(psc->sc_dev, "Failed to initialize V2 device.\n"); 648 return res; 649 } 650 651 static int 652 pms_alps_init_v7(struct pms_softc *psc) 653 { 654 uint8_t val; 655 uint8_t nibble; 656 int res; 657 658 /* Start command mode */ 659 if ((res = pms_alps_start_command_mode(psc)) != 0) { 660 goto err; 661 } 662 if ((res = pms_alps_cm_read_1(psc->sc_kbctag, psc->sc_kbcslot, 0xc2d9, &val)) != 0) { 663 goto err; 664 } 665 if ((res = pms_alps_get_resolution_v7(psc)) != 0) { 666 goto err; 667 } 668 if ((res = pms_alps_cm_write_1(psc->sc_kbctag, psc->sc_kbcslot, 0xc2c9, 0x64)) != 0) { 669 goto err; 670 } 671 672 /* Start absolute mode */ 673 if ((res = pms_alps_cm_read_1(psc->sc_kbctag, psc->sc_kbcslot, 0xc2c4, &val)) != 0) { 674 goto err; 675 } 676 /* Do not set address before this, so do not use pms_cm_write_1() */ 677 val = val | __BIT(1); 678 nibble = __SHIFTOUT(val, __BITS(7, 4)); 679 if ((res = pms_alps_cm_write_nibble(psc->sc_kbctag, psc->sc_kbcslot, nibble)) != 0) { 680 goto err; 681 } 682 nibble = __SHIFTOUT(val, __BITS(3, 0)); 683 if ((res = pms_alps_cm_write_nibble(psc->sc_kbctag, psc->sc_kbcslot, nibble)) != 0) { 684 goto err; 685 } 686 687 /* End command mode */ 688 if ((res = pms_alps_end_command_mode(psc)) != 0) 689 goto err; 690 691 return res; 692 693 err: 694 (void)pms_alps_end_command_mode(psc); 695 aprint_error_dev(psc->sc_dev, "Failed to initialize V7 device.\n"); 696 return res; 697 } 698 699 int 700 pms_alps_probe_init(void *opaque) 701 { 702 struct pms_softc *psc = opaque; 703 struct alps_softc *sc = &psc->u.alps; 704 struct sysctllog *clog = NULL; 705 uint8_t e6sig[3]; 706 uint8_t e7sig[3]; 707 uint8_t ecsig[3]; 708 int res; 709 u_char cmd[1]; 710 711 sc->last_x1 = 0; 712 sc->last_y1 = 0; 713 sc->last_x2 = 0; 714 sc->last_y2 = 0; 715 sc->last_nfingers = 0; 716 717 pckbport_flush(psc->sc_kbctag, psc->sc_kbcslot); 718 719 if ((res = pms_alps_e6sig(psc, e6sig)) != 0) 720 goto err; 721 722 if ((res = pms_alps_e7sig(psc, e7sig)) != 0) 723 goto err; 724 725 if ((res = pms_alps_ecsig(psc, ecsig)) != 0) 726 goto err; 727 728 /* Determine protocol version */ 729 if ((ecsig[0] == 0x88) && (__SHIFTOUT(ecsig[1], __BITS(7, 4)) == 0x0b)) { 730 /* V7 device in Toshiba dynabook R63/PS */ 731 sc->version = ALPS_PROTO_V7; 732 } else if ((e7sig[0] == 0x73) && (e7sig[1] == 0x02) && 733 ((e7sig[2] == 0x14) || (e7sig[2] == 0x0a))) { 734 /* 0x14: V2 device in NEC VJ22MF-7 (VersaPro JVF-7) */ 735 /* 0x0a: V2 devices in Toshiba dynabook satellite B551/D 736 and dynabook SS RX1 */ 737 sc->version = ALPS_PROTO_V2; 738 } 739 740 if (sc->version == ALPS_PROTO_V7) { 741 /* Initialize V7 device */ 742 if ((res = pms_alps_init_v7(psc)) != 0) 743 goto err; 744 aprint_normal_dev(psc->sc_dev, 745 "ALPS PS/2 V7 pointing device\n"); 746 } else if (sc->version == ALPS_PROTO_V2) { 747 /* Initialize V2 pointing device */ 748 if ((res = pms_alps_init_v2(psc)) != 0) 749 goto err; 750 aprint_normal_dev(psc->sc_dev, 751 "ALPS PS/2 V2 pointing device\n"); 752 } else { 753 res = EINVAL; 754 goto err; 755 } 756 757 /* From sysctl */ 758 pms_sysctl_alps(&clog); 759 /* Register hundler */ 760 if (sc->version == ALPS_PROTO_V7) { 761 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot, 762 pms_alps_input_v7, psc, device_xname(psc->sc_dev)); 763 } else if (sc->version == ALPS_PROTO_V2) { 764 pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot, 765 pms_alps_input_v2, psc, device_xname(psc->sc_dev)); 766 } else { 767 res = EINVAL; 768 goto err; 769 } 770 /* Palm detection is enabled. */ 771 772 return 0; 773 774 err: 775 cmd[0] = PMS_RESET; 776 (void)pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, 777 cmd, 1, 2, NULL, 1); 778 if (res != ENODEV) 779 aprint_error_dev(psc->sc_dev, "Failed to initialize an ALPS device.\n"); 780 return res; 781 } 782 783 void 784 pms_alps_enable(void *opaque) 785 { 786 struct pms_softc *psc = opaque; 787 struct alps_softc *sc = &psc->u.alps; 788 789 sc->initializing = true; 790 } 791 792 void 793 pms_alps_resume(void *opaque) 794 { 795 struct pms_softc *psc = opaque; 796 struct alps_softc *sc = &psc->u.alps; 797 uint8_t cmd, resp[2]; 798 int res; 799 800 cmd = PMS_RESET; 801 res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, &cmd, 802 1, 2, resp, 1); 803 if (res) 804 aprint_error_dev(psc->sc_dev, 805 "ALPS reset on resume failed\n"); 806 else { 807 if (sc->version == ALPS_PROTO_V7) { 808 (void)pms_alps_init_v7(psc); 809 } else if (sc->version == ALPS_PROTO_V2) { 810 (void)pms_alps_init_v2(psc); 811 } else { 812 /* Not supported */ 813 } 814 pms_alps_enable(psc); 815 } 816 } 817 818 static void 819 pms_alps_decode_trackstick_packet_v7(struct pms_softc *psc) 820 { 821 int s; 822 823 int x, y, z; 824 int dx, dy, dz; 825 int left, middle, right; 826 u_int buttons; 827 828 x = (int8_t)((psc->packet[2] & 0xbf) | 829 ((psc->packet[3] & 0x10) << 2)); 830 y = (int8_t)((psc->packet[3] & 0x07) | (psc->packet[4] & 0xb8) | 831 ((psc->packet[3] & 0x20) << 1)); 832 z = (int8_t)((psc->packet[5] & 0x3f) | 833 ((psc->packet[3] & 0x80) >> 1)); 834 835 dx = x * alps_trackstick_xy_precision; 836 dy = y * alps_trackstick_xy_precision; 837 dz = z * 1; 838 839 left = psc->packet[1] & 0x01; 840 middle = (psc->packet[1] & 0x04) >> 2; 841 right = (psc->packet[1] & 0x02) >> 1; 842 buttons = 0; 843 buttons = (u_int)((left << 0) | (middle << 1) | (right << 2)); 844 845 s = spltty(); 846 wsmouse_input(psc->sc_wsmousedev, 847 buttons, 848 dx, dy, dz, 0, 849 WSMOUSE_INPUT_DELTA); 850 splx(s); 851 } 852 853 static uint8_t 854 pms_alps_decode_packetid_v7(struct pms_softc *psc) 855 { 856 if (psc->packet[4] & 0x40) 857 return ALPS_V7_PACKETID_TWOFINGER; 858 else if (psc->packet[4] & 0x01) 859 return ALPS_V7_PACKETID_MULTIFINGER; 860 else if ((psc->packet[0] & 0x10) && !(psc->packet[4] & 0x43)) 861 return ALPS_V7_PACKETID_NEWPACKET; 862 else if ((psc->packet[1] == 0x00) && (psc->packet[4] == 0x00)) 863 return ALPS_V7_PACKETID_IDLE; 864 else 865 return ALPS_V7_PACKETID_UNKNOWN; 866 } 867 868 static void 869 pms_alps_decode_touchpad_packet_v7(struct pms_softc *psc) 870 { 871 int s; 872 struct alps_softc *sc = &psc->u.alps; 873 uint8_t packetid; 874 875 uint16_t cur_x1, cur_y1; 876 uint16_t cur_x2, cur_y2; 877 int dx1, dy1; 878 int button; 879 u_int buttons; 880 881 packetid = pms_alps_decode_packetid_v7(psc); 882 switch (packetid) { 883 case ALPS_V7_PACKETID_IDLE: 884 /* Accept meaningful packets only */ 885 return; 886 case ALPS_V7_PACKETID_UNKNOWN: 887 /* Accept meaningful packets only */ 888 return; 889 case ALPS_V7_PACKETID_NEWPACKET: 890 /* Sent new packet ID to reset status and not decoded */ 891 sc->initializing = true; 892 return; 893 } 894 895 /* Decode a number of fingers and locations */ 896 /* X0-11 ... X0-0 */ 897 cur_x1 = (psc->packet[2] & 0x80) << 4; /* X0-11 */ 898 cur_x1 |= (psc->packet[2] & 0x3f) << 5; /* X0-10 ... X0-5 */ 899 cur_x1 |= (psc->packet[3] & 0x30) >> 1; /* X0-4, X0-3 */ 900 cur_x1 |= psc->packet[3] & 0x07; /* X0-2 ... X0-0 */ 901 902 /* Y0-10 ... Y0-0 */ 903 cur_y1 = psc->packet[1] << 3; /* Y0-10 ... Y0-3 */ 904 cur_y1 |= psc->packet[0] & 0x07; /* Y0-2 ... Y0-0 */ 905 906 /* X1-11 ... X1-3 */ 907 cur_x2 = (psc->packet[3] & 0x80) << 4; /* X1-11 */ 908 cur_x2 |= (psc->packet[4] & 0x80) << 3; /* X1-10 */ 909 cur_x2 |= (psc->packet[4] & 0x3f) << 4; /* X1-9 ... X1-4 */ 910 911 /* Y1-10 ... Y1-4 */ 912 cur_y2 = (psc->packet[5] & 0x80) << 3; /* Y1-10 */ 913 cur_y2 |= (psc->packet[5] & 0x3f) << 4; /* Y1-9 .. Y1-4 */ 914 915 switch (packetid) { 916 case ALPS_V7_PACKETID_TWOFINGER: 917 cur_x2 &= ~__BITS(3, 0); /* Clear undefined locations */ 918 cur_y2 |= __BITS(3, 0); /* Fill undefined locations */ 919 break; 920 case ALPS_V7_PACKETID_MULTIFINGER: 921 cur_x2 &= ~__BITS(5, 0); /* Clear undefined locations */ 922 cur_y2 &= ~__BIT(5); /* Clear duplicate locations */ 923 cur_y2 |= (psc->packet[4] & __BIT(1)) << 4; /* Set another */ 924 cur_y2 |= __BITS(4, 0); /* Fill undefined locations */ 925 break; 926 } 927 928 cur_y1 = 0x7ff - cur_y1; 929 cur_y2 = 0x7ff - cur_y2; 930 931 /* Handle finger touch reported in cur_x2/y2. only */ 932 if (cur_x1 == 0 && cur_y1 == 0 && cur_x2 != 0 && cur_y2 != 0) { 933 cur_x1 = cur_x2; 934 cur_y1 = cur_y2; 935 cur_x2 = 0; 936 cur_y2 = 0; 937 } 938 939 switch (packetid) { 940 case ALPS_V7_PACKETID_TWOFINGER: 941 if ((cur_x2 == 0) && (cur_y2 == 0)) 942 sc->nfingers = 1; 943 else 944 sc->nfingers = 2; 945 break; 946 case ALPS_V7_PACKETID_MULTIFINGER: 947 sc->nfingers = 3 + (psc->packet[5] & 0x03); 948 break; 949 } 950 951 button = (psc->packet[0] & 0x80) >> 7; 952 buttons = 0; 953 if (sc->nfingers == 1) { 954 if (button && (cur_y1 > 1700) && (cur_x1 < 1700)) 955 buttons |= button << 0; /* Left button */ 956 else if (button && (cur_y1 > 1700) 957 && (1700 <= cur_x1) && (cur_x1 <= 2700)) 958 buttons |= button << 1; /* Middle button */ 959 else if (button && (cur_y1 > 1700) && (2700 < cur_x1)) 960 buttons |= button << 2; /* Right button */ 961 } else if (sc->nfingers > 1) { 962 if (button && (cur_y2 > 1700) && (cur_x2 < 1700)) 963 buttons |= button << 0; /* Left button */ 964 else if (button && (cur_y2 > 1700) 965 && (1700 <= cur_x2) && (cur_x2 <= 2700)) 966 buttons |= button << 1; /* Middle button */ 967 else if (button && (cur_y2 > 1700) && (2700 < cur_x2)) 968 buttons |= button << 2; /* Right button */ 969 } 970 971 /* New touch */ 972 if (sc->nfingers == 0 || sc->nfingers != sc->last_nfingers) 973 sc->initializing = true; 974 975 if (sc->initializing == true) { 976 dx1 = 0; 977 dy1 = 0; 978 } else { 979 dx1 = (int16_t)(cur_x1 - sc->last_x1); 980 dy1 = (int16_t)(sc->last_y1 - cur_y1); 981 982 dx1 = dx1 >> alps_touchpad_xy_unprecision; 983 dy1 = dy1 >> alps_touchpad_xy_unprecision; 984 } 985 986 if (abs(dx1) < alps_touchpad_movement_threshold) { 987 dx1 = 0; 988 } 989 if (abs(dy1) < alps_touchpad_movement_threshold) { 990 dy1 = 0; 991 } 992 993 /* Allow finger detouch during drag and drop */ 994 if ((sc->nfingers < sc->last_nfingers) 995 && (cur_x2 == sc->last_x1) && (cur_y2 == sc->last_y1)) { 996 sc->last_x1 = sc->last_x2; 997 sc->last_y1 = sc->last_y2; 998 dx1 = 0; 999 dy1 = 0; 1000 } 1001 1002 s = spltty(); 1003 wsmouse_input(psc->sc_wsmousedev, 1004 buttons, 1005 dx1, dy1, 0, 0, 1006 WSMOUSE_INPUT_DELTA); 1007 splx(s); 1008 1009 if (sc->initializing == true || (dx1 != 0)) 1010 sc->last_x1 = cur_x1; 1011 if (sc->initializing == true || (dy1 != 0)) 1012 sc->last_y1 = cur_y1; 1013 1014 if (sc->nfingers > 0) 1015 sc->initializing = false; 1016 sc->last_nfingers = sc->nfingers; 1017 } 1018 1019 static void 1020 pms_alps_dispatch_packet_v7(struct pms_softc *psc) 1021 { 1022 if ((psc->packet[0] == 0x48) && ((psc->packet[4] & 0x47) == 0x06)) 1023 pms_alps_decode_trackstick_packet_v7(psc); 1024 else 1025 pms_alps_decode_touchpad_packet_v7(psc); 1026 } 1027 1028 static void 1029 pms_alps_decode_touchpad_packet_v2(struct pms_softc *psc) 1030 { 1031 int s; 1032 struct alps_softc *sc = &psc->u.alps; 1033 uint16_t cur_x, cur_y; 1034 int16_t dx, dy; 1035 u_int left, middle, right; 1036 u_int forward, back; 1037 u_int buttons; 1038 uint8_t ges; 1039 1040 sc->nfingers = (psc->packet[2] & 0x02) >> 1; 1041 if (sc->last_nfingers == 0) 1042 sc->initializing = true; 1043 1044 left = psc->packet[3] & 0x01; 1045 right = (psc->packet[3] & 0x02) >> 1; 1046 middle = (psc->packet[3] & 0x04) >> 2; 1047 1048 cur_x = psc->packet[1]; 1049 cur_x |= (psc->packet[2] & 0x78) << 4; 1050 1051 cur_y = psc->packet[4]; 1052 cur_y |= (psc->packet[3] & 0x70) << 3; 1053 1054 #if 0 1055 cur_z = psc->packet[5]; 1056 #endif 1057 1058 forward = (psc->packet[2] & 0x04) >> 2; 1059 back = (psc->packet[3] & 0x04) >> 2; 1060 ges = psc->packet[2] & 0x01; 1061 1062 buttons = (left | ges) << 0; 1063 buttons |= (middle | forward | back) << 1; 1064 buttons |= right << 2; 1065 1066 if (sc->initializing == true) { 1067 dx = 0; 1068 dy = 0; 1069 } else { 1070 dx = (cur_x - sc->last_x1); 1071 dy = (sc->last_y1 - cur_y); 1072 1073 dx = dx >> alps_touchpad_xy_unprecision; 1074 dy = dy >> alps_touchpad_xy_unprecision; 1075 } 1076 1077 s = spltty(); 1078 wsmouse_input(psc->sc_wsmousedev, 1079 buttons, 1080 dx, dy, 0, 0, 1081 WSMOUSE_INPUT_DELTA); 1082 splx(s); 1083 1084 if (sc->initializing == true || (dx != 0)) 1085 sc->last_x1 = cur_x; 1086 if (sc->initializing == true || (dy != 0)) 1087 sc->last_y1 = cur_y; 1088 1089 if (sc->nfingers > 0) 1090 sc->initializing = false; 1091 sc->last_nfingers = sc->nfingers; 1092 } 1093 1094 static void 1095 pms_alps_input_v2(void *opaque, int data) 1096 { 1097 struct pms_softc *psc = opaque; 1098 1099 if (!psc->sc_enabled) 1100 return; 1101 1102 psc->packet[psc->inputstate++] = data & 0xff; 1103 if (psc->inputstate < 6) 1104 return; 1105 1106 pms_alps_decode_touchpad_packet_v2(psc); 1107 1108 psc->inputstate = 0; 1109 } 1110 1111 static void 1112 pms_alps_input_v7(void *opaque, int data) 1113 { 1114 struct pms_softc *psc = opaque; 1115 1116 if (!psc->sc_enabled) 1117 return; 1118 1119 psc->packet[psc->inputstate++] = data & 0xff; 1120 if (psc->inputstate < 6) 1121 return; 1122 1123 pms_alps_dispatch_packet_v7(psc); 1124 1125 psc->inputstate = 0; 1126 } 1127