xref: /openbsd/sys/dev/i2c/iatp.c (revision fd0cc40e)
1 /* $OpenBSD: iatp.c,v 1.1 2016/09/01 10:04:51 jcs Exp $ */
2 /*
3  * Atmel maXTouch i2c touchscreen/touchpad driver
4  * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
5  *
6  * AT421085 datasheet:
7  * http://www.atmel.com/images/Atmel-9626-AT42-QTouch-BSW-AT421085-Object-Protocol-Guide_Datasheet.pdf
8  *
9  * Uses code from libmaxtouch <https://github.com/atmel-maxtouch/mxt-app>
10  * Copyright 2011 Atmel Corporation. All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  *    1. Redistributions of source code must retain the above copyright notice,
16  *    this list of conditions and the following disclaimer.
17  *
18  *    2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ATMEL ''AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
25  * EVENT SHALL ATMEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/stdint.h>
40 
41 #include <dev/i2c/i2cvar.h>
42 
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wscons/wsmousevar.h>
45 #include <dev/hid/hid.h>
46 #include <dev/hid/hidmsvar.h>
47 
48 /* #define IATP_DEBUG */
49 
50 #ifdef IATP_DEBUG
51 #define DPRINTF(x) printf x
52 #else
53 #define DPRINTF(x)
54 #endif
55 
56 struct mxt_object {
57 	uint8_t type;
58 	uint16_t start_pos;
59 	uint8_t size_minus_one;
60 #define MXT_SIZE(o)		((uint16_t)((o)->size_minus_one) + 1)
61 	uint8_t instances_minus_one;
62 #define MXT_INSTANCES(o)	((uint16_t)((o)->instances_minus_one) + 1)
63 	uint8_t num_report_ids;
64 } __packed;
65 
66 struct mxt_id_info {
67 	uint8_t family;
68 	uint8_t variant;
69 	uint8_t version;
70 	uint8_t build;
71 	uint8_t matrix_x_size;
72 	uint8_t matrix_y_size;
73 	uint8_t num_objects;
74 } __packed;
75 
76 struct mxt_info {
77 	struct mxt_id_info id;
78 	struct mxt_object *objects;
79 	uint32_t crc;
80 	uint8_t *raw_info;
81 	uint8_t max_report_id;
82 };
83 
84 /* object types we care about (of 117 total!) */
85 
86 #define MXT_GEN_MESSAGEPROCESSOR_T5	5
87 
88 #define MXT_GEN_COMMANDPROCESSOR_T6	6
89 # define MXT_T6_STATUS_RESET		(1 << 7)
90 # define MXT_T6_STATUS_OFL		(1 << 6)
91 # define MXT_T6_STATUS_SIGERR		(1 << 5)
92 # define MXT_T6_STATUS_CAL		(1 << 4)
93 # define MXT_T6_STATUS_CFGERR		(1 << 3)
94 # define MXT_T6_STATUS_COMSERR		(1 << 2)
95 # define MXT_T6_CMD_RESET		0
96 # define MXT_T6_CMD_BACKUPNV		1
97 # define MXT_T6_CMD_CALIBRATE		2
98 # define MXT_T6_CMD_REPORTALL		3
99 # define MXT_T6_CMD_DIAGNOSTIC		5
100 
101 #define MXT_GEN_POWERCONFIG_T7		7
102 # define MXT_T7_POWER_MODE_DEFAULT	1
103 # define MXT_T7_POWER_MODE_DEEP_SLEEP	2
104 struct mxt_t7_config {
105 	uint8_t idle;
106 	uint8_t active;
107 	uint8_t atoi_timeout;
108 } __packed;
109 
110 #define MXT_SPT_GPIOPWM_T19		19
111 static const struct mxt_t19_button_map {
112 	const char *vendor;
113 	const char *product;
114 	const char *hid;
115 	int bit;
116 } mxt_t19_button_map_devs[] = {
117 	/* Chromebook Pixel 2015 */
118 	{ "GOOGLE", "Samus", "ATML0000", 3 },
119 	/* Other Google Chromebooks */
120 	{ "GOOGLE", "", "ATML0000", 5 },
121 	{ NULL }
122 };
123 
124 #define MXT_SPT_MESSAGECOUNT_T44	44
125 
126 #define MXT_TOUCH_MULTITOUCHSCREEN_T100	100
127 # define MXT_T100_CTRL			0
128 # define MXT_T100_CFG1			1
129 # define MXT_T100_TCHAUX		3
130 # define MXT_T100_XRANGE		13
131 # define MXT_T100_YRANGE		24
132 # define MXT_T100_CFG_SWITCHXY		(1 << 5)
133 # define MXT_T100_TCHAUX_VECT		(1 << 0)
134 # define MXT_T100_TCHAUX_AMPL		(1 << 1)
135 # define MXT_T100_TCHAUX_AREA		(1 << 2)
136 # define MXT_T100_DETECT		(1 << 7)
137 # define MXT_T100_TYPE_MASK		0x70
138 
139 enum t100_type {
140 	MXT_T100_TYPE_FINGER		= 1,
141 	MXT_T100_TYPE_PASSIVE_STYLUS	= 2,
142 	MXT_T100_TYPE_HOVERING_FINGER	= 4,
143 	MXT_T100_TYPE_GLOVE		= 5,
144 	MXT_T100_TYPE_LARGE_TOUCH	= 6,
145 };
146 
147 #define MXT_DISTANCE_ACTIVE_TOUCH	0
148 #define MXT_DISTANCE_HOVERING		1
149 
150 #define MXT_TOUCH_MAJOR_DEFAULT		1
151 
152 struct iatp_softc {
153 	struct device		sc_dev;
154 	i2c_tag_t		sc_tag;
155 
156 	i2c_addr_t		sc_addr;
157 	void			*sc_ih;
158 
159 	struct device		*sc_wsmousedev;
160 	char			sc_hid[16];
161 	int			sc_busy;
162 	int			sc_enabled;
163 	int			sc_touchpad;
164 	struct tsscale		sc_tsscale;
165 
166 	uint8_t			*table;
167 	size_t			table_size;
168 
169 	struct mxt_info		info;
170 	uint8_t			*msg_buf;
171 	uint8_t			multitouch;
172 	uint8_t			num_touchids;
173 	uint32_t		max_x;
174 	uint32_t		max_y;
175 	uint8_t			button;
176 
177 	uint16_t		t5_address;
178 	uint8_t			t5_msg_size;
179 	uint16_t		t6_address;
180 	uint8_t			t6_reportid;
181 	uint16_t		t7_address;
182 	struct mxt_t7_config	t7_config;
183 	uint8_t			t19_reportid;
184 	int			t19_button_bit;
185 	uint16_t		t44_address;
186 	uint8_t			t100_reportid_min;
187 	uint8_t			t100_reportid_max;
188 	uint8_t			t100_aux_ampl;
189 	uint8_t			t100_aux_area;
190 	uint8_t			t100_aux_vect;
191 };
192 
193 int	iatp_match(struct device *, void *, void *);
194 void	iatp_attach(struct device *, struct device *, void *);
195 int	iatp_detach(struct device *, int);
196 int	iatp_activate(struct device *, int);
197 
198 int	iatp_ioctl(void *, u_long, caddr_t, int, struct proc *);
199 int	iatp_enable(void *);
200 void	iatp_disable(void *);
201 
202 int	iatp_read_reg(struct iatp_softc *, uint16_t, size_t, void *);
203 int	iatp_write_reg(struct iatp_softc *, uint16_t, size_t, void *);
204 int	iatp_init(struct iatp_softc *);
205 int	iatp_intr(void *);
206 
207 int	iatp_proc_msg(struct iatp_softc *, uint8_t *);
208 int	iatp_t5_read_msgs(struct iatp_softc *, int);
209 void	iatp_t6_proc_msg(struct iatp_softc *, uint8_t *);
210 int	iatp_t7_set_power_mode(struct iatp_softc *, int);
211 void	iatp_t19_proc_msg(struct iatp_softc *, uint8_t *);
212 int	iatp_t44_read_count(struct iatp_softc *);
213 void	iatp_t100_proc_msg(struct iatp_softc *, uint8_t *);
214 
215 /* for gpio pin mapping */
216 extern char *hw_vendor, *hw_prod;
217 
218 const struct wsmouse_accessops iatp_accessops = {
219 	iatp_enable,
220 	iatp_ioctl,
221 	iatp_disable,
222 };
223 
224 struct cfattach iatp_ca = {
225 	sizeof(struct iatp_softc),
226 	iatp_match,
227 	iatp_attach,
228 	iatp_detach,
229 	iatp_activate
230 };
231 
232 struct cfdriver iatp_cd = {
233 	NULL, "iatp", DV_DULL
234 };
235 
236 int
237 iatp_match(struct device *parent, void *match, void *aux)
238 {
239 	struct i2c_attach_args *ia = aux;
240 
241 	if (strcmp(ia->ia_name, "iatp") == 0)
242 		return 1;
243 
244 	return 0;
245 }
246 
247 void
248 iatp_attach(struct device *parent, struct device *self, void *aux)
249 {
250 	struct iatp_softc *sc = (struct iatp_softc *)self;
251 	struct i2c_attach_args *ia = aux;
252 	struct wsmousedev_attach_args wsmaa;
253 
254 	sc->sc_tag = ia->ia_tag;
255 	sc->sc_addr = ia->ia_addr;
256 
257 	if (ia->ia_cookie != NULL)
258 		memcpy(&sc->sc_hid, ia->ia_cookie, sizeof(sc->sc_hid));
259 
260 	if (!iatp_init(sc))
261 		return;
262 
263 	if (ia->ia_intr) {
264 		printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr));
265 
266 		sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr,
267 		    IPL_TTY, iatp_intr, sc, sc->sc_dev.dv_xname);
268 		if (sc->sc_ih == NULL) {
269 			printf(", can't establish interrupt\n");
270 			return;
271 		}
272 	}
273 
274 	printf(": Atmel maXTouch Touch%s (%dx%d)\n",
275 	    sc->sc_touchpad ? "pad" : "screen", sc->max_x, sc->max_y);
276 
277 	wsmaa.accessops = &iatp_accessops;
278 	wsmaa.accesscookie = sc;
279 	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
280 }
281 
282 int
283 iatp_detach(struct device *self, int flags)
284 {
285 	struct iatp_softc *sc = (struct iatp_softc *)self;
286 
287 	if (sc->sc_ih != NULL) {
288 		intr_disestablish(sc->sc_ih);
289 		sc->sc_ih = NULL;
290 	}
291 
292 	sc->sc_enabled = 0;
293 
294 	return 0;
295 }
296 
297 int
298 iatp_activate(struct device *self, int act)
299 {
300 	struct iatp_softc *sc = (struct iatp_softc *)self;
301 
302 	switch (act) {
303 	case DVACT_QUIESCE:
304 #if 0
305 		/* XXX: causes dwiic troubles */
306 		iatp_t7_set_power_mode(sc, MXT_T7_POWER_MODE_DEEP_SLEEP);
307 #endif
308 		break;
309 	case DVACT_WAKEUP:
310 		sc->sc_busy = 1;
311 		iatp_init(sc);
312 		sc->sc_busy = 0;
313 		break;
314 	}
315 
316 	config_activate_children(self, act);
317 
318 	return 0;
319 }
320 
321 int
322 iatp_enable(void *v)
323 {
324 	struct iatp_softc *sc = v;
325 
326 	if (sc->sc_busy && tsleep(&sc->sc_busy, PRIBIO, "iatp", hz) != 0) {
327 		printf("%s: trying to enable but we're busy\n",
328 		    sc->sc_dev.dv_xname);
329 		return 1;
330 	}
331 
332 	sc->sc_busy = 1;
333 
334 	DPRINTF(("%s: enabling\n", sc->sc_dev.dv_xname));
335 
336 	if (wsmouse_mt_init(sc->sc_wsmousedev, sc->num_touchids, 0)) {
337 		printf("%s: failed wsmouse_mt_init\n", sc->sc_dev.dv_xname);
338 		return 1;
339 	}
340 
341 	if (sc->sc_touchpad)
342 		wsmouse_set_mode(sc->sc_wsmousedev, WSMOUSE_COMPAT);
343 
344 	/* force a read of any pending messages so we start getting new
345 	 * interrupts */
346 	iatp_t5_read_msgs(sc, sc->info.max_report_id);
347 
348 	sc->sc_enabled = 1;
349 	sc->sc_busy = 0;
350 
351 	return 0;
352 }
353 
354 void
355 iatp_disable(void *v)
356 {
357 	struct iatp_softc *sc = v;
358 
359 	DPRINTF(("%s: disabling\n", sc->sc_dev.dv_xname));
360 
361 	if (sc->sc_touchpad)
362 		wsmouse_set_mode(sc->sc_wsmousedev, WSMOUSE_COMPAT);
363 
364 	sc->sc_enabled = 0;
365 }
366 
367 int
368 iatp_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
369 {
370 	struct iatp_softc *sc = v;
371 	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
372 	int wsmode;
373 
374 	DPRINTF(("%s: %s: cmd %ld\n", sc->sc_dev.dv_xname, __func__, cmd));
375 
376 	switch (cmd) {
377 	case WSMOUSEIO_SCALIBCOORDS:
378 		sc->sc_tsscale.minx = wsmc->minx;
379 		sc->sc_tsscale.maxx = wsmc->maxx;
380 		sc->sc_tsscale.miny = wsmc->miny;
381 		sc->sc_tsscale.maxy = wsmc->maxy;
382 		sc->sc_tsscale.swapxy = wsmc->swapxy;
383 		sc->sc_tsscale.resx = wsmc->resx;
384 		sc->sc_tsscale.resy = wsmc->resy;
385 		break;
386 
387 	case WSMOUSEIO_GCALIBCOORDS:
388 		wsmc->minx = sc->sc_tsscale.minx;
389 		wsmc->maxx = sc->sc_tsscale.maxx;
390 		wsmc->miny = sc->sc_tsscale.miny;
391 		wsmc->maxy = sc->sc_tsscale.maxy;
392 		wsmc->swapxy = sc->sc_tsscale.swapxy;
393 		wsmc->resx = sc->sc_tsscale.resx;
394 		wsmc->resy = sc->sc_tsscale.resy;
395 		break;
396 
397 	case WSMOUSEIO_GTYPE:
398 		if (sc->sc_touchpad)
399 			*(u_int *)data = WSMOUSE_TYPE_SYNAPTICS;
400 		else
401 			*(u_int *)data = WSMOUSE_TYPE_TPANEL;
402 		break;
403 
404 	case WSMOUSEIO_SETMODE:
405 		if (!sc->sc_touchpad)
406 			return -1;
407 
408 		wsmode = *(u_int *)data;
409 		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) {
410 			printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname,
411 			    wsmode);
412 			return EINVAL;
413 		}
414 		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
415 		break;
416 
417 	default:
418 		return -1;
419 	}
420 
421 	return 0;
422 }
423 
424 int
425 iatp_init(struct iatp_softc *sc)
426 {
427 	uint8_t reportid;
428 	int i;
429 
430 	sc->sc_enabled = 0;
431 
432 	/* some sane defaults */
433 	sc->num_touchids = 10;
434 	sc->max_x = 1023;
435 	sc->max_y = 1023;
436 	sc->sc_touchpad = 0;
437 
438 	/*
439 	 * AT42QT1085 Information block:
440 	 *
441 	 * ID information (struct mxt_id_info)
442 	 *	0 Family ID
443 	 *	1 Variant ID
444 	 *	2 Version
445 	 *	3 Build
446 	 *	4 Number of Keys
447 	 *	5 1
448 	 *	6 Number of Object Table Elements
449 	 * Object Table Element 1 (struct mxt_object)
450 	 *	7 Object Type
451 	 *	8-9 Object Start Address
452 	 *	10 Size - 1
453 	 *	11 Instances - 1
454 	 *	12 Number of report IDs per instance
455 	 * Object Table Element 2 (struct mxt_object)
456 	 * 	...
457 	 * Information Block Checksum
458 	 * [ Object 1 ]
459 	 * ...
460 	 */
461 
462 	/* read table header */
463 	if (iatp_read_reg(sc, 0, sizeof(struct mxt_id_info), &sc->info.id) ||
464 	    !sc->info.id.num_objects) {
465 		printf("%s: failed reading main memory map\n",
466 		    sc->sc_dev.dv_xname);
467 		return 0;
468 	}
469 
470 	sc->table_size = sc->info.id.num_objects * sizeof(struct mxt_object);
471 	sc->table = malloc(sc->table_size, M_DEVBUF, M_NOWAIT | M_ZERO);
472 
473 	/* read all table objects */
474 	if (iatp_read_reg(sc, sizeof(struct mxt_id_info), sc->table_size,
475 	    sc->table)) {
476 		printf("%s: failed reading info table of size %zu\n",
477 		    sc->sc_dev.dv_xname, sc->table_size);
478 		return 0;
479 	}
480 
481 	reportid = 1;
482 	for (i = 0; i < sc->info.id.num_objects; i++) {
483 		struct mxt_object *object = (void *)(sc->table +
484 		    (sizeof(struct mxt_object) * i));
485 		int min_id = 0, max_id = 0;
486 
487 		if (object->num_report_ids) {
488 			min_id = reportid;
489 			reportid += (object->num_report_ids *
490 			    (uint8_t)MXT_INSTANCES(object));
491 			max_id = reportid - 1;
492 		}
493 
494 		DPRINTF(("%s: object[%d] T%d at 0x%x, %d report ids (%d-%d)\n",
495 		    sc->sc_dev.dv_xname, i, object->type,
496 		    le16toh(object->start_pos), object->num_report_ids, min_id,
497 		    max_id));
498 
499 		switch (object->type) {
500 		case MXT_GEN_MESSAGEPROCESSOR_T5:
501 			/*
502 			 * 4.2 - message processor is what interrupts and
503 			 * relays new messages to us
504 			 */
505 
506 			if (sc->info.id.family == 0x80 &&
507 			    sc->info.id.version < 0x20)
508 				/*
509 				 * from linux: "On mXT224 firmware versions
510 				 * prior to V2.0 read and discard unused CRC
511 				 * byte otherwise DMA reads are misaligned."
512 				 */
513 				sc->t5_msg_size = MXT_SIZE(object);
514 			else
515 				sc->t5_msg_size = MXT_SIZE(object) - 1;
516 
517 			sc->t5_address = le16toh(object->start_pos);
518 			break;
519 
520 		case MXT_GEN_COMMANDPROCESSOR_T6:
521 			/*
522 			 * 4.3 - command processor receives commands from us
523 			 * and reports command status messages
524 			 */
525 			sc->t6_address = le16toh(object->start_pos);
526 			sc->t6_reportid = min_id;
527 			break;
528 
529 		case MXT_GEN_POWERCONFIG_T7:
530 			/*
531 			 * 4.4 - power configuration, number of milliseconds
532 			 * between sampling in each mode
533 			 */
534 			sc->t7_address = le16toh(object->start_pos);
535 
536 			iatp_read_reg(sc, sc->t7_address,
537 			    sizeof(sc->t7_config), &sc->t7_config);
538 
539 			break;
540 
541 		case MXT_SPT_GPIOPWM_T19: {
542 			/*
543 			 * generic gpio pin, mapped to touchpad button(s)
544 			 */
545 			const struct mxt_t19_button_map *m;
546 
547 			sc->t19_reportid = min_id;
548 
549 			/* find this machine's button config */
550 			sc->t19_button_bit = -1;
551 			if (hw_vendor == NULL || hw_prod == NULL ||
552 			    sc->sc_hid == NULL)
553 				break;
554 
555 			for (m = mxt_t19_button_map_devs; m->vendor != NULL;
556 			    m++) {
557 				if (strncmp(hw_vendor, m->vendor,
558 				    strlen(m->vendor)) != 0 ||
559 				    strncmp(hw_prod, m->product,
560 				    strlen(m->product)) != 0 ||
561 				    strncmp(sc->sc_hid, m->hid,
562 				    strlen(m->hid)) != 0)
563 					continue;
564 
565 				DPRINTF(("%s: found matching t19 "
566 				    "button map device \"%s\"/\"%s\" on %s: "
567 				    "bit %d\n", sc->sc_dev.dv_xname,
568 				    m->vendor, m->product, m->hid, m->bit));
569 				sc->t19_button_bit = m->bit;
570 				break;
571 			}
572 
573 			if (sc->t19_button_bit > -1)
574 				sc->sc_touchpad = 1;
575 
576 			break;
577 		}
578 
579 		case MXT_SPT_MESSAGECOUNT_T44:
580 			sc->t44_address = le16toh(object->start_pos);
581 			break;
582 
583 		case MXT_TOUCH_MULTITOUCHSCREEN_T100: {
584 			uint16_t range_x, range_y;
585 			uint8_t orient, tchaux;
586 			int aux;
587 
588 			sc->t100_reportid_min = min_id;
589 			sc->t100_reportid_max = max_id;
590 			sc->num_touchids = object->num_report_ids - 2;
591 			sc->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
592 
593 			if (iatp_read_reg(sc, object->start_pos +
594 			    MXT_T100_XRANGE, sizeof(range_x), &range_x) ||
595 			    iatp_read_reg(sc, object->start_pos +
596 			    MXT_T100_YRANGE, sizeof(range_y), &range_y) ||
597 			    iatp_read_reg(sc, object->start_pos +
598 			    MXT_T100_CFG1, 1, &orient) ||
599 			    iatp_read_reg(sc, object->start_pos +
600 			    MXT_T100_TCHAUX, 1, &tchaux)) {
601 				printf("%s: failed reading t100 settings\n",
602 				    sc->sc_dev.dv_xname);
603 				continue;
604 			}
605 
606 			/*
607 			 * orient just affects the size we read, not the x/y
608 			 * values we read per-packet later.
609 			 */
610 			if (orient & MXT_T100_CFG_SWITCHXY) {
611 				sc->max_x = le16toh(range_y);
612 				sc->max_y = le16toh(range_x);
613 			} else {
614 				sc->max_x = le16toh(range_x);
615 				sc->max_y = le16toh(range_y);
616 			}
617 
618 			aux = 6;
619 			if (tchaux & MXT_T100_TCHAUX_VECT)
620 				sc->t100_aux_vect = aux++;
621 			if (tchaux & MXT_T100_TCHAUX_AMPL)
622 				sc->t100_aux_ampl = aux++;
623 			if (tchaux & MXT_T100_TCHAUX_AREA)
624 				sc->t100_aux_area = aux++;
625 			break;
626 		}
627 		}
628 	}
629 
630 	sc->info.max_report_id = reportid;
631 
632 	sc->sc_tsscale.minx = 0;
633 	sc->sc_tsscale.maxx = sc->max_x;
634 	sc->sc_tsscale.miny = 0;
635 	sc->sc_tsscale.maxy = sc->max_y;
636 	sc->sc_tsscale.swapxy = 0;
637 	sc->sc_tsscale.resx = 0;
638 	sc->sc_tsscale.resy = 0;
639 
640 	/*
641 	 * iatp_t44_read_count expects t5 message processor to immediately
642 	 * follow t44 message count byte
643 	 */
644 	if (sc->t44_address && (sc->t5_address != sc->t44_address + 1)) {
645 		printf("%s: t5 address (0x%x) != t44 (0x%x + 1)\n",
646 		    sc->sc_dev.dv_xname, sc->t5_address, sc->t44_address);
647 		return 0;
648 	}
649 
650 	sc->msg_buf = mallocarray(sc->info.max_report_id, sc->t5_msg_size,
651 	    M_DEVBUF, M_NOWAIT | M_ZERO);
652 
653 	/* flush queue of any pending messages */
654 	iatp_t5_read_msgs(sc, sc->info.max_report_id);
655 
656 	return 1;
657 }
658 
659 int
660 iatp_read_reg(struct iatp_softc *sc, uint16_t reg, size_t len, void *val)
661 {
662 	uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff };
663 	int ret;
664 
665 	iic_acquire_bus(sc->sc_tag, 0);
666 
667 	ret = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmd,
668 	    sizeof(cmd), val, len, I2C_F_POLL);
669 
670 	iic_release_bus(sc->sc_tag, 0);
671 
672 	return ret;
673 }
674 
675 int
676 iatp_write_reg(struct iatp_softc *sc, uint16_t reg, size_t len, void *val)
677 {
678 	int ret;
679 	uint8_t *cmd;
680 
681 	cmd = malloc(len + 2, M_DEVBUF, M_NOWAIT | M_ZERO);
682 	cmd[0] = reg & 0xff;
683 	cmd[1] = (reg >> 8) & 0xff;
684 	memcpy(&cmd[2], val, len);
685 
686 	iic_acquire_bus(sc->sc_tag, 0);
687 
688 	ret = iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_addr, cmd, len + 2,
689 	    NULL, 0, I2C_F_POLL);
690 
691 	iic_release_bus(sc->sc_tag, 0);
692 
693 	free(cmd, M_DEVBUF, sizeof(len + 2));
694 
695 	return ret;
696 }
697 
698 int
699 iatp_intr(void *arg)
700 {
701 	struct iatp_softc *sc = arg;
702 	int count;
703 
704 	DPRINTF(("%s: %s (busy:%d enabled:%d)\n", sc->sc_dev.dv_xname,
705 	    __func__, sc->sc_busy, sc->sc_enabled));
706 
707 	if (sc->sc_busy)
708 		return 1;
709 
710 	sc->sc_busy = 1;
711 
712 	if (sc->t44_address)
713 		count = iatp_t44_read_count(sc);
714 	else
715 		count = 1;
716 
717 	if (count)
718 		iatp_t5_read_msgs(sc, count);
719 
720 	sc->sc_busy = 0;
721 	wakeup(&sc->sc_busy);
722 
723 	return 1;
724 }
725 
726 int
727 iatp_proc_msg(struct iatp_softc *sc, uint8_t *msg)
728 {
729 	uint8_t report_id = msg[0];
730 	int i;
731 
732 	/* process a single message that has already been read off the wire */
733 
734 	if (report_id == 0xff)
735 		/*
736 		 * this is usually when we've intentionally over-read just to
737 		 * clear any pending data to keep interrupts flowing
738 		 */
739 		return 0;
740 
741 	DPRINTF(("%s: %s: report id %d\n", sc->sc_dev.dv_xname, __func__,
742 	    report_id));
743 
744 	if (report_id == sc->t19_reportid)
745 		iatp_t19_proc_msg(sc, msg);
746 	else if (report_id >= sc->t100_reportid_min &&
747 	    report_id <= sc->t100_reportid_max)
748 		iatp_t100_proc_msg(sc, msg);
749 	else {
750 		DPRINTF(("%s: unknown message (report id %d)",
751 		    sc->sc_dev.dv_xname, report_id));
752 		for (i = 0; i < sc->t5_msg_size; i++)
753 			DPRINTF((" %02x", msg[i]));
754 		DPRINTF(("\n"));
755 	}
756 
757 	return 1;
758 }
759 
760 int
761 iatp_t5_read_msgs(struct iatp_softc *sc, int count)
762 {
763 	int i;
764 
765 	if (count > sc->info.max_report_id) {
766 		DPRINTF(("%s: clamping count %d to max_report_id %d\n",
767 		    sc->sc_dev.dv_xname, count, sc->info.max_report_id));
768 		count = sc->info.max_report_id;
769 	}
770 
771 	DPRINTF(("%s: %s: %d message(s) to read\n", sc->sc_dev.dv_xname,
772 	    __func__, count));
773 
774 	if (iatp_read_reg(sc, sc->t5_address, sc->t5_msg_size * count,
775 	    sc->msg_buf)) {
776 		printf("%s: failed reading %d\n", sc->sc_dev.dv_xname,
777 		    sc->t5_msg_size * count);
778 		return 0;
779 	}
780 
781 	for (i = 0;  i < count; i++)
782 		iatp_proc_msg(sc, sc->msg_buf + (sc->t5_msg_size * i));
783 
784 	return 1;
785 }
786 
787 void
788 iatp_t6_proc_msg(struct iatp_softc *sc, uint8_t *msg)
789 {
790 	uint8_t status = msg[1];
791 
792 	if (status & MXT_T6_STATUS_RESET)
793 		DPRINTF(("%s: completed reset\n", sc->sc_dev.dv_xname));
794 	else
795 		DPRINTF(("%s: other status report 0x%x\n", sc->sc_dev.dv_xname,
796 		    status));
797 }
798 
799 int
800 iatp_t7_set_power_mode(struct iatp_softc *sc, int mode)
801 {
802 	struct mxt_t7_config new_config;
803 
804 	if (mode == MXT_T7_POWER_MODE_DEEP_SLEEP) {
805 		new_config.idle = 0;
806 		new_config.active = 0;
807 		new_config.atoi_timeout = 0;
808 	} else
809 		new_config = sc->t7_config;
810 
811 	DPRINTF(("%s: setting power mode to %d\n", sc->sc_dev.dv_xname, mode));
812 
813 	if (iatp_write_reg(sc, sc->t7_address, sizeof(new_config),
814 	    &new_config)) {
815 		printf("%s: failed setting power mode to %d\n",
816 		    sc->sc_dev.dv_xname, mode);
817 		return 1;
818 	}
819 
820 	return 0;
821 }
822 
823 void
824 iatp_t19_proc_msg(struct iatp_softc *sc, uint8_t *msg)
825 {
826 	int s;
827 
828 	if (!sc->sc_enabled)
829 		return;
830 
831 	/* active-low switch */
832 	sc->button = !(msg[1] & (1 << sc->t19_button_bit));
833 
834 	DPRINTF(("%s: button is %d\n", sc->sc_dev.dv_xname, sc->button));
835 
836 	s = spltty();
837 	wsmouse_buttons(sc->sc_wsmousedev, sc->button);
838 	wsmouse_input_sync(sc->sc_wsmousedev);
839 	splx(s);
840 }
841 
842 int
843 iatp_t44_read_count(struct iatp_softc *sc)
844 {
845 	int ret, count;
846 
847 	/* read t44 count byte and t5 message data in one shot */
848 	ret = iatp_read_reg(sc, sc->t44_address, 1 + sc->t5_msg_size,
849 	    sc->msg_buf);
850 	if (ret) {
851 		printf("%s: failed reading t44 and t5\n", sc->sc_dev.dv_xname);
852 		return 0;
853 	}
854 
855 	count = sc->msg_buf[0];
856 	if (count == 0) {
857 		DPRINTF(("%s: %s: no messages\n", sc->sc_dev.dv_xname,
858 		    __func__));
859 		/* flush so we keep getting interrupts */
860 		iatp_t5_read_msgs(sc, sc->info.max_report_id);
861 		return 0;
862 	}
863 
864 	count--;
865 	iatp_proc_msg(sc, sc->msg_buf + 1);
866 
867 	return count;
868 }
869 
870 void
871 iatp_t100_proc_msg(struct iatp_softc *sc, uint8_t *msg)
872 {
873 	int id = msg[0] - sc->t100_reportid_min - 2;
874 	int s;
875 	uint8_t status, type = 0, pressure = 0;
876 	uint16_t x, y;
877 
878 	if (id < 0 || !sc->sc_enabled)
879 		return;
880 
881 	status = msg[1];
882 	x = (msg[3] << 8) | msg[2];
883 	y = (msg[5] << 8) | msg[4];
884 
885 	if (status & MXT_T100_DETECT) {
886 		type = (status & MXT_T100_TYPE_MASK) >> 4;
887 
888 		if (sc->t100_aux_ampl)
889 			pressure = msg[sc->t100_aux_ampl];
890 
891 		if (!pressure && type != MXT_T100_TYPE_HOVERING_FINGER)
892 			pressure = 50; /* large enough for synaptics driver */
893 
894 		DPRINTF(("%s: type=%d x=%d y=%d finger=%d pressure=%d "
895 		    "button=%d\n", sc->sc_dev.dv_xname, type, x, y, id,
896 		    pressure, sc->button));
897 	} else {
898 		DPRINTF(("%s: closing slot for finger=%d\n",
899 		    sc->sc_dev.dv_xname, id));
900 
901 		if (sc->sc_touchpad)
902 			x = y = 0;
903 
904 		pressure = 0;
905 	}
906 
907 	if (sc->sc_touchpad)
908 		y = (sc->max_y - y);
909 
910 	/* TODO: adjust to sc_tsscale? */
911 
912 	s = spltty();
913 
914 	wsmouse_mtstate(sc->sc_wsmousedev, id, x, y, pressure);
915 
916 	/* on the touchscreen, assume any finger down is clicking */
917 	if (!sc->sc_touchpad)
918 		wsmouse_buttons(sc->sc_wsmousedev, pressure ? 1 : 0);
919 
920 	wsmouse_input_sync(sc->sc_wsmousedev);
921 
922 	splx(s);
923 }
924