xref: /openbsd/sys/dev/i2c/ietp.c (revision 07e9317c)
1 /* $OpenBSD: ietp.c,v 1.3 2024/08/18 03:25:04 deraadt Exp $ */
2 /*
3  * Elan I2C Touchpad driver
4  *
5  * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
6  * Copyright (c) 2020, 2022 Vladimir Kondratyev <wulf@FreeBSD.org>
7  * Copyright (c) 2023 vladimir serbinenko <phcoder@gmail.com>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /* Protocol documentation:
23  * https://lkml.indiana.edu/hypermail/linux/kernel/1205.0/02551.html
24  * Based on FreeBSD ietp driver.
25  */
26 
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/malloc.h>
31 #include <sys/stdint.h>
32 
33 #include <dev/i2c/i2cvar.h>
34 #include <dev/i2c/ietp.h>
35 
36 #include <dev/wscons/wsconsio.h>
37 #include <dev/wscons/wsmousevar.h>
38 
39 /* #define IETP_DEBUG */
40 
41 #ifdef IETP_DEBUG
42 #define DPRINTF(x) printf x
43 #else
44 #define DPRINTF(x)
45 #endif
46 
47 enum {
48 	I2C_HID_CMD_DESCR	= 0x0,
49 	I2C_HID_CMD_RESET	= 0x1,
50 	I2C_HID_CMD_SET_POWER	= 0x8,
51 };
52 
53 #define I2C_HID_POWER_ON	0x0
54 #define I2C_HID_POWER_OFF	0x1
55 
56 #define IETP_PATTERN            0x0100
57 #define	IETP_UNIQUEID		0x0101
58 #define	IETP_IC_TYPE		0x0103
59 #define	IETP_OSM_VERSION	0x0103
60 #define	IETP_NSM_VERSION	0x0104
61 #define	IETP_TRACENUM		0x0105
62 #define	IETP_MAX_X_AXIS		0x0106
63 #define	IETP_MAX_Y_AXIS		0x0107
64 #define	IETP_RESOLUTION		0x0108
65 #define	IETP_PRESSURE		0x010A
66 
67 #define	IETP_CONTROL		0x0300
68 #define	IETP_CTRL_ABSOLUTE	0x0001
69 #define	IETP_CTRL_STANDARD	0x0000
70 
71 #define	IETP_REPORT_LEN_LO	31
72 #define	IETP_REPORT_LEN_HI	36
73 #define	IETP_MAX_FINGERS	5
74 
75 #define	IETP_REPORT_ID_LO	0x5D
76 #define	IETP_REPORT_ID_HI	0x60
77 
78 #define	IETP_TOUCH_INFO		0
79 #define	IETP_FINGER_DATA	1
80 #define	IETP_FINGER_DATA_LEN	5
81 #define	IETP_WH_DATA		31
82 
83 #define	IETP_TOUCH_LMB		(1 << 0)
84 #define	IETP_TOUCH_RMB		(1 << 1)
85 #define	IETP_TOUCH_MMB		(1 << 2)
86 
87 #define	IETP_MAX_PRESSURE	255
88 #define	IETP_FWIDTH_REDUCE	90
89 #define	IETP_PRESSURE_BASE	25
90 
91 int	ietp_match(struct device *, void *, void *);
92 void	ietp_attach(struct device *, struct device *, void *);
93 int	ietp_detach(struct device *, int);
94 int	ietp_activate(struct device *, int);
95 
96 int	ietp_intr(void *);
97 int	ietp_reset(struct ietp_softc *);
98 
99 int	ietp_fetch_descriptor(struct ietp_softc *sc);
100 int	ietp_set_power(struct ietp_softc *sc, int power);
101 int	ietp_reset_cmd(struct ietp_softc *sc);
102 
103 int32_t		ietp_res2dpmm(uint8_t, bool);
104 
105 int		ietp_iic_read_reg(struct ietp_softc *, uint16_t, size_t, void *);
106 int		ietp_iic_write_reg(struct ietp_softc *, uint16_t, uint16_t);
107 int		ietp_iic_set_absolute_mode(struct ietp_softc *, bool);
108 
109 const struct cfattach ietp_ca = {
110 	sizeof(struct ietp_softc),
111 	ietp_match,
112 	ietp_attach,
113 	ietp_detach,
114 	ietp_activate,
115 };
116 
117 const struct wsmouse_accessops ietp_mouse_access = {
118 	ietp_enable,
119 	ietp_ioctl,
120 	ietp_disable
121 };
122 
123 struct cfdriver ietp_cd = {
124 	NULL, "ietp", DV_DULL
125 };
126 
127 int
ietp_match(struct device * parent,void * match,void * aux)128 ietp_match(struct device *parent, void *match, void *aux)
129 {
130 	struct i2c_attach_args *ia = aux;
131 
132 	if (strcmp(ia->ia_name, "ietp") == 0)
133 		return (1);
134 
135 	return (0);
136 }
137 
138 int32_t
ietp_res2dpmm(uint8_t res,bool hi_precision)139 ietp_res2dpmm(uint8_t res, bool hi_precision)
140 {
141 	int32_t dpi;
142 
143 	dpi = hi_precision ? 300 + res * 100 : 790 + res * 10;
144 
145 	return (dpi * 10 /254);
146 }
147 
148 void
ietp_attach(struct device * parent,struct device * self,void * aux)149 ietp_attach(struct device *parent, struct device *self, void *aux)
150 {
151 	struct ietp_softc *sc = (struct ietp_softc *)self;
152  	struct i2c_attach_args *ia = aux;
153 	uint16_t buf, reg;
154 	uint8_t *buf8;
155 	uint8_t pattern;
156 	struct wsmousedev_attach_args a;
157 	struct wsmousehw *hw;
158 
159 	sc->sc_tag = ia->ia_tag;
160 	sc->sc_addr = ia->ia_addr;
161 
162 	ietp_fetch_descriptor(sc);
163 
164 	if (ia->ia_intr) {
165 		printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr));
166 
167 		sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr,
168 		    IPL_TTY, ietp_intr, sc, sc->sc_dev.dv_xname);
169 		if (sc->sc_ih == NULL) {
170 			printf(", can't establish interrupt\n");
171 			return;
172 		}
173 	}
174 
175 	sc->sc_buttons = 0;
176 	sc->sc_refcnt = 0;
177 
178 	buf8 = (uint8_t *)&buf;
179 
180 	if (ietp_iic_read_reg(sc, IETP_UNIQUEID, sizeof(buf), &buf) != 0) {
181 		printf(": failed reading product ID\n");
182 		return;
183 	}
184 	sc->product_id = le16toh(buf);
185 
186 	if (ietp_iic_read_reg(sc, IETP_PATTERN, sizeof(buf), &buf) != 0) {
187 		printf(": failed reading pattern\n");
188 		return;
189 	}
190 	pattern = buf == 0xFFFF ? 0 : buf8[1];
191 	sc->hi_precision = pattern >= 0x02;
192 
193 	reg = pattern >= 0x01 ? IETP_IC_TYPE : IETP_OSM_VERSION;
194 	if (ietp_iic_read_reg(sc, reg, sizeof(buf), &buf) != 0) {
195 		printf(": failed reading IC type\n");
196 		return;
197 	}
198 	sc->ic_type = pattern >= 0x01 ? be16toh(buf) : buf8[1];
199 
200 	if (ietp_iic_read_reg(sc, IETP_NSM_VERSION, sizeof(buf), &buf) != 0) {
201 		printf(": failed reading SM version\n");
202 		return;
203 	}
204 	sc->is_clickpad = (buf8[0] & 0x10) != 0;
205 
206 	if (ietp_iic_set_absolute_mode(sc, true) != 0) {
207 		printf(": failed to set absolute mode\n");
208 		return;
209 	}
210 
211 	if (ietp_iic_read_reg(sc, IETP_MAX_X_AXIS, sizeof(buf), &buf) != 0) {
212 		printf(": failed reading max x\n");
213 		return;
214 	}
215 	sc->max_x = le16toh(buf);
216 
217 	if (ietp_iic_read_reg(sc, IETP_MAX_Y_AXIS, sizeof(buf), &buf) != 0) {
218 		printf(": failed reading max y\n");
219 		return;
220 	}
221 	sc->max_y = le16toh(buf);
222 
223 	if (ietp_iic_read_reg(sc, IETP_TRACENUM, sizeof(buf), &buf) != 0) {
224 		printf(": failed reading trace info\n");
225 		return;
226 	}
227 	sc->trace_x = sc->max_x / buf8[0];
228 	sc->trace_y = sc->max_y / buf8[1];
229 
230 	if (ietp_iic_read_reg(sc, IETP_PRESSURE, sizeof(buf), &buf) != 0) {
231 		printf(": failed reading pressure format\n");
232 		return;
233 	}
234 	sc->pressure_base = (buf8[0] & 0x10) ? 0 : IETP_PRESSURE_BASE;
235 
236 	if (ietp_iic_read_reg(sc, IETP_RESOLUTION, sizeof(buf), &buf)  != 0) {
237 		printf(": failed reading resolution\n");
238 		return;
239 	}
240 	/* Conversion from internal format to dot per mm */
241 	sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precision);
242 	sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precision);
243 
244 	sc->report_id = sc->hi_precision ?
245 	    IETP_REPORT_ID_HI : IETP_REPORT_ID_LO;
246 	sc->report_len = sc->hi_precision ?
247 	    IETP_REPORT_LEN_HI : IETP_REPORT_LEN_LO;
248 
249 	sc->sc_ibuf = malloc(IETP_REPORT_LEN_HI + 12, M_DEVBUF,
250 	    M_NOWAIT | M_ZERO);
251 	sc->sc_isize = sc->report_len + 3;
252 
253 	a.accessops = &ietp_mouse_access;
254 	a.accesscookie = sc;
255 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
256 
257 	hw = wsmouse_get_hw(sc->sc_wsmousedev);
258 	hw->type = WSMOUSE_TYPE_TOUCHPAD;
259 	hw->hw_type = sc->is_clickpad ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD;
260 	hw->x_min = 0;
261 	hw->x_max = sc->max_x;
262 	hw->y_min = 0;
263 	hw->y_max = sc->max_y;
264 	hw->h_res = sc->res_x;
265 	hw->v_res = sc->res_y;
266 	hw->mt_slots = IETP_MAX_FINGERS;
267 
268 	wsmouse_configure(sc->sc_wsmousedev, NULL, 0);
269 
270 	/* power down until we're opened */
271 	if (ietp_set_power(sc, I2C_HID_POWER_OFF)) {
272 		printf(": failed to power down\n");
273 		return;
274 	}
275 
276 	printf("\n");
277 
278 	DPRINTF(("%s: max_x=%d, max_y=%d, %s\n", sc->sc_dev.dv_xname,
279 		 sc->max_x, sc->max_y,
280 		 sc->is_clickpad ? "clickpad" : "touchpad"));
281 
282 	return;
283 }
284 
285 int
ietp_detach(struct device * self,int flags)286 ietp_detach(struct device *self, int flags)
287 {
288 	struct ietp_softc *sc = (struct ietp_softc *)self;
289 
290 	if (sc->sc_ih != NULL) {
291 		iic_intr_disestablish(sc->sc_tag, sc->sc_ih);
292 		sc->sc_ih = NULL;
293 	}
294 
295 	if (sc->sc_ibuf != NULL) {
296 		free(sc->sc_ibuf, M_DEVBUF, sc->sc_isize);
297 		sc->sc_ibuf = NULL;
298 	}
299 
300 	return (0);
301 }
302 
303 int
ietp_activate(struct device * self,int act)304 ietp_activate(struct device *self, int act)
305 {
306 	struct ietp_softc *sc = (struct ietp_softc *)self;
307 	int rv;
308 
309 	DPRINTF(("%s(%d)\n", __func__, act));
310 
311 	switch (act) {
312 	case DVACT_QUIESCE:
313 		rv = config_activate_children(self, act);
314 		sc->sc_dying = 1;
315 		if (ietp_set_power(sc, I2C_HID_POWER_OFF))
316 			printf("%s: failed to power down\n",
317 			    sc->sc_dev.dv_xname);
318 		break;
319 	case DVACT_WAKEUP:
320 		ietp_reset(sc);
321 		sc->sc_dying = 0;
322 		rv = config_activate_children(self, act);
323 		break;
324 	default:
325 		rv = config_activate_children(self, act);
326 		break;
327 	}
328 	return rv;
329 }
330 
331 void
ietp_sleep(struct ietp_softc * sc,int ms)332 ietp_sleep(struct ietp_softc *sc, int ms)
333 {
334 	if (cold)
335 		delay(ms * 1000);
336 	else
337 		tsleep_nsec(&sc, PWAIT, "ietp", MSEC_TO_NSEC(ms));
338 }
339 
340 int
ietp_iic_set_absolute_mode(struct ietp_softc * sc,bool enable)341 ietp_iic_set_absolute_mode(struct ietp_softc *sc, bool enable)
342 {
343 	static const struct {
344 		uint16_t	ic_type;
345 		uint16_t	product_id;
346 	} special_fw[] = {
347 	    { 0x0E, 0x05 }, { 0x0E, 0x06 }, { 0x0E, 0x07 }, { 0x0E, 0x09 },
348 	    { 0x0E, 0x13 }, { 0x08, 0x26 },
349 	};
350 	uint16_t val;
351 	int i, error;
352 	bool require_wakeup;
353 
354 	error = 0;
355 
356 	/*
357 	 * Some ASUS touchpads need to be powered on to enter absolute mode.
358 	 */
359 	require_wakeup = false;
360 	for (i = 0; i < nitems(special_fw); i++) {
361 		if (sc->ic_type == special_fw[i].ic_type &&
362 		    sc->product_id == special_fw[i].product_id) {
363 			require_wakeup = true;
364 			break;
365 		}
366 	}
367 
368 	if (require_wakeup && ietp_set_power(sc, I2C_HID_POWER_ON) != 0) {
369 		printf("%s: failed writing poweron command\n",
370 		    sc->sc_dev.dv_xname);
371 		return (EIO);
372 	}
373 
374 	val = enable ? IETP_CTRL_ABSOLUTE : IETP_CTRL_STANDARD;
375 	if (ietp_iic_write_reg(sc, IETP_CONTROL, val) != 0) {
376 		printf("%s: failed setting absolute mode\n",
377 		    sc->sc_dev.dv_xname);
378 		error = EIO;
379 	}
380 
381 	if (require_wakeup && ietp_set_power(sc, I2C_HID_POWER_OFF) != 0) {
382 		printf("%s: failed writing poweroff command\n",
383 		    sc->sc_dev.dv_xname);
384 		error = EIO;
385 	}
386 
387 	return (error);
388 }
389 
390 int
ietp_iic_read_reg(struct ietp_softc * sc,uint16_t reg,size_t len,void * val)391 ietp_iic_read_reg(struct ietp_softc *sc, uint16_t reg, size_t len, void *val)
392 {
393 	uint8_t cmd[] = {
394 		reg & 0xff,
395 		reg >> 8,
396 	};
397 
398 	return iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
399 		 &cmd, 2, val, len, 0);
400 }
401 
402 int
ietp_iic_write_reg(struct ietp_softc * sc,uint16_t reg,uint16_t val)403 ietp_iic_write_reg(struct ietp_softc *sc, uint16_t reg, uint16_t val)
404 {
405 	uint8_t cmd[] = {
406 		reg & 0xff,
407 		reg >> 8,
408 		val & 0xff,
409 		val >> 8,
410 	};
411 
412 	return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
413 		 &cmd, 4, NULL, 0, 0);
414 }
415 
416 int
ietp_set_power(struct ietp_softc * sc,int power)417 ietp_set_power(struct ietp_softc *sc, int power)
418 {
419 	int res = 1;
420 	uint8_t cmd[] = {
421 		htole16(sc->hid_desc.wCommandRegister) & 0xff,
422 		htole16(sc->hid_desc.wCommandRegister) >> 8,
423 		power,
424 		I2C_HID_CMD_SET_POWER,
425 	};
426 
427 	iic_acquire_bus(sc->sc_tag, 0);
428 
429 	DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n",
430 		 sc->sc_dev.dv_xname, power));
431 
432 	/* 22 00 00 08 */
433 	res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
434 		       &cmd, sizeof(cmd), NULL, 0, 0);
435 
436 	iic_release_bus(sc->sc_tag, 0);
437 
438 	return (res);
439 }
440 
441 int
ietp_reset_cmd(struct ietp_softc * sc)442 ietp_reset_cmd(struct ietp_softc *sc)
443 {
444 	int res = 1;
445 	uint8_t cmd[] = {
446 		htole16(sc->hid_desc.wCommandRegister) & 0xff,
447 		htole16(sc->hid_desc.wCommandRegister) >> 8,
448 		0,
449 		I2C_HID_CMD_RESET,
450 	};
451 
452 	iic_acquire_bus(sc->sc_tag, 0);
453 
454 	DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n",
455 		 sc->sc_dev.dv_xname));
456 
457 	/* 22 00 00 01 */
458 	res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
459 		       &cmd, sizeof(cmd), NULL, 0, 0);
460 
461 	iic_release_bus(sc->sc_tag, 0);
462 
463 	return (res);
464 }
465 
466 int
ietp_fetch_descriptor(struct ietp_softc * sc)467 ietp_fetch_descriptor(struct ietp_softc *sc)
468 {
469 	int i, res = 1;
470 	/*
471 	 * 5.2.2 - HID Descriptor Retrieval
472 	 * register is passed from the controller
473 	 */
474 	uint8_t cmd[] = {
475 		1,
476 		0,
477 	};
478 
479 	iic_acquire_bus(sc->sc_tag, 0);
480 
481 	DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x1\n",
482 		 sc->sc_dev.dv_xname));
483 
484 	/* 20 00 */
485 	res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
486 		       &cmd, sizeof(cmd), &sc->hid_desc_buf,
487 		       sizeof(struct i2c_hid_desc), 0);
488 
489 	DPRINTF(("%s: HID descriptor:", sc->sc_dev.dv_xname));
490 	for (i = 0; i < sizeof(struct i2c_hid_desc); i++)
491 		DPRINTF((" %.2x", sc->hid_desc_buf[i]));
492 	DPRINTF(("\n"));
493 
494 	iic_release_bus(sc->sc_tag, 0);
495 
496 	return (res);
497 }
498 
499 int
ietp_reset(struct ietp_softc * sc)500 ietp_reset(struct ietp_softc *sc)
501 {
502 	DPRINTF(("%s: resetting\n", sc->sc_dev.dv_xname));
503 
504 	if (ietp_set_power(sc, I2C_HID_POWER_ON)) {
505 		printf("%s: failed to power on\n", sc->sc_dev.dv_xname);
506 		return (1);
507 	}
508 
509 	ietp_sleep(sc, 100);
510 
511 	if (ietp_reset_cmd(sc)) {
512 		printf("%s: failed to reset hardware\n", sc->sc_dev.dv_xname);
513 
514 		ietp_set_power(sc, I2C_HID_POWER_OFF);
515 
516 		return (1);
517 	}
518 
519 	ietp_sleep(sc, 100);
520 
521 	return (0);
522 }
523 
524 void
parse_input(struct ietp_softc * sc,u_char * report,int len)525 parse_input(struct ietp_softc *sc, u_char *report, int len)
526 {
527 	uint8_t *fdata;
528 	int32_t finger;
529 	int32_t x, y, p;
530 	int buttons = 0;
531 	int s;
532 
533 	/* we seem to get 0 length reports sometimes, ignore them */
534 	if (len == 0)
535 		return;
536 	if (len != sc->report_len) {
537 		printf("%s: wrong report length (%d vs %d expected)",
538 		    sc->sc_dev.dv_xname, len, (int) sc->report_len);
539 		return;
540 	}
541 
542 	s = spltty();
543 
544 	buttons = report[IETP_TOUCH_INFO] & 7;
545 
546 	if (sc->sc_buttons != buttons) {
547 		wsmouse_buttons(sc->sc_wsmousedev, buttons);
548 		sc->sc_buttons = buttons;
549 	}
550 
551 	for (finger = 0, fdata = report + IETP_FINGER_DATA;
552 	     finger < IETP_MAX_FINGERS;
553 	     finger++, fdata += IETP_FINGER_DATA_LEN) {
554 		if ((report[IETP_TOUCH_INFO] & (1 << (finger + 3))) != 0) {
555 			if (sc->hi_precision) {
556 				x = fdata[0] << 8 | fdata[1];
557 				y = fdata[2] << 8 | fdata[3];
558 			} else {
559 				x = (fdata[0] & 0xf0) << 4 | fdata[1];
560 				y = (fdata[0] & 0x0f) << 8 | fdata[2];
561 			}
562 
563 			if (x > sc->max_x || y > sc->max_y) {
564 				printf("%s: [%d] x=%d y=%d over max (%d, %d)\n",
565 				    sc->sc_dev.dv_xname, finger, x, y,
566 				    sc->max_x, sc->max_y);
567 				continue;
568 			}
569 
570 
571 			p = MIN((int32_t)fdata[4] + sc->pressure_base,
572 				    IETP_MAX_PRESSURE);
573 
574 		} else {
575 			x = 0;
576 			y = 0;
577 			p = 0;
578 		}
579 
580 		DPRINTF(("position: [finger=%d, x=%d, y=%d, p=%d]\n", finger,
581 		    x, y, p));
582 		wsmouse_mtstate(sc->sc_wsmousedev, finger, x, y, p);
583 	}
584 
585 	wsmouse_input_sync(sc->sc_wsmousedev);
586 
587 	splx(s);
588 }
589 
590 int
ietp_intr(void * arg)591 ietp_intr(void *arg)
592 {
593 	struct ietp_softc *sc = arg;
594 	int psize, i;
595 	u_char *p;
596 	u_int rep = 0;
597 
598 	if (sc->sc_dying)
599 		return 1;
600 
601 	/*
602 	 * XXX: force I2C_F_POLL for now to avoid dwiic interrupting
603 	 * while we are interrupting
604 	 */
605 
606 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
607 	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0,
608 	    sc->sc_ibuf, letoh16(sc->hid_desc.wMaxInputLength), I2C_F_POLL);
609 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
610 
611 	/*
612 	 * 6.1.1 - First two bytes are the packet length, which must be less
613 	 * than or equal to wMaxInputLength
614 	 */
615 	psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8;
616 	if (psize <= 2 || psize > sc->sc_isize) {
617 		DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n",
618 			    sc->sc_dev.dv_xname, __func__, psize,
619 			    sc->sc_isize));
620 		return (1);
621 	}
622 
623 	/* 3rd byte is the report id */
624 	p = sc->sc_ibuf + 2;
625 	psize -= 2;
626 	rep = *p++;
627 	psize--;
628 
629 	DPRINTF(("%s: %s: hid input (rep 0x%x):", sc->sc_dev.dv_xname, __func__,
630 	    rep));
631 	for (i = 0; i < psize; i++) {
632 		DPRINTF((" %.2x", p[i]));
633 	}
634 	DPRINTF(("\n"));
635 
636 	if (sc->sc_refcnt && rep == sc->report_id) {
637 		parse_input(sc, p, psize);
638 	}
639 
640 	return (1);
641 }
642 
643 int
ietp_enable(void * dev)644 ietp_enable(void *dev)
645 {
646 	struct ietp_softc *sc = dev;
647 
648 	DPRINTF(("%s: %s: refcnt=%d\n", sc->sc_dev.dv_xname,
649 	    __func__, sc->sc_refcnt));
650 
651 	if (sc->sc_refcnt++ || sc->sc_isize == 0)
652 		return (0);
653 
654 	/* power on */
655 	ietp_reset(sc);
656 
657 	return (0);
658 }
659 
660 void
ietp_disable(void * dev)661 ietp_disable(void *dev)
662 {
663 	struct ietp_softc *sc = dev;
664 	DPRINTF(("%s: %s: refcnt=%d\n", sc->sc_dev.dv_xname,
665 	    __func__, sc->sc_refcnt));
666 
667 	if (--sc->sc_refcnt)
668 		return;
669 
670 	/* no sub-devices open, conserve power */
671 
672 	if (ietp_set_power(sc, I2C_HID_POWER_OFF))
673 		printf("%s: failed to power down\n", sc->sc_dev.dv_xname);
674 }
675 
676 int
ietp_ioctl(void * dev,u_long cmd,caddr_t data,int flag,struct proc * p)677 ietp_ioctl(void *dev, u_long cmd, caddr_t data, int flag,
678     struct proc *p)
679 {
680 	struct ietp_softc *sc = dev;
681  	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
682 
683 	switch (cmd) {
684 	case WSMOUSEIO_GTYPE:
685 		*(u_int *)data = WSMOUSE_TYPE_TOUCHPAD;
686 		return 0;
687 
688 	case WSMOUSEIO_GCALIBCOORDS:
689 		wsmc->minx = 0;
690 		wsmc->maxx = sc->max_x;
691 		wsmc->miny = 0;
692 		wsmc->maxy = sc->max_y;
693 		wsmc->swapxy = 0;
694 		wsmc->resx = sc->res_x;
695 		wsmc->resy = sc->res_y;
696 		return 0;
697 	}
698 	return -1;
699 }
700