xref: /freebsd/sys/dev/hid/ietp.c (revision cb2887746f8b9dd4ad6b1e757cdc053a08b25a2e)
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[] = {
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 	0x95, IETP_REPORT_LEN_LO,	/*   Report Count (IETP_REPORT_LEN_LO)	*/
208 	0x75, 0x08,			/*   Report Size (8)			*/
209 	0x81, 0x02,			/*   Input (Data,Var,Abs)		*/
210 	0xC0,				/* End Collection			*/
211 };
212 
213 static const struct evdev_methods ietp_evdev_methods = {
214 	.ev_open = &ietp_ev_open,
215 	.ev_close = &ietp_ev_close,
216 };
217 
218 static int
219 ietp_ev_open(struct evdev_dev *evdev)
220 {
221 	struct ietp_softc *sc = evdev_get_softc(evdev);
222 	int error;
223 
224 	error = hid_intr_start(sc->dev);
225 	if (error == 0)
226 		sc->open = true;
227 	return (error);
228 }
229 
230 static int
231 ietp_ev_close(struct evdev_dev *evdev)
232 {
233 	struct ietp_softc *sc = evdev_get_softc(evdev);
234 	int error;
235 
236 	error = hid_intr_stop(sc->dev);
237 	if (error == 0)
238 		sc->open = false;
239 	return (error);
240 }
241 
242 static int
243 ietp_probe(struct ietp_softc *sc)
244 {
245 	if (hidbus_find_child(device_get_parent(sc->dev),
246 	    HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD)) != NULL) {
247 		DPRINTFN(5, "Ignore HID-compatible touchpad on %s\n",
248 		    device_get_nameunit(device_get_parent(sc->dev)));
249 		return (ENXIO);
250 	}
251 
252 	device_set_desc(sc->dev, "Elan Touchpad");
253 
254 	return (BUS_PROBE_DEFAULT);
255 }
256 
257 static int
258 ietp_attach(struct ietp_softc *sc)
259 {
260 	const struct hid_device_info *hw = hid_get_device_info(sc->dev);
261 	void *d_ptr;
262 	hid_size_t d_len;
263 	int32_t minor, major;
264 	int error;
265 
266 	sc->report_id = sc->hi_precision ?
267 	    IETP_REPORT_ID_HI : IETP_REPORT_ID_LO;
268 	sc->report_len = sc->hi_precision ?
269 	    IETP_REPORT_LEN_HI : IETP_REPORT_LEN_LO;
270 
271 	/* Try to detect 3-rd button by relative mouse TLC */
272 	if (!sc->is_clickpad) {
273 		error = hid_get_report_descr(sc->dev, &d_ptr, &d_len);
274 		if (error != 0) {
275 			device_printf(sc->dev, "could not retrieve report "
276 			    "descriptor from device: %d\n", error);
277 			return (ENXIO);
278 		}
279 		if (hidbus_locate(d_ptr, d_len, HID_USAGE2(HUP_BUTTON, 3),
280 		    hid_input, hidbus_get_index(sc->dev), 0, NULL, NULL, NULL,
281 		    NULL))
282 			sc->has_3buttons = true;
283 	}
284 
285 	sc->evdev = evdev_alloc();
286 	evdev_set_name(sc->evdev, device_get_desc(sc->dev));
287 	evdev_set_phys(sc->evdev, device_get_nameunit(sc->dev));
288 	evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct,
289 	    hw->idVersion);
290 	evdev_set_serial(sc->evdev, hw->serial);
291 	evdev_set_methods(sc->evdev, sc, &ietp_evdev_methods);
292 	evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT);
293 	evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
294 
295 	evdev_support_event(sc->evdev, EV_SYN);
296 	evdev_support_event(sc->evdev, EV_ABS);
297 	evdev_support_event(sc->evdev, EV_KEY);
298 	evdev_support_prop(sc->evdev, INPUT_PROP_POINTER);
299 	evdev_support_key(sc->evdev, BTN_LEFT);
300 	if (sc->is_clickpad) {
301 		evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD);
302 	} else {
303 		evdev_support_key(sc->evdev, BTN_RIGHT);
304 		if (sc->has_3buttons)
305 			evdev_support_key(sc->evdev, BTN_MIDDLE);
306 	}
307 
308 	major = IETP_FINGER_MAX_WIDTH * MAX(sc->trace_x, sc->trace_y);
309 	minor = IETP_FINGER_MAX_WIDTH * MIN(sc->trace_x, sc->trace_y);
310 
311 	evdev_support_abs(sc->evdev, ABS_MT_SLOT,
312 	    0, IETP_MAX_FINGERS - 1, 0, 0, 0);
313 	evdev_support_abs(sc->evdev, ABS_MT_TRACKING_ID,
314 	    -1, IETP_MAX_FINGERS - 1, 0, 0, 0);
315 	evdev_support_abs(sc->evdev, ABS_MT_POSITION_X,
316 	    0, sc->max_x, 0, 0, sc->res_x);
317 	evdev_support_abs(sc->evdev, ABS_MT_POSITION_Y,
318 	    0, sc->max_y, 0, 0, sc->res_y);
319 	evdev_support_abs(sc->evdev, ABS_MT_PRESSURE,
320 	    0, IETP_MAX_PRESSURE, 0, 0, 0);
321 	evdev_support_abs(sc->evdev, ABS_MT_ORIENTATION, 0, 1, 0, 0, 0);
322 	evdev_support_abs(sc->evdev, ABS_MT_TOUCH_MAJOR, 0, major, 0, 0, 0);
323 	evdev_support_abs(sc->evdev, ABS_MT_TOUCH_MINOR, 0, minor, 0, 0, 0);
324 	evdev_support_abs(sc->evdev, ABS_DISTANCE, 0, 1, 0, 0, 0);
325 
326 	error = evdev_register(sc->evdev);
327 	if (error != 0) {
328 		ietp_detach(sc);
329 		return (ENOMEM);
330 	}
331 
332 	hidbus_set_intr(sc->dev, ietp_intr, sc);
333 
334 	device_printf(sc->dev, "[%d:%d], %s\n", sc->max_x, sc->max_y,
335 	    sc->is_clickpad ? "clickpad" :
336 	    sc->has_3buttons ? "3 buttons" : "2 buttons");
337 
338 	return (0);
339 }
340 
341 static int
342 ietp_detach(struct ietp_softc *sc)
343 {
344 	evdev_free(sc->evdev);
345 
346 	return (0);
347 }
348 
349 static void
350 ietp_intr(void *context, void *buf, hid_size_t len)
351 {
352 	struct ietp_softc *sc = context;
353 	union evdev_mt_slot slot_data;
354 	uint8_t *report, *fdata;
355 	int32_t finger;
356 	int32_t x, y, w, h, wh;
357 
358 	/* we seem to get 0 length reports sometimes, ignore them */
359 	if (len == 0)
360 		return;
361 	if (len != sc->report_len) {
362 		DPRINTF("wrong report length (%d vs %d expected)", len, sc->report_len);
363 		return;
364 	}
365 
366 	report = buf;
367 	if (*report != sc->report_id)
368 		return;
369 
370 	evdev_push_key(sc->evdev, BTN_LEFT,
371 	    report[IETP_TOUCH_INFO] & IETP_TOUCH_LMB);
372 	evdev_push_key(sc->evdev, BTN_MIDDLE,
373 	    report[IETP_TOUCH_INFO] & IETP_TOUCH_MMB);
374 	evdev_push_key(sc->evdev, BTN_RIGHT,
375 	    report[IETP_TOUCH_INFO] & IETP_TOUCH_RMB);
376 	evdev_push_abs(sc->evdev, ABS_DISTANCE,
377 	    (report[IETP_HOVER_INFO] & 0x40) >> 6);
378 
379 	for (finger = 0, fdata = report + IETP_FINGER_DATA;
380 	     finger < IETP_MAX_FINGERS;
381 	     finger++, fdata += IETP_FINGER_DATA_LEN) {
382 		if ((report[IETP_TOUCH_INFO] & (1 << (finger + 3))) != 0) {
383 			if (sc->hi_precision) {
384 				x = fdata[0] << 8 | fdata[1];
385 				y = fdata[2] << 8 | fdata[3];
386 				wh = report[IETP_WH_DATA + finger];
387 			} else {
388 				x = (fdata[0] & 0xf0) << 4 | fdata[1];
389 				y = (fdata[0] & 0x0f) << 8 | fdata[2];
390 				wh = fdata[3];
391 			}
392 
393 			if (x > sc->max_x || y > sc->max_y) {
394 				DPRINTF("[%d] x=%d y=%d over max (%d, %d)",
395 				    finger, x, y, sc->max_x, sc->max_y);
396 				continue;
397 			}
398 
399 			/* Reduce trace size to not treat large finger as palm */
400 			w = (wh & 0x0F) * (sc->trace_x - IETP_FWIDTH_REDUCE);
401 			h = (wh >> 4) * (sc->trace_y - IETP_FWIDTH_REDUCE);
402 
403 			slot_data = (union evdev_mt_slot) {
404 				.id = finger,
405 				.x = x,
406 				.y = sc->max_y - y,
407 				.p = MIN((int32_t)fdata[4] + sc->pressure_base,
408 				    IETP_MAX_PRESSURE),
409 				.ori = w > h ? 1 : 0,
410 				.maj = MAX(w, h),
411 				.min = MIN(w, h),
412 			};
413 			evdev_mt_push_slot(sc->evdev, finger, &slot_data);
414 		} else {
415 			evdev_push_abs(sc->evdev, ABS_MT_SLOT, finger);
416 			evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1);
417 		}
418 	}
419 
420 	evdev_sync(sc->evdev);
421 }
422 
423 static int32_t
424 ietp_res2dpmm(uint8_t res, bool hi_precision)
425 {
426 	int32_t dpi;
427 
428 	dpi = hi_precision ? 300 + res * 100 : 790 + res * 10;
429 
430 	return (dpi * 10 /254);
431 }
432 
433 static void
434 ietp_iic_identify(driver_t *driver, device_t parent)
435 {
436 	void *d_ptr;
437 	hid_size_t d_len;
438 	int isize;
439 	uint8_t iid;
440 
441 	if (HIDBUS_LOOKUP_ID(parent, ietp_iic_devs) == NULL)
442 		return;
443 	if (hid_get_report_descr(parent, &d_ptr, &d_len) != 0)
444 		return;
445 
446 	/*
447 	 * Some Elantech trackpads have a mangled HID report descriptor, which
448 	 * reads as having an incorrect input size (i.e. < IETP_REPORT_LEN_LO).
449 	 * If the input size is incorrect, load a dummy report descriptor.
450 	 */
451 
452 	isize = hid_report_size_max(d_ptr, d_len, hid_input, &iid);
453 	if (isize >= IETP_REPORT_LEN_LO)
454 		return;
455 
456 	hid_set_report_descr(parent, ietp_dummy_rdesc,
457 	    sizeof(ietp_dummy_rdesc));
458 }
459 
460 static int
461 ietp_iic_probe(device_t dev)
462 {
463 	struct ietp_softc *sc = device_get_softc(dev);
464 	device_t iichid;
465 	int error;
466 
467 	error = HIDBUS_LOOKUP_DRIVER_INFO(dev, ietp_iic_devs);
468 	if (error != 0)
469 		return (error);
470 
471 	iichid = device_get_parent(device_get_parent(dev));
472 	if (device_get_devclass(iichid) != devclass_find("iichid"))
473 		return (ENXIO);
474 
475 	sc->dev = dev;
476 
477 	return (ietp_probe(sc));
478 }
479 
480 static int
481 ietp_iic_attach(device_t dev)
482 {
483 	struct ietp_softc *sc = device_get_softc(dev);
484 	uint16_t buf, reg;
485 	uint8_t *buf8;
486 	uint8_t pattern;
487 
488 	buf8 = (uint8_t *)&buf;
489 
490 	if (ietp_iic_read_reg(dev, IETP_UNIQUEID, sizeof(buf), &buf) != 0) {
491 		device_printf(sc->dev, "failed reading product ID\n");
492 		return (EIO);
493 	}
494 	sc->product_id = le16toh(buf);
495 
496 	if (ietp_iic_read_reg(dev, IETP_PATTERN, sizeof(buf), &buf) != 0) {
497 		device_printf(sc->dev, "failed reading pattern\n");
498 		return (EIO);
499 	}
500 	pattern = buf == 0xFFFF ? 0 : buf8[1];
501 	sc->hi_precision = pattern >= 0x02;
502 
503 	reg = pattern >= 0x01 ? IETP_IC_TYPE : IETP_OSM_VERSION;
504 	if (ietp_iic_read_reg(dev, reg, sizeof(buf), &buf) != 0) {
505 		device_printf(sc->dev, "failed reading IC type\n");
506 		return (EIO);
507 	}
508 	sc->ic_type = pattern >= 0x01 ? be16toh(buf) : buf8[1];
509 
510 	if (ietp_iic_read_reg(dev, IETP_NSM_VERSION, sizeof(buf), &buf) != 0) {
511 		device_printf(sc->dev, "failed reading SM version\n");
512 		return (EIO);
513 	}
514 	sc->is_clickpad = (buf8[0] & 0x10) != 0;
515 
516 	if (ietp_iic_set_absolute_mode(dev, true) != 0) {
517 		device_printf(sc->dev, "failed to set absolute mode\n");
518 		return (EIO);
519 	}
520 
521 	if (ietp_iic_read_reg(dev, IETP_MAX_X_AXIS, sizeof(buf), &buf) != 0) {
522 		device_printf(sc->dev, "failed reading max x\n");
523 		return (EIO);
524 	}
525 	sc->max_x = le16toh(buf);
526 
527 	if (ietp_iic_read_reg(dev, IETP_MAX_Y_AXIS, sizeof(buf), &buf) != 0) {
528 		device_printf(sc->dev, "failed reading max y\n");
529 		return (EIO);
530 	}
531 	sc->max_y = le16toh(buf);
532 
533 	if (ietp_iic_read_reg(dev, IETP_TRACENUM, sizeof(buf), &buf) != 0) {
534 		device_printf(sc->dev, "failed reading trace info\n");
535 		return (EIO);
536 	}
537 	sc->trace_x = sc->max_x / buf8[0];
538 	sc->trace_y = sc->max_y / buf8[1];
539 
540 	if (ietp_iic_read_reg(dev, IETP_PRESSURE, sizeof(buf), &buf) != 0) {
541 		device_printf(sc->dev, "failed reading pressure format\n");
542 		return (EIO);
543 	}
544 	sc->pressure_base = (buf8[0] & 0x10) ? 0 : IETP_PRESSURE_BASE;
545 
546 	if (ietp_iic_read_reg(dev, IETP_RESOLUTION, sizeof(buf), &buf)  != 0) {
547 		device_printf(sc->dev, "failed reading resolution\n");
548 		return (EIO);
549 	}
550 	/* Conversion from internal format to dot per mm */
551 	sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precision);
552 	sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precision);
553 
554 	return (ietp_attach(sc));
555 }
556 
557 static int
558 ietp_iic_detach(device_t dev)
559 {
560 	struct ietp_softc *sc = device_get_softc(dev);
561 
562 	if (ietp_iic_set_absolute_mode(dev, false) != 0)
563 		device_printf(dev, "failed setting standard mode\n");
564 
565 	return (ietp_detach(sc));
566 }
567 
568 static int
569 ietp_iic_resume(device_t dev)
570 {
571 	if (ietp_iic_set_absolute_mode(dev, true) != 0) {
572 		device_printf(dev, "reset when resuming failed: \n");
573 		return (EIO);
574 	}
575 
576 	return (0);
577 }
578 
579 static int
580 ietp_iic_set_absolute_mode(device_t dev, bool enable)
581 {
582 	struct ietp_softc *sc = device_get_softc(dev);
583 	static const struct {
584 		uint16_t	ic_type;
585 		uint16_t	product_id;
586 	} special_fw[] = {
587 	    { 0x0E, 0x05 }, { 0x0E, 0x06 }, { 0x0E, 0x07 }, { 0x0E, 0x09 },
588 	    { 0x0E, 0x13 }, { 0x08, 0x26 },
589 	};
590 	uint16_t val;
591 	int i, error;
592 	bool require_wakeup;
593 
594 	error = 0;
595 
596 	/*
597 	 * Some ASUS touchpads need to be powered on to enter absolute mode.
598 	 */
599 	require_wakeup = false;
600 	if (!sc->open) {
601 		for (i = 0; i < nitems(special_fw); i++) {
602 			if (sc->ic_type == special_fw[i].ic_type &&
603 			    sc->product_id == special_fw[i].product_id) {
604 				require_wakeup = true;
605 				break;
606 			}
607 		}
608 	}
609 
610 	if (require_wakeup && hid_intr_start(dev) != 0) {
611 		device_printf(dev, "failed writing poweron command\n");
612 		return (EIO);
613 	}
614 
615 	val = enable ? IETP_CTRL_ABSOLUTE : IETP_CTRL_STANDARD;
616 	if (ietp_iic_write_reg(dev, IETP_CONTROL, val) != 0) {
617 		device_printf(dev, "failed setting absolute mode\n");
618 		error = EIO;
619 	}
620 
621 	if (require_wakeup && hid_intr_stop(dev) != 0) {
622 		device_printf(dev, "failed writing poweroff command\n");
623 		error = EIO;
624 	}
625 
626 	return (error);
627 }
628 
629 static int
630 ietp_iic_read_reg(device_t dev, uint16_t reg, size_t len, void *val)
631 {
632 	device_t iichid = device_get_parent(device_get_parent(dev));
633 	uint16_t addr = iicbus_get_addr(iichid) << 1;
634 	uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff };
635 	struct iic_msg msgs[2] = {
636 	    { addr, IIC_M_WR | IIC_M_NOSTOP,  sizeof(cmd), cmd },
637 	    { addr, IIC_M_RD, len, val },
638 	};
639 	struct iic_rdwr_data ird = { msgs, nitems(msgs) };
640 	int error;
641 
642 	DPRINTF("Read reg 0x%04x with size %zu\n", reg, len);
643 
644 	error = hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird);
645 	if (error != 0)
646 		return (error);
647 
648 	DPRINTF("Response: %*D\n", (int)len, val, " ");
649 
650 	return (0);
651 }
652 
653 static int
654 ietp_iic_write_reg(device_t dev, uint16_t reg, uint16_t val)
655 {
656 	device_t iichid = device_get_parent(device_get_parent(dev));
657 	uint16_t addr = iicbus_get_addr(iichid) << 1;
658 	uint8_t cmd[4] = { reg & 0xff, (reg >> 8) & 0xff,
659 			   val & 0xff, (val >> 8) & 0xff };
660 	struct iic_msg msgs[1] = {
661 	    { addr, IIC_M_WR, sizeof(cmd), cmd },
662 	};
663 	struct iic_rdwr_data ird = { msgs, nitems(msgs) };
664 
665 	DPRINTF("Write reg 0x%04x with value 0x%04x\n", reg, val);
666 
667 	return (hid_ioctl(dev, I2CRDWR, (uintptr_t)&ird));
668 }
669 
670 static device_method_t ietp_methods[] = {
671 	DEVMETHOD(device_identify,	ietp_iic_identify),
672 	DEVMETHOD(device_probe,		ietp_iic_probe),
673 	DEVMETHOD(device_attach,	ietp_iic_attach),
674 	DEVMETHOD(device_detach,	ietp_iic_detach),
675 	DEVMETHOD(device_resume,	ietp_iic_resume),
676 	DEVMETHOD_END
677 };
678 
679 static driver_t ietp_driver = {
680 	.name = "ietp",
681 	.methods = ietp_methods,
682 	.size = sizeof(struct ietp_softc),
683 };
684 
685 DRIVER_MODULE(ietp, hidbus, ietp_driver, NULL, NULL);
686 MODULE_DEPEND(ietp, hidbus, 1, 1, 1);
687 MODULE_DEPEND(ietp, hid, 1, 1, 1);
688 MODULE_DEPEND(ietp, evdev, 1, 1, 1);
689 MODULE_VERSION(ietp, 1);
690 HID_PNP_INFO(ietp_iic_devs);
691