1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020, 2022 Vladimir Kondratyev <wulf@FreeBSD.org> 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * Elan I2C Touchpad driver. Based on Linux driver. 30 * https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/input/mouse/elan_i2c_core.c 31 */ 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/endian.h> 36 #include <sys/kernel.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/module.h> 40 #include <sys/mutex.h> 41 #include <sys/sysctl.h> 42 #include <sys/systm.h> 43 44 #include <dev/evdev/evdev.h> 45 #include <dev/evdev/input.h> 46 47 #include <dev/iicbus/iic.h> 48 #include <dev/iicbus/iicbus.h> 49 50 #define HID_DEBUG_VAR ietp_debug 51 #include <dev/hid/hid.h> 52 #include <dev/hid/hidbus.h> 53 #include <dev/hid/hidquirk.h> 54 55 #ifdef HID_DEBUG 56 static SYSCTL_NODE(_hw_hid, OID_AUTO, ietp, CTLFLAG_RW, 0, 57 "Elantech Touchpad"); 58 static int ietp_debug = 1; 59 SYSCTL_INT(_hw_hid_ietp, OID_AUTO, debug, CTLFLAG_RWTUN, 60 &ietp_debug, 1, "Debug level"); 61 #endif 62 63 #define IETP_PATTERN 0x0100 64 #define IETP_UNIQUEID 0x0101 65 #define IETP_FW_VERSION 0x0102 66 #define IETP_IC_TYPE 0x0103 67 #define IETP_OSM_VERSION 0x0103 68 #define IETP_NSM_VERSION 0x0104 69 #define IETP_TRACENUM 0x0105 70 #define IETP_MAX_X_AXIS 0x0106 71 #define IETP_MAX_Y_AXIS 0x0107 72 #define IETP_RESOLUTION 0x0108 73 #define IETP_PRESSURE 0x010A 74 75 #define IETP_CONTROL 0x0300 76 #define IETP_CTRL_ABSOLUTE 0x0001 77 #define IETP_CTRL_STANDARD 0x0000 78 79 #define IETP_REPORT_LEN_LO 32 80 #define IETP_REPORT_LEN_HI 37 81 #define IETP_MAX_FINGERS 5 82 83 #define IETP_REPORT_ID_LO 0x5D 84 #define IETP_REPORT_ID_HI 0x60 85 86 #define IETP_TOUCH_INFO 1 87 #define IETP_FINGER_DATA 2 88 #define IETP_FINGER_DATA_LEN 5 89 #define IETP_HOVER_INFO 28 90 #define IETP_WH_DATA 31 91 92 #define IETP_TOUCH_LMB (1 << 0) 93 #define IETP_TOUCH_RMB (1 << 1) 94 #define IETP_TOUCH_MMB (1 << 2) 95 96 #define IETP_MAX_PRESSURE 255 97 #define IETP_FWIDTH_REDUCE 90 98 #define IETP_FINGER_MAX_WIDTH 15 99 #define IETP_PRESSURE_BASE 25 100 101 struct ietp_softc { 102 device_t dev; 103 104 struct evdev_dev *evdev; 105 bool open; 106 uint8_t report_id; 107 hid_size_t report_len; 108 109 uint16_t product_id; 110 uint16_t ic_type; 111 112 int32_t pressure_base; 113 uint16_t max_x; 114 uint16_t max_y; 115 uint16_t trace_x; 116 uint16_t trace_y; 117 uint16_t res_x; /* dots per mm */ 118 uint16_t res_y; 119 bool hi_precision; 120 bool is_clickpad; 121 bool has_3buttons; 122 }; 123 124 static evdev_open_t ietp_ev_open; 125 static evdev_close_t ietp_ev_close; 126 static hid_intr_t ietp_intr; 127 128 static int ietp_probe(struct ietp_softc *); 129 static int ietp_attach(struct ietp_softc *); 130 static int ietp_detach(struct ietp_softc *); 131 static int32_t ietp_res2dpmm(uint8_t, bool); 132 133 static device_identify_t ietp_iic_identify; 134 static device_probe_t ietp_iic_probe; 135 static device_attach_t ietp_iic_attach; 136 static device_detach_t ietp_iic_detach; 137 static device_resume_t ietp_iic_resume; 138 139 static int ietp_iic_read_reg(device_t, uint16_t, size_t, void *); 140 static int ietp_iic_write_reg(device_t, uint16_t, uint16_t); 141 static int ietp_iic_set_absolute_mode(device_t, bool); 142 143 #define IETP_IIC_DEV(pnp) \ 144 { HID_TLC(HUP_GENERIC_DESKTOP, HUG_MOUSE), HID_BUS(BUS_I2C), HID_PNP(pnp) } 145 146 static const struct hid_device_id ietp_iic_devs[] = { 147 IETP_IIC_DEV("ELAN0000"), 148 IETP_IIC_DEV("ELAN0100"), 149 IETP_IIC_DEV("ELAN0600"), 150 IETP_IIC_DEV("ELAN0601"), 151 IETP_IIC_DEV("ELAN0602"), 152 IETP_IIC_DEV("ELAN0603"), 153 IETP_IIC_DEV("ELAN0604"), 154 IETP_IIC_DEV("ELAN0605"), 155 IETP_IIC_DEV("ELAN0606"), 156 IETP_IIC_DEV("ELAN0607"), 157 IETP_IIC_DEV("ELAN0608"), 158 IETP_IIC_DEV("ELAN0609"), 159 IETP_IIC_DEV("ELAN060B"), 160 IETP_IIC_DEV("ELAN060C"), 161 IETP_IIC_DEV("ELAN060F"), 162 IETP_IIC_DEV("ELAN0610"), 163 IETP_IIC_DEV("ELAN0611"), 164 IETP_IIC_DEV("ELAN0612"), 165 IETP_IIC_DEV("ELAN0615"), 166 IETP_IIC_DEV("ELAN0616"), 167 IETP_IIC_DEV("ELAN0617"), 168 IETP_IIC_DEV("ELAN0618"), 169 IETP_IIC_DEV("ELAN0619"), 170 IETP_IIC_DEV("ELAN061A"), 171 IETP_IIC_DEV("ELAN061B"), 172 IETP_IIC_DEV("ELAN061C"), 173 IETP_IIC_DEV("ELAN061D"), 174 IETP_IIC_DEV("ELAN061E"), 175 IETP_IIC_DEV("ELAN061F"), 176 IETP_IIC_DEV("ELAN0620"), 177 IETP_IIC_DEV("ELAN0621"), 178 IETP_IIC_DEV("ELAN0622"), 179 IETP_IIC_DEV("ELAN0623"), 180 IETP_IIC_DEV("ELAN0624"), 181 IETP_IIC_DEV("ELAN0625"), 182 IETP_IIC_DEV("ELAN0626"), 183 IETP_IIC_DEV("ELAN0627"), 184 IETP_IIC_DEV("ELAN0628"), 185 IETP_IIC_DEV("ELAN0629"), 186 IETP_IIC_DEV("ELAN062A"), 187 IETP_IIC_DEV("ELAN062B"), 188 IETP_IIC_DEV("ELAN062C"), 189 IETP_IIC_DEV("ELAN062D"), 190 IETP_IIC_DEV("ELAN062E"), /* Lenovo V340 Whiskey Lake U */ 191 IETP_IIC_DEV("ELAN062F"), /* Lenovo V340 Comet Lake U */ 192 IETP_IIC_DEV("ELAN0631"), 193 IETP_IIC_DEV("ELAN0632"), 194 IETP_IIC_DEV("ELAN0633"), /* Lenovo S145 */ 195 IETP_IIC_DEV("ELAN0634"), /* Lenovo V340 Ice lake */ 196 IETP_IIC_DEV("ELAN0635"), /* Lenovo V1415-IIL */ 197 IETP_IIC_DEV("ELAN0636"), /* Lenovo V1415-Dali */ 198 IETP_IIC_DEV("ELAN0637"), /* Lenovo V1415-IGLR */ 199 IETP_IIC_DEV("ELAN1000"), 200 }; 201 202 static uint8_t const ietp_dummy_rdesc_lo[] = { 203 0x05, HUP_GENERIC_DESKTOP, /* Usage Page (Generic Desktop Ctrls) */ 204 0x09, HUG_MOUSE, /* Usage (Mouse) */ 205 0xA1, 0x01, /* Collection (Application) */ 206 0x09, 0x01, /* Usage (0x01) */ 207 0x15, 0x00, /* Logical Minimum (0) */ 208 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ 209 0x95, IETP_REPORT_LEN_LO, /* Report Count (IETP_REPORT_LEN_LO) */ 210 0x75, 0x08, /* Report Size (8) */ 211 0x81, 0x02, /* Input (Data,Var,Abs) */ 212 0xC0, /* End Collection */ 213 }; 214 215 static uint8_t const ietp_dummy_rdesc_hi[] = { 216 0x05, HUP_GENERIC_DESKTOP, /* Usage Page (Generic Desktop Ctrls) */ 217 0x09, HUG_MOUSE, /* Usage (Mouse) */ 218 0xA1, 0x01, /* Collection (Application) */ 219 0x09, 0x01, /* Usage (0x01) */ 220 0x15, 0x00, /* Logical Minimum (0) */ 221 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ 222 0x95, IETP_REPORT_LEN_HI, /* Report Count (IETP_REPORT_LEN_HI) */ 223 0x75, 0x08, /* Report Size (8) */ 224 0x81, 0x02, /* Input (Data,Var,Abs) */ 225 0xC0, /* End Collection */ 226 }; 227 228 static const struct evdev_methods ietp_evdev_methods = { 229 .ev_open = &ietp_ev_open, 230 .ev_close = &ietp_ev_close, 231 }; 232 233 static int 234 ietp_ev_open(struct evdev_dev *evdev) 235 { 236 struct ietp_softc *sc = evdev_get_softc(evdev); 237 int error; 238 239 error = hid_intr_start(sc->dev); 240 if (error == 0) 241 sc->open = true; 242 return (error); 243 } 244 245 static int 246 ietp_ev_close(struct evdev_dev *evdev) 247 { 248 struct ietp_softc *sc = evdev_get_softc(evdev); 249 int error; 250 251 error = hid_intr_stop(sc->dev); 252 if (error == 0) 253 sc->open = false; 254 return (error); 255 } 256 257 static int 258 ietp_probe(struct ietp_softc *sc) 259 { 260 if (hidbus_find_child(device_get_parent(sc->dev), 261 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD)) != NULL) { 262 DPRINTFN(5, "Ignore HID-compatible touchpad on %s\n", 263 device_get_nameunit(device_get_parent(sc->dev))); 264 return (ENXIO); 265 } 266 267 device_set_desc(sc->dev, "Elan Touchpad"); 268 269 return (BUS_PROBE_DEFAULT); 270 } 271 272 static int 273 ietp_attach(struct ietp_softc *sc) 274 { 275 const struct hid_device_info *hw = hid_get_device_info(sc->dev); 276 void *d_ptr; 277 hid_size_t d_len; 278 int32_t minor, major; 279 int error; 280 281 sc->report_id = sc->hi_precision ? 282 IETP_REPORT_ID_HI : IETP_REPORT_ID_LO; 283 sc->report_len = sc->hi_precision ? 284 IETP_REPORT_LEN_HI : IETP_REPORT_LEN_LO; 285 286 /* Try to detect 3-rd button by relative mouse TLC */ 287 if (!sc->is_clickpad) { 288 error = hid_get_report_descr(sc->dev, &d_ptr, &d_len); 289 if (error != 0) { 290 device_printf(sc->dev, "could not retrieve report " 291 "descriptor from device: %d\n", error); 292 return (ENXIO); 293 } 294 if (hidbus_locate(d_ptr, d_len, HID_USAGE2(HUP_BUTTON, 3), 295 hid_input, hidbus_get_index(sc->dev), 0, NULL, NULL, NULL, 296 NULL)) 297 sc->has_3buttons = true; 298 } 299 300 sc->evdev = evdev_alloc(); 301 evdev_set_name(sc->evdev, device_get_desc(sc->dev)); 302 evdev_set_phys(sc->evdev, device_get_nameunit(sc->dev)); 303 evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct, 304 hw->idVersion); 305 evdev_set_serial(sc->evdev, hw->serial); 306 evdev_set_methods(sc->evdev, sc, &ietp_evdev_methods); 307 evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT); 308 evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */ 309 310 evdev_support_event(sc->evdev, EV_SYN); 311 evdev_support_event(sc->evdev, EV_ABS); 312 evdev_support_event(sc->evdev, EV_KEY); 313 evdev_support_prop(sc->evdev, INPUT_PROP_POINTER); 314 evdev_support_key(sc->evdev, BTN_LEFT); 315 if (sc->is_clickpad) { 316 evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD); 317 } else { 318 evdev_support_key(sc->evdev, BTN_RIGHT); 319 if (sc->has_3buttons) 320 evdev_support_key(sc->evdev, BTN_MIDDLE); 321 } 322 323 major = IETP_FINGER_MAX_WIDTH * MAX(sc->trace_x, sc->trace_y); 324 minor = IETP_FINGER_MAX_WIDTH * MIN(sc->trace_x, sc->trace_y); 325 326 evdev_support_abs(sc->evdev, ABS_MT_SLOT, 327 0, IETP_MAX_FINGERS - 1, 0, 0, 0); 328 evdev_support_abs(sc->evdev, ABS_MT_TRACKING_ID, 329 -1, IETP_MAX_FINGERS - 1, 0, 0, 0); 330 evdev_support_abs(sc->evdev, ABS_MT_POSITION_X, 331 0, sc->max_x, 0, 0, sc->res_x); 332 evdev_support_abs(sc->evdev, ABS_MT_POSITION_Y, 333 0, sc->max_y, 0, 0, sc->res_y); 334 evdev_support_abs(sc->evdev, ABS_MT_PRESSURE, 335 0, IETP_MAX_PRESSURE, 0, 0, 0); 336 evdev_support_abs(sc->evdev, ABS_MT_ORIENTATION, 0, 1, 0, 0, 0); 337 evdev_support_abs(sc->evdev, ABS_MT_TOUCH_MAJOR, 0, major, 0, 0, 0); 338 evdev_support_abs(sc->evdev, ABS_MT_TOUCH_MINOR, 0, minor, 0, 0, 0); 339 evdev_support_abs(sc->evdev, ABS_DISTANCE, 0, 1, 0, 0, 0); 340 341 error = evdev_register(sc->evdev); 342 if (error != 0) { 343 ietp_detach(sc); 344 return (ENOMEM); 345 } 346 347 hidbus_set_intr(sc->dev, ietp_intr, sc); 348 349 device_printf(sc->dev, "[%d:%d], %s\n", sc->max_x, sc->max_y, 350 sc->is_clickpad ? "clickpad" : 351 sc->has_3buttons ? "3 buttons" : "2 buttons"); 352 353 return (0); 354 } 355 356 static int 357 ietp_detach(struct ietp_softc *sc) 358 { 359 evdev_free(sc->evdev); 360 361 return (0); 362 } 363 364 static void 365 ietp_intr(void *context, void *buf, hid_size_t len) 366 { 367 struct ietp_softc *sc = context; 368 union evdev_mt_slot slot_data; 369 uint8_t *report, *fdata; 370 int32_t finger; 371 int32_t x, y, w, h, wh; 372 373 /* we seem to get 0 length reports sometimes, ignore them */ 374 if (len == 0) 375 return; 376 if (len != sc->report_len) { 377 DPRINTF("wrong report length (%d vs %d expected)", len, sc->report_len); 378 return; 379 } 380 381 report = buf; 382 if (*report != sc->report_id) 383 return; 384 385 evdev_push_key(sc->evdev, BTN_LEFT, 386 report[IETP_TOUCH_INFO] & IETP_TOUCH_LMB); 387 evdev_push_key(sc->evdev, BTN_MIDDLE, 388 report[IETP_TOUCH_INFO] & IETP_TOUCH_MMB); 389 evdev_push_key(sc->evdev, BTN_RIGHT, 390 report[IETP_TOUCH_INFO] & IETP_TOUCH_RMB); 391 evdev_push_abs(sc->evdev, ABS_DISTANCE, 392 (report[IETP_HOVER_INFO] & 0x40) >> 6); 393 394 for (finger = 0, fdata = report + IETP_FINGER_DATA; 395 finger < IETP_MAX_FINGERS; 396 finger++, fdata += IETP_FINGER_DATA_LEN) { 397 if ((report[IETP_TOUCH_INFO] & (1 << (finger + 3))) != 0) { 398 if (sc->hi_precision) { 399 x = fdata[0] << 8 | fdata[1]; 400 y = fdata[2] << 8 | fdata[3]; 401 wh = report[IETP_WH_DATA + finger]; 402 } else { 403 x = (fdata[0] & 0xf0) << 4 | fdata[1]; 404 y = (fdata[0] & 0x0f) << 8 | fdata[2]; 405 wh = fdata[3]; 406 } 407 408 if (x > sc->max_x || y > sc->max_y) { 409 DPRINTF("[%d] x=%d y=%d over max (%d, %d)", 410 finger, x, y, sc->max_x, sc->max_y); 411 continue; 412 } 413 414 /* Reduce trace size to not treat large finger as palm */ 415 w = (wh & 0x0F) * (sc->trace_x - IETP_FWIDTH_REDUCE); 416 h = (wh >> 4) * (sc->trace_y - IETP_FWIDTH_REDUCE); 417 418 slot_data = (union evdev_mt_slot) { 419 .id = finger, 420 .x = x, 421 .y = sc->max_y - y, 422 .p = MIN((int32_t)fdata[4] + sc->pressure_base, 423 IETP_MAX_PRESSURE), 424 .ori = w > h ? 1 : 0, 425 .maj = MAX(w, h), 426 .min = MIN(w, h), 427 }; 428 evdev_mt_push_slot(sc->evdev, finger, &slot_data); 429 } else { 430 evdev_push_abs(sc->evdev, ABS_MT_SLOT, finger); 431 evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1); 432 } 433 } 434 435 evdev_sync(sc->evdev); 436 } 437 438 static int32_t 439 ietp_res2dpmm(uint8_t res, bool hi_precision) 440 { 441 int32_t dpi; 442 443 dpi = hi_precision ? 300 + res * 100 : 790 + res * 10; 444 445 return (dpi * 10 /254); 446 } 447 448 static void 449 ietp_iic_identify(driver_t *driver, device_t parent) 450 { 451 device_t iichid = device_get_parent(parent); 452 static const uint16_t reg = IETP_PATTERN; 453 uint16_t addr = iicbus_get_addr(iichid) << 1; 454 uint8_t resp[2]; 455 uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff }; 456 struct iic_msg msgs[2] = { 457 { addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd }, 458 { addr, IIC_M_RD, sizeof(resp), resp }, 459 }; 460 struct iic_rdwr_data ird = { msgs, nitems(msgs) }; 461 uint8_t pattern; 462 463 if (HIDBUS_LOOKUP_ID(parent, ietp_iic_devs) == NULL) 464 return; 465 466 if (device_get_devclass(iichid) != devclass_find("iichid")) 467 return; 468 469 DPRINTF("Read reg 0x%04x with size %zu\n", reg, sizeof(resp)); 470 471 if (hid_ioctl(parent, I2CRDWR, (uintptr_t)&ird) != 0) 472 return; 473 474 DPRINTF("Response: %*D\n", (int)size(resp), resp, " "); 475 476 pattern = (resp[0] == 0xFF && resp[1] == 0xFF) ? 0 : resp[1]; 477 if (pattern >= 0x02) 478 hid_set_report_descr(parent, ietp_dummy_rdesc_hi, 479 sizeof(ietp_dummy_rdesc_hi)); 480 else 481 hid_set_report_descr(parent, ietp_dummy_rdesc_lo, 482 sizeof(ietp_dummy_rdesc_lo)); 483 } 484 485 static int 486 ietp_iic_probe(device_t dev) 487 { 488 struct ietp_softc *sc = device_get_softc(dev); 489 device_t iichid; 490 int error; 491 492 error = HIDBUS_LOOKUP_DRIVER_INFO(dev, ietp_iic_devs); 493 if (error != 0) 494 return (error); 495 496 iichid = device_get_parent(device_get_parent(dev)); 497 if (device_get_devclass(iichid) != devclass_find("iichid")) 498 return (ENXIO); 499 500 sc->dev = dev; 501 502 return (ietp_probe(sc)); 503 } 504 505 static int 506 ietp_iic_attach(device_t dev) 507 { 508 struct ietp_softc *sc = device_get_softc(dev); 509 uint16_t buf, reg; 510 uint8_t *buf8; 511 uint8_t pattern; 512 513 buf8 = (uint8_t *)&buf; 514 515 if (ietp_iic_read_reg(dev, IETP_UNIQUEID, sizeof(buf), &buf) != 0) { 516 device_printf(sc->dev, "failed reading product ID\n"); 517 return (EIO); 518 } 519 sc->product_id = le16toh(buf); 520 521 if (ietp_iic_read_reg(dev, IETP_PATTERN, sizeof(buf), &buf) != 0) { 522 device_printf(sc->dev, "failed reading pattern\n"); 523 return (EIO); 524 } 525 pattern = buf == 0xFFFF ? 0 : buf8[1]; 526 sc->hi_precision = pattern >= 0x02; 527 528 reg = pattern >= 0x01 ? IETP_IC_TYPE : IETP_OSM_VERSION; 529 if (ietp_iic_read_reg(dev, reg, sizeof(buf), &buf) != 0) { 530 device_printf(sc->dev, "failed reading IC type\n"); 531 return (EIO); 532 } 533 sc->ic_type = pattern >= 0x01 ? be16toh(buf) : buf8[1]; 534 535 if (ietp_iic_read_reg(dev, IETP_NSM_VERSION, sizeof(buf), &buf) != 0) { 536 device_printf(sc->dev, "failed reading SM version\n"); 537 return (EIO); 538 } 539 sc->is_clickpad = (buf8[0] & 0x10) != 0; 540 541 if (ietp_iic_set_absolute_mode(dev, true) != 0) { 542 device_printf(sc->dev, "failed to set absolute mode\n"); 543 return (EIO); 544 } 545 546 if (ietp_iic_read_reg(dev, IETP_MAX_X_AXIS, sizeof(buf), &buf) != 0) { 547 device_printf(sc->dev, "failed reading max x\n"); 548 return (EIO); 549 } 550 sc->max_x = le16toh(buf); 551 552 if (ietp_iic_read_reg(dev, IETP_MAX_Y_AXIS, sizeof(buf), &buf) != 0) { 553 device_printf(sc->dev, "failed reading max y\n"); 554 return (EIO); 555 } 556 sc->max_y = le16toh(buf); 557 558 if (ietp_iic_read_reg(dev, IETP_TRACENUM, sizeof(buf), &buf) != 0) { 559 device_printf(sc->dev, "failed reading trace info\n"); 560 return (EIO); 561 } 562 sc->trace_x = sc->max_x / buf8[0]; 563 sc->trace_y = sc->max_y / buf8[1]; 564 565 if (ietp_iic_read_reg(dev, IETP_PRESSURE, sizeof(buf), &buf) != 0) { 566 device_printf(sc->dev, "failed reading pressure format\n"); 567 return (EIO); 568 } 569 sc->pressure_base = (buf8[0] & 0x10) ? 0 : IETP_PRESSURE_BASE; 570 571 if (ietp_iic_read_reg(dev, IETP_RESOLUTION, sizeof(buf), &buf) != 0) { 572 device_printf(sc->dev, "failed reading resolution\n"); 573 return (EIO); 574 } 575 /* Conversion from internal format to dot per mm */ 576 sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precision); 577 sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precision); 578 579 return (ietp_attach(sc)); 580 } 581 582 static int 583 ietp_iic_detach(device_t dev) 584 { 585 struct ietp_softc *sc = device_get_softc(dev); 586 587 if (ietp_iic_set_absolute_mode(dev, false) != 0) 588 device_printf(dev, "failed setting standard mode\n"); 589 590 return (ietp_detach(sc)); 591 } 592 593 static int 594 ietp_iic_resume(device_t dev) 595 { 596 if (ietp_iic_set_absolute_mode(dev, true) != 0) { 597 device_printf(dev, "reset when resuming failed: \n"); 598 return (EIO); 599 } 600 601 return (0); 602 } 603 604 static int 605 ietp_iic_set_absolute_mode(device_t dev, bool enable) 606 { 607 struct ietp_softc *sc = device_get_softc(dev); 608 static const struct { 609 uint16_t ic_type; 610 uint16_t product_id; 611 } special_fw[] = { 612 { 0x0E, 0x05 }, { 0x0E, 0x06 }, { 0x0E, 0x07 }, { 0x0E, 0x09 }, 613 { 0x0E, 0x13 }, { 0x08, 0x26 }, 614 }; 615 uint16_t val; 616 int i, error; 617 bool require_wakeup; 618 619 error = 0; 620 621 /* 622 * Some ASUS touchpads need to be powered on to enter absolute mode. 623 */ 624 require_wakeup = false; 625 if (!sc->open) { 626 for (i = 0; i < nitems(special_fw); i++) { 627 if (sc->ic_type == special_fw[i].ic_type && 628 sc->product_id == special_fw[i].product_id) { 629 require_wakeup = true; 630 break; 631 } 632 } 633 } 634 635 if (require_wakeup && hid_intr_start(dev) != 0) { 636 device_printf(dev, "failed writing poweron command\n"); 637 return (EIO); 638 } 639 640 val = enable ? IETP_CTRL_ABSOLUTE : IETP_CTRL_STANDARD; 641 if (ietp_iic_write_reg(dev, IETP_CONTROL, val) != 0) { 642 device_printf(dev, "failed setting absolute mode\n"); 643 error = EIO; 644 } 645 646 if (require_wakeup && hid_intr_stop(dev) != 0) { 647 device_printf(dev, "failed writing poweroff command\n"); 648 error = EIO; 649 } 650 651 return (error); 652 } 653 654 static int 655 ietp_iic_read_reg(device_t dev, uint16_t reg, size_t len, void *val) 656 { 657 device_t iichid = device_get_parent(device_get_parent(dev)); 658 uint16_t addr = iicbus_get_addr(iichid) << 1; 659 uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff }; 660 struct iic_msg msgs[2] = { 661 { addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd }, 662 { addr, IIC_M_RD, len, val }, 663 }; 664 struct iic_rdwr_data ird = { msgs, nitems(msgs) }; 665 int error; 666 667 DPRINTF("Read reg 0x%04x with size %zu\n", reg, len); 668 669 error = hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird); 670 if (error != 0) 671 return (error); 672 673 DPRINTF("Response: %*D\n", (int)len, val, " "); 674 675 return (0); 676 } 677 678 static int 679 ietp_iic_write_reg(device_t dev, uint16_t reg, uint16_t val) 680 { 681 device_t iichid = device_get_parent(device_get_parent(dev)); 682 uint16_t addr = iicbus_get_addr(iichid) << 1; 683 uint8_t cmd[4] = { reg & 0xff, (reg >> 8) & 0xff, 684 val & 0xff, (val >> 8) & 0xff }; 685 struct iic_msg msgs[1] = { 686 { addr, IIC_M_WR, sizeof(cmd), cmd }, 687 }; 688 struct iic_rdwr_data ird = { msgs, nitems(msgs) }; 689 690 DPRINTF("Write reg 0x%04x with value 0x%04x\n", reg, val); 691 692 return (hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird)); 693 } 694 695 static device_method_t ietp_methods[] = { 696 DEVMETHOD(device_identify, ietp_iic_identify), 697 DEVMETHOD(device_probe, ietp_iic_probe), 698 DEVMETHOD(device_attach, ietp_iic_attach), 699 DEVMETHOD(device_detach, ietp_iic_detach), 700 DEVMETHOD(device_resume, ietp_iic_resume), 701 DEVMETHOD_END 702 }; 703 704 static driver_t ietp_driver = { 705 .name = "ietp", 706 .methods = ietp_methods, 707 .size = sizeof(struct ietp_softc), 708 }; 709 710 DRIVER_MODULE(ietp, hidbus, ietp_driver, NULL, NULL); 711 MODULE_DEPEND(ietp, hidbus, 1, 1, 1); 712 MODULE_DEPEND(ietp, hid, 1, 1, 1); 713 MODULE_DEPEND(ietp, evdev, 1, 1, 1); 714 MODULE_VERSION(ietp, 1); 715 HID_PNP_INFO(ietp_iic_devs); 716