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
ietp_ev_open(struct evdev_dev * evdev)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
ietp_ev_close(struct evdev_dev * evdev)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
ietp_probe(struct ietp_softc * sc)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
ietp_attach(struct ietp_softc * sc)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
ietp_detach(struct ietp_softc * sc)357 ietp_detach(struct ietp_softc *sc)
358 {
359 evdev_free(sc->evdev);
360
361 return (0);
362 }
363
364 static void
ietp_intr(void * context,void * buf,hid_size_t len)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
ietp_res2dpmm(uint8_t res,bool hi_precision)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
ietp_iic_identify(driver_t * driver,device_t parent)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;
454 uint8_t resp[2];
455 uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff };
456 struct iic_msg msgs[2];
457 struct iic_rdwr_data ird = { msgs, nitems(msgs) };
458 uint8_t pattern;
459
460 if (HIDBUS_LOOKUP_ID(parent, ietp_iic_devs) == NULL)
461 return;
462
463 if (device_get_devclass(iichid) != devclass_find("iichid"))
464 return;
465
466 addr = iicbus_get_addr(iichid) << 1;
467 msgs[0] = (struct iic_msg){ addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd };
468 msgs[1] = (struct iic_msg){ addr, IIC_M_RD, sizeof(resp), resp };
469
470 DPRINTF("Read reg 0x%04x with size %zu\n", reg, sizeof(resp));
471
472 if (hid_ioctl(parent, I2CRDWR, (uintptr_t)&ird) != 0)
473 return;
474
475 DPRINTF("Response: %*D\n", (int)size(resp), resp, " ");
476
477 pattern = (resp[0] == 0xFF && resp[1] == 0xFF) ? 0 : resp[1];
478 if (pattern >= 0x02)
479 hid_set_report_descr(parent, ietp_dummy_rdesc_hi,
480 sizeof(ietp_dummy_rdesc_hi));
481 else
482 hid_set_report_descr(parent, ietp_dummy_rdesc_lo,
483 sizeof(ietp_dummy_rdesc_lo));
484 }
485
486 static int
ietp_iic_probe(device_t dev)487 ietp_iic_probe(device_t dev)
488 {
489 struct ietp_softc *sc = device_get_softc(dev);
490 device_t iichid;
491 int error;
492
493 error = HIDBUS_LOOKUP_DRIVER_INFO(dev, ietp_iic_devs);
494 if (error != 0)
495 return (error);
496
497 iichid = device_get_parent(device_get_parent(dev));
498 if (device_get_devclass(iichid) != devclass_find("iichid"))
499 return (ENXIO);
500
501 sc->dev = dev;
502
503 return (ietp_probe(sc));
504 }
505
506 static int
ietp_iic_attach(device_t dev)507 ietp_iic_attach(device_t dev)
508 {
509 struct ietp_softc *sc = device_get_softc(dev);
510 uint16_t buf, reg;
511 uint8_t *buf8;
512 uint8_t pattern;
513
514 buf8 = (uint8_t *)&buf;
515
516 if (ietp_iic_read_reg(dev, IETP_UNIQUEID, sizeof(buf), &buf) != 0) {
517 device_printf(sc->dev, "failed reading product ID\n");
518 return (EIO);
519 }
520 sc->product_id = le16toh(buf);
521
522 if (ietp_iic_read_reg(dev, IETP_PATTERN, sizeof(buf), &buf) != 0) {
523 device_printf(sc->dev, "failed reading pattern\n");
524 return (EIO);
525 }
526 pattern = buf == 0xFFFF ? 0 : buf8[1];
527 sc->hi_precision = pattern >= 0x02;
528
529 reg = pattern >= 0x01 ? IETP_IC_TYPE : IETP_OSM_VERSION;
530 if (ietp_iic_read_reg(dev, reg, sizeof(buf), &buf) != 0) {
531 device_printf(sc->dev, "failed reading IC type\n");
532 return (EIO);
533 }
534 sc->ic_type = pattern >= 0x01 ? be16toh(buf) : buf8[1];
535
536 if (ietp_iic_read_reg(dev, IETP_NSM_VERSION, sizeof(buf), &buf) != 0) {
537 device_printf(sc->dev, "failed reading SM version\n");
538 return (EIO);
539 }
540 sc->is_clickpad = (buf8[0] & 0x10) != 0;
541
542 if (ietp_iic_set_absolute_mode(dev, true) != 0) {
543 device_printf(sc->dev, "failed to set absolute mode\n");
544 return (EIO);
545 }
546
547 if (ietp_iic_read_reg(dev, IETP_MAX_X_AXIS, sizeof(buf), &buf) != 0) {
548 device_printf(sc->dev, "failed reading max x\n");
549 return (EIO);
550 }
551 sc->max_x = le16toh(buf);
552
553 if (ietp_iic_read_reg(dev, IETP_MAX_Y_AXIS, sizeof(buf), &buf) != 0) {
554 device_printf(sc->dev, "failed reading max y\n");
555 return (EIO);
556 }
557 sc->max_y = le16toh(buf);
558
559 if (ietp_iic_read_reg(dev, IETP_TRACENUM, sizeof(buf), &buf) != 0) {
560 device_printf(sc->dev, "failed reading trace info\n");
561 return (EIO);
562 }
563 sc->trace_x = sc->max_x / buf8[0];
564 sc->trace_y = sc->max_y / buf8[1];
565
566 if (ietp_iic_read_reg(dev, IETP_PRESSURE, sizeof(buf), &buf) != 0) {
567 device_printf(sc->dev, "failed reading pressure format\n");
568 return (EIO);
569 }
570 sc->pressure_base = (buf8[0] & 0x10) ? 0 : IETP_PRESSURE_BASE;
571
572 if (ietp_iic_read_reg(dev, IETP_RESOLUTION, sizeof(buf), &buf) != 0) {
573 device_printf(sc->dev, "failed reading resolution\n");
574 return (EIO);
575 }
576 /* Conversion from internal format to dot per mm */
577 sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precision);
578 sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precision);
579
580 return (ietp_attach(sc));
581 }
582
583 static int
ietp_iic_detach(device_t dev)584 ietp_iic_detach(device_t dev)
585 {
586 struct ietp_softc *sc = device_get_softc(dev);
587
588 if (ietp_iic_set_absolute_mode(dev, false) != 0)
589 device_printf(dev, "failed setting standard mode\n");
590
591 return (ietp_detach(sc));
592 }
593
594 static int
ietp_iic_resume(device_t dev)595 ietp_iic_resume(device_t dev)
596 {
597 if (ietp_iic_set_absolute_mode(dev, true) != 0) {
598 device_printf(dev, "reset when resuming failed: \n");
599 return (EIO);
600 }
601
602 return (0);
603 }
604
605 static int
ietp_iic_set_absolute_mode(device_t dev,bool enable)606 ietp_iic_set_absolute_mode(device_t dev, bool enable)
607 {
608 struct ietp_softc *sc = device_get_softc(dev);
609 static const struct {
610 uint16_t ic_type;
611 uint16_t product_id;
612 } special_fw[] = {
613 { 0x0E, 0x05 }, { 0x0E, 0x06 }, { 0x0E, 0x07 }, { 0x0E, 0x09 },
614 { 0x0E, 0x13 }, { 0x08, 0x26 },
615 };
616 uint16_t val;
617 int i, error;
618 bool require_wakeup;
619
620 error = 0;
621
622 /*
623 * Some ASUS touchpads need to be powered on to enter absolute mode.
624 */
625 require_wakeup = false;
626 if (!sc->open) {
627 for (i = 0; i < nitems(special_fw); i++) {
628 if (sc->ic_type == special_fw[i].ic_type &&
629 sc->product_id == special_fw[i].product_id) {
630 require_wakeup = true;
631 break;
632 }
633 }
634 }
635
636 if (require_wakeup && hid_intr_start(dev) != 0) {
637 device_printf(dev, "failed writing poweron command\n");
638 return (EIO);
639 }
640
641 val = enable ? IETP_CTRL_ABSOLUTE : IETP_CTRL_STANDARD;
642 if (ietp_iic_write_reg(dev, IETP_CONTROL, val) != 0) {
643 device_printf(dev, "failed setting absolute mode\n");
644 error = EIO;
645 }
646
647 if (require_wakeup && hid_intr_stop(dev) != 0) {
648 device_printf(dev, "failed writing poweroff command\n");
649 error = EIO;
650 }
651
652 return (error);
653 }
654
655 static int
ietp_iic_read_reg(device_t dev,uint16_t reg,size_t len,void * val)656 ietp_iic_read_reg(device_t dev, uint16_t reg, size_t len, void *val)
657 {
658 device_t iichid = device_get_parent(device_get_parent(dev));
659 uint16_t addr = iicbus_get_addr(iichid) << 1;
660 uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff };
661 struct iic_msg msgs[2] = {
662 { addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd },
663 { addr, IIC_M_RD, len, val },
664 };
665 struct iic_rdwr_data ird = { msgs, nitems(msgs) };
666 int error;
667
668 DPRINTF("Read reg 0x%04x with size %zu\n", reg, len);
669
670 error = hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird);
671 if (error != 0)
672 return (error);
673
674 DPRINTF("Response: %*D\n", (int)len, val, " ");
675
676 return (0);
677 }
678
679 static int
ietp_iic_write_reg(device_t dev,uint16_t reg,uint16_t val)680 ietp_iic_write_reg(device_t dev, uint16_t reg, uint16_t val)
681 {
682 device_t iichid = device_get_parent(device_get_parent(dev));
683 uint16_t addr = iicbus_get_addr(iichid) << 1;
684 uint8_t cmd[4] = { reg & 0xff, (reg >> 8) & 0xff,
685 val & 0xff, (val >> 8) & 0xff };
686 struct iic_msg msgs[1] = {
687 { addr, IIC_M_WR, sizeof(cmd), cmd },
688 };
689 struct iic_rdwr_data ird = { msgs, nitems(msgs) };
690
691 DPRINTF("Write reg 0x%04x with value 0x%04x\n", reg, val);
692
693 return (hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird));
694 }
695
696 static device_method_t ietp_methods[] = {
697 DEVMETHOD(device_identify, ietp_iic_identify),
698 DEVMETHOD(device_probe, ietp_iic_probe),
699 DEVMETHOD(device_attach, ietp_iic_attach),
700 DEVMETHOD(device_detach, ietp_iic_detach),
701 DEVMETHOD(device_resume, ietp_iic_resume),
702 DEVMETHOD_END
703 };
704
705 static driver_t ietp_driver = {
706 .name = "ietp",
707 .methods = ietp_methods,
708 .size = sizeof(struct ietp_softc),
709 };
710
711 DRIVER_MODULE(ietp, hidbus, ietp_driver, NULL, NULL);
712 MODULE_DEPEND(ietp, hidbus, 1, 1, 1);
713 MODULE_DEPEND(ietp, hid, 1, 1, 1);
714 MODULE_DEPEND(ietp, evdev, 1, 1, 1);
715 MODULE_VERSION(ietp, 1);
716 HID_PNP_INFO(ietp_iic_devs);
717