Line data Source code
1 : /* $OpenBSD: iatp.c,v 1.6 2018/07/30 15:56:30 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 0 : iatp_match(struct device *parent, void *match, void *aux)
238 : {
239 0 : struct i2c_attach_args *ia = aux;
240 :
241 0 : if (strcmp(ia->ia_name, "iatp") == 0)
242 0 : return 1;
243 :
244 0 : return 0;
245 0 : }
246 :
247 : void
248 0 : iatp_attach(struct device *parent, struct device *self, void *aux)
249 : {
250 0 : struct iatp_softc *sc = (struct iatp_softc *)self;
251 0 : struct i2c_attach_args *ia = aux;
252 0 : struct wsmousedev_attach_args wsmaa;
253 :
254 0 : sc->sc_tag = ia->ia_tag;
255 0 : sc->sc_addr = ia->ia_addr;
256 :
257 0 : if (ia->ia_cookie != NULL)
258 0 : memcpy(&sc->sc_hid, ia->ia_cookie, sizeof(sc->sc_hid));
259 :
260 0 : if (!iatp_init(sc))
261 0 : return;
262 :
263 0 : if (ia->ia_intr) {
264 0 : printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr));
265 :
266 0 : sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr,
267 : IPL_TTY, iatp_intr, sc, sc->sc_dev.dv_xname);
268 0 : if (sc->sc_ih == NULL) {
269 0 : printf(", can't establish interrupt\n");
270 0 : return;
271 : }
272 : }
273 :
274 0 : printf(": Atmel maXTouch Touch%s (%dx%d)\n",
275 0 : sc->sc_touchpad ? "pad" : "screen", sc->max_x, sc->max_y);
276 :
277 0 : wsmaa.accessops = &iatp_accessops;
278 0 : wsmaa.accesscookie = sc;
279 0 : sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
280 0 : }
281 :
282 : int
283 0 : iatp_detach(struct device *self, int flags)
284 : {
285 0 : struct iatp_softc *sc = (struct iatp_softc *)self;
286 :
287 0 : if (sc->sc_ih != NULL) {
288 0 : intr_disestablish(sc->sc_ih);
289 0 : sc->sc_ih = NULL;
290 0 : }
291 :
292 0 : sc->sc_enabled = 0;
293 :
294 0 : return 0;
295 : }
296 :
297 : int
298 0 : iatp_activate(struct device *self, int act)
299 : {
300 0 : struct iatp_softc *sc = (struct iatp_softc *)self;
301 :
302 0 : 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 0 : sc->sc_busy = 1;
311 0 : iatp_init(sc);
312 0 : sc->sc_busy = 0;
313 0 : break;
314 : }
315 :
316 0 : config_activate_children(self, act);
317 :
318 0 : return 0;
319 : }
320 :
321 : int
322 0 : iatp_configure(struct iatp_softc *sc)
323 : {
324 : struct wsmousehw *hw;
325 :
326 0 : hw = wsmouse_get_hw(sc->sc_wsmousedev);
327 0 : if (sc->sc_touchpad) {
328 0 : hw->type = WSMOUSE_TYPE_TOUCHPAD;
329 0 : hw->hw_type = WSMOUSEHW_CLICKPAD;
330 0 : } else {
331 0 : hw->type = WSMOUSE_TYPE_TPANEL;
332 0 : hw->hw_type = WSMOUSEHW_TPANEL;
333 : }
334 0 : hw->x_min = sc->sc_tsscale.minx;
335 0 : hw->x_max = sc->sc_tsscale.maxx;
336 0 : hw->y_min = sc->sc_tsscale.miny;
337 0 : hw->y_max = sc->sc_tsscale.maxy;
338 0 : hw->h_res = sc->sc_tsscale.resx;
339 0 : hw->v_res = sc->sc_tsscale.resy;
340 0 : hw->mt_slots = sc->num_touchids;
341 :
342 0 : return (wsmouse_configure(sc->sc_wsmousedev, NULL, 0));
343 : }
344 :
345 : int
346 0 : iatp_enable(void *v)
347 : {
348 0 : struct iatp_softc *sc = v;
349 :
350 0 : if (sc->sc_busy && tsleep(&sc->sc_busy, PRIBIO, "iatp", hz) != 0) {
351 0 : printf("%s: trying to enable but we're busy\n",
352 0 : sc->sc_dev.dv_xname);
353 0 : return 1;
354 : }
355 :
356 0 : sc->sc_busy = 1;
357 :
358 : DPRINTF(("%s: enabling\n", sc->sc_dev.dv_xname));
359 :
360 0 : if (iatp_configure(sc)) {
361 0 : printf("%s: failed wsmouse_configure\n", sc->sc_dev.dv_xname);
362 0 : return 1;
363 : }
364 :
365 : /* force a read of any pending messages so we start getting new
366 : * interrupts */
367 0 : iatp_t5_read_msgs(sc, sc->info.max_report_id);
368 :
369 0 : sc->sc_enabled = 1;
370 0 : sc->sc_busy = 0;
371 :
372 0 : return 0;
373 0 : }
374 :
375 : void
376 0 : iatp_disable(void *v)
377 : {
378 0 : struct iatp_softc *sc = v;
379 :
380 : DPRINTF(("%s: disabling\n", sc->sc_dev.dv_xname));
381 :
382 0 : if (sc->sc_touchpad)
383 0 : wsmouse_set_mode(sc->sc_wsmousedev, WSMOUSE_COMPAT);
384 :
385 0 : sc->sc_enabled = 0;
386 0 : }
387 :
388 : int
389 0 : iatp_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
390 : {
391 0 : struct iatp_softc *sc = v;
392 0 : struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
393 : int wsmode;
394 :
395 : DPRINTF(("%s: %s: cmd %ld\n", sc->sc_dev.dv_xname, __func__, cmd));
396 :
397 0 : switch (cmd) {
398 : case WSMOUSEIO_SCALIBCOORDS:
399 0 : sc->sc_tsscale.minx = wsmc->minx;
400 0 : sc->sc_tsscale.maxx = wsmc->maxx;
401 0 : sc->sc_tsscale.miny = wsmc->miny;
402 0 : sc->sc_tsscale.maxy = wsmc->maxy;
403 0 : sc->sc_tsscale.swapxy = wsmc->swapxy;
404 0 : sc->sc_tsscale.resx = wsmc->resx;
405 0 : sc->sc_tsscale.resy = wsmc->resy;
406 0 : break;
407 :
408 : case WSMOUSEIO_GCALIBCOORDS:
409 0 : wsmc->minx = sc->sc_tsscale.minx;
410 0 : wsmc->maxx = sc->sc_tsscale.maxx;
411 0 : wsmc->miny = sc->sc_tsscale.miny;
412 0 : wsmc->maxy = sc->sc_tsscale.maxy;
413 0 : wsmc->swapxy = sc->sc_tsscale.swapxy;
414 0 : wsmc->resx = sc->sc_tsscale.resx;
415 0 : wsmc->resy = sc->sc_tsscale.resy;
416 0 : break;
417 :
418 : case WSMOUSEIO_GTYPE: {
419 0 : struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
420 0 : *(u_int *)data = hw->type;
421 : break;
422 : }
423 :
424 : case WSMOUSEIO_SETMODE:
425 0 : if (!sc->sc_touchpad)
426 0 : return -1;
427 :
428 0 : wsmode = *(u_int *)data;
429 0 : if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) {
430 0 : printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname,
431 : wsmode);
432 0 : return EINVAL;
433 : }
434 0 : wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
435 0 : break;
436 :
437 : default:
438 0 : return -1;
439 : }
440 :
441 0 : return 0;
442 0 : }
443 :
444 : int
445 0 : iatp_init(struct iatp_softc *sc)
446 : {
447 : uint8_t reportid;
448 : int i;
449 :
450 0 : sc->sc_enabled = 0;
451 :
452 : /* some sane defaults */
453 0 : sc->num_touchids = 10;
454 0 : sc->max_x = 1023;
455 0 : sc->max_y = 1023;
456 0 : sc->sc_touchpad = 0;
457 :
458 : /*
459 : * AT42QT1085 Information block:
460 : *
461 : * ID information (struct mxt_id_info)
462 : * 0 Family ID
463 : * 1 Variant ID
464 : * 2 Version
465 : * 3 Build
466 : * 4 Number of Keys
467 : * 5 1
468 : * 6 Number of Object Table Elements
469 : * Object Table Element 1 (struct mxt_object)
470 : * 7 Object Type
471 : * 8-9 Object Start Address
472 : * 10 Size - 1
473 : * 11 Instances - 1
474 : * 12 Number of report IDs per instance
475 : * Object Table Element 2 (struct mxt_object)
476 : * ...
477 : * Information Block Checksum
478 : * [ Object 1 ]
479 : * ...
480 : */
481 :
482 : /* read table header */
483 0 : if (iatp_read_reg(sc, 0, sizeof(struct mxt_id_info), &sc->info.id) ||
484 0 : !sc->info.id.num_objects) {
485 0 : printf("%s: failed reading main memory map\n",
486 0 : sc->sc_dev.dv_xname);
487 0 : return 0;
488 : }
489 :
490 0 : sc->table_size = sc->info.id.num_objects * sizeof(struct mxt_object);
491 0 : sc->table = malloc(sc->table_size, M_DEVBUF, M_NOWAIT | M_ZERO);
492 :
493 : /* read all table objects */
494 0 : if (iatp_read_reg(sc, sizeof(struct mxt_id_info), sc->table_size,
495 : sc->table)) {
496 0 : printf("%s: failed reading info table of size %zu\n",
497 0 : sc->sc_dev.dv_xname, sc->table_size);
498 0 : return 0;
499 : }
500 :
501 : reportid = 1;
502 0 : for (i = 0; i < sc->info.id.num_objects; i++) {
503 0 : struct mxt_object *object = (void *)(sc->table +
504 0 : (sizeof(struct mxt_object) * i));
505 : int min_id = 0, max_id = 0;
506 :
507 0 : if (object->num_report_ids) {
508 0 : min_id = reportid;
509 0 : reportid += (object->num_report_ids *
510 0 : (uint8_t)MXT_INSTANCES(object));
511 0 : max_id = reportid - 1;
512 0 : }
513 :
514 : DPRINTF(("%s: object[%d] T%d at 0x%x, %d report ids (%d-%d)\n",
515 : sc->sc_dev.dv_xname, i, object->type,
516 : le16toh(object->start_pos), object->num_report_ids, min_id,
517 : max_id));
518 :
519 0 : switch (object->type) {
520 : case MXT_GEN_MESSAGEPROCESSOR_T5:
521 : /*
522 : * 4.2 - message processor is what interrupts and
523 : * relays new messages to us
524 : */
525 :
526 0 : if (sc->info.id.family == 0x80 &&
527 0 : sc->info.id.version < 0x20)
528 : /*
529 : * from linux: "On mXT224 firmware versions
530 : * prior to V2.0 read and discard unused CRC
531 : * byte otherwise DMA reads are misaligned."
532 : */
533 0 : sc->t5_msg_size = MXT_SIZE(object);
534 : else
535 0 : sc->t5_msg_size = MXT_SIZE(object) - 1;
536 :
537 0 : sc->t5_address = le16toh(object->start_pos);
538 0 : break;
539 :
540 : case MXT_GEN_COMMANDPROCESSOR_T6:
541 : /*
542 : * 4.3 - command processor receives commands from us
543 : * and reports command status messages
544 : */
545 0 : sc->t6_address = le16toh(object->start_pos);
546 0 : sc->t6_reportid = min_id;
547 0 : break;
548 :
549 : case MXT_GEN_POWERCONFIG_T7:
550 : /*
551 : * 4.4 - power configuration, number of milliseconds
552 : * between sampling in each mode
553 : */
554 0 : sc->t7_address = le16toh(object->start_pos);
555 :
556 0 : iatp_read_reg(sc, sc->t7_address,
557 0 : sizeof(sc->t7_config), &sc->t7_config);
558 :
559 0 : break;
560 :
561 : case MXT_SPT_GPIOPWM_T19: {
562 : /*
563 : * generic gpio pin, mapped to touchpad button(s)
564 : */
565 : const struct mxt_t19_button_map *m;
566 :
567 0 : sc->t19_reportid = min_id;
568 :
569 : /* find this machine's button config */
570 0 : sc->t19_button_bit = -1;
571 0 : if (hw_vendor == NULL || hw_prod == NULL)
572 0 : break;
573 :
574 0 : for (m = mxt_t19_button_map_devs; m->vendor != NULL;
575 0 : m++) {
576 0 : if (strncmp(hw_vendor, m->vendor,
577 0 : strlen(m->vendor)) != 0 ||
578 0 : strncmp(hw_prod, m->product,
579 0 : strlen(m->product)) != 0 ||
580 0 : strncmp(sc->sc_hid, m->hid,
581 0 : strlen(m->hid)) != 0)
582 : continue;
583 :
584 : DPRINTF(("%s: found matching t19 "
585 : "button map device \"%s\"/\"%s\" on %s: "
586 : "bit %d\n", sc->sc_dev.dv_xname,
587 : m->vendor, m->product, m->hid, m->bit));
588 0 : sc->t19_button_bit = m->bit;
589 0 : break;
590 : }
591 :
592 0 : if (sc->t19_button_bit > -1)
593 0 : sc->sc_touchpad = 1;
594 :
595 0 : break;
596 : }
597 :
598 : case MXT_SPT_MESSAGECOUNT_T44:
599 0 : sc->t44_address = le16toh(object->start_pos);
600 0 : break;
601 :
602 : case MXT_TOUCH_MULTITOUCHSCREEN_T100: {
603 0 : uint16_t range_x, range_y;
604 0 : uint8_t orient, tchaux;
605 : int aux;
606 :
607 0 : sc->t100_reportid_min = min_id;
608 0 : sc->t100_reportid_max = max_id;
609 0 : sc->num_touchids = object->num_report_ids - 2;
610 0 : sc->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
611 :
612 0 : if (iatp_read_reg(sc, object->start_pos +
613 0 : MXT_T100_XRANGE, sizeof(range_x), &range_x) ||
614 0 : iatp_read_reg(sc, object->start_pos +
615 0 : MXT_T100_YRANGE, sizeof(range_y), &range_y) ||
616 0 : iatp_read_reg(sc, object->start_pos +
617 0 : MXT_T100_CFG1, 1, &orient) ||
618 0 : iatp_read_reg(sc, object->start_pos +
619 : MXT_T100_TCHAUX, 1, &tchaux)) {
620 0 : printf("%s: failed reading t100 settings\n",
621 0 : sc->sc_dev.dv_xname);
622 0 : continue;
623 : }
624 :
625 : /*
626 : * orient just affects the size we read, not the x/y
627 : * values we read per-packet later.
628 : */
629 0 : if (orient & MXT_T100_CFG_SWITCHXY) {
630 0 : sc->max_x = le16toh(range_y);
631 0 : sc->max_y = le16toh(range_x);
632 0 : } else {
633 0 : sc->max_x = le16toh(range_x);
634 0 : sc->max_y = le16toh(range_y);
635 : }
636 :
637 : aux = 6;
638 0 : if (tchaux & MXT_T100_TCHAUX_VECT)
639 0 : sc->t100_aux_vect = aux++;
640 0 : if (tchaux & MXT_T100_TCHAUX_AMPL)
641 0 : sc->t100_aux_ampl = aux++;
642 0 : if (tchaux & MXT_T100_TCHAUX_AREA)
643 0 : sc->t100_aux_area = aux++;
644 0 : break;
645 0 : }
646 : }
647 0 : }
648 :
649 0 : sc->info.max_report_id = reportid;
650 :
651 0 : sc->sc_tsscale.minx = 0;
652 0 : sc->sc_tsscale.maxx = sc->max_x;
653 0 : sc->sc_tsscale.miny = 0;
654 0 : sc->sc_tsscale.maxy = sc->max_y;
655 0 : sc->sc_tsscale.swapxy = 0;
656 0 : sc->sc_tsscale.resx = 0;
657 0 : sc->sc_tsscale.resy = 0;
658 :
659 : /*
660 : * iatp_t44_read_count expects t5 message processor to immediately
661 : * follow t44 message count byte
662 : */
663 0 : if (sc->t44_address && (sc->t5_address != sc->t44_address + 1)) {
664 0 : printf("%s: t5 address (0x%x) != t44 (0x%x + 1)\n",
665 0 : sc->sc_dev.dv_xname, sc->t5_address, sc->t44_address);
666 0 : return 0;
667 : }
668 :
669 0 : sc->msg_buf = mallocarray(sc->info.max_report_id, sc->t5_msg_size,
670 : M_DEVBUF, M_NOWAIT | M_ZERO);
671 :
672 : /* flush queue of any pending messages */
673 0 : iatp_t5_read_msgs(sc, sc->info.max_report_id);
674 :
675 0 : return 1;
676 0 : }
677 :
678 : int
679 0 : iatp_read_reg(struct iatp_softc *sc, uint16_t reg, size_t len, void *val)
680 : {
681 0 : uint8_t cmd[2] = { reg & 0xff, (reg >> 8) & 0xff };
682 : int ret;
683 :
684 0 : iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
685 :
686 0 : ret = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmd,
687 : sizeof(cmd), val, len, I2C_F_POLL);
688 :
689 0 : iic_release_bus(sc->sc_tag, I2C_F_POLL);
690 :
691 0 : return ret;
692 0 : }
693 :
694 : int
695 0 : iatp_write_reg(struct iatp_softc *sc, uint16_t reg, size_t len, void *val)
696 : {
697 : int ret;
698 : uint8_t *cmd;
699 :
700 0 : cmd = malloc(len + 2, M_DEVBUF, M_NOWAIT | M_ZERO);
701 0 : cmd[0] = reg & 0xff;
702 0 : cmd[1] = (reg >> 8) & 0xff;
703 0 : memcpy(&cmd[2], val, len);
704 :
705 0 : iic_acquire_bus(sc->sc_tag, 0);
706 :
707 0 : ret = iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_addr, cmd, len + 2,
708 : NULL, 0, I2C_F_POLL);
709 :
710 0 : iic_release_bus(sc->sc_tag, 0);
711 :
712 0 : free(cmd, M_DEVBUF, len + 2);
713 :
714 0 : return ret;
715 : }
716 :
717 : int
718 0 : iatp_intr(void *arg)
719 : {
720 0 : struct iatp_softc *sc = arg;
721 : int count;
722 :
723 : DPRINTF(("%s: %s (busy:%d enabled:%d)\n", sc->sc_dev.dv_xname,
724 : __func__, sc->sc_busy, sc->sc_enabled));
725 :
726 0 : if (sc->sc_busy)
727 0 : return 1;
728 :
729 0 : sc->sc_busy = 1;
730 :
731 0 : if (sc->t44_address)
732 0 : count = iatp_t44_read_count(sc);
733 : else
734 : count = 1;
735 :
736 0 : if (count)
737 0 : iatp_t5_read_msgs(sc, count);
738 :
739 0 : sc->sc_busy = 0;
740 0 : wakeup(&sc->sc_busy);
741 :
742 0 : return 1;
743 0 : }
744 :
745 : int
746 0 : iatp_proc_msg(struct iatp_softc *sc, uint8_t *msg)
747 : {
748 0 : uint8_t report_id = msg[0];
749 : int i;
750 :
751 : /* process a single message that has already been read off the wire */
752 :
753 0 : if (report_id == 0xff)
754 : /*
755 : * this is usually when we've intentionally over-read just to
756 : * clear any pending data to keep interrupts flowing
757 : */
758 0 : return 0;
759 :
760 : DPRINTF(("%s: %s: report id %d\n", sc->sc_dev.dv_xname, __func__,
761 : report_id));
762 :
763 0 : if (report_id == sc->t19_reportid)
764 0 : iatp_t19_proc_msg(sc, msg);
765 0 : else if (report_id >= sc->t100_reportid_min &&
766 0 : report_id <= sc->t100_reportid_max)
767 0 : iatp_t100_proc_msg(sc, msg);
768 : else {
769 : DPRINTF(("%s: unknown message (report id %d)",
770 : sc->sc_dev.dv_xname, report_id));
771 0 : for (i = 0; i < sc->t5_msg_size; i++)
772 : DPRINTF((" %02x", msg[i]));
773 : DPRINTF(("\n"));
774 : }
775 :
776 0 : return 1;
777 0 : }
778 :
779 : int
780 0 : iatp_t5_read_msgs(struct iatp_softc *sc, int count)
781 : {
782 : int i;
783 :
784 0 : if (count > sc->info.max_report_id) {
785 : DPRINTF(("%s: clamping count %d to max_report_id %d\n",
786 : sc->sc_dev.dv_xname, count, sc->info.max_report_id));
787 : count = sc->info.max_report_id;
788 0 : }
789 :
790 : DPRINTF(("%s: %s: %d message(s) to read\n", sc->sc_dev.dv_xname,
791 : __func__, count));
792 :
793 0 : if (iatp_read_reg(sc, sc->t5_address, sc->t5_msg_size * count,
794 0 : sc->msg_buf)) {
795 0 : printf("%s: failed reading %d\n", sc->sc_dev.dv_xname,
796 0 : sc->t5_msg_size * count);
797 0 : return 0;
798 : }
799 :
800 0 : for (i = 0; i < count; i++)
801 0 : iatp_proc_msg(sc, sc->msg_buf + (sc->t5_msg_size * i));
802 :
803 0 : return 1;
804 0 : }
805 :
806 : void
807 0 : iatp_t6_proc_msg(struct iatp_softc *sc, uint8_t *msg)
808 : {
809 0 : uint8_t status = msg[1];
810 :
811 : if (status & MXT_T6_STATUS_RESET)
812 : DPRINTF(("%s: completed reset\n", sc->sc_dev.dv_xname));
813 : else
814 : DPRINTF(("%s: other status report 0x%x\n", sc->sc_dev.dv_xname,
815 : status));
816 0 : }
817 :
818 : int
819 0 : iatp_t7_set_power_mode(struct iatp_softc *sc, int mode)
820 : {
821 0 : struct mxt_t7_config new_config;
822 :
823 0 : if (mode == MXT_T7_POWER_MODE_DEEP_SLEEP) {
824 0 : new_config.idle = 0;
825 0 : new_config.active = 0;
826 0 : new_config.atoi_timeout = 0;
827 0 : } else
828 0 : new_config = sc->t7_config;
829 :
830 : DPRINTF(("%s: setting power mode to %d\n", sc->sc_dev.dv_xname, mode));
831 :
832 0 : if (iatp_write_reg(sc, sc->t7_address, sizeof(new_config),
833 : &new_config)) {
834 0 : printf("%s: failed setting power mode to %d\n",
835 0 : sc->sc_dev.dv_xname, mode);
836 0 : return 1;
837 : }
838 :
839 0 : return 0;
840 0 : }
841 :
842 : void
843 0 : iatp_t19_proc_msg(struct iatp_softc *sc, uint8_t *msg)
844 : {
845 : int s;
846 :
847 0 : if (!sc->sc_enabled)
848 0 : return;
849 :
850 : /* active-low switch */
851 0 : sc->button = !(msg[1] & (1 << sc->t19_button_bit));
852 :
853 : DPRINTF(("%s: button is %d\n", sc->sc_dev.dv_xname, sc->button));
854 :
855 0 : s = spltty();
856 0 : wsmouse_buttons(sc->sc_wsmousedev, sc->button);
857 0 : wsmouse_input_sync(sc->sc_wsmousedev);
858 0 : splx(s);
859 0 : }
860 :
861 : int
862 0 : iatp_t44_read_count(struct iatp_softc *sc)
863 : {
864 : int ret, count;
865 :
866 : /* read t44 count byte and t5 message data in one shot */
867 0 : ret = iatp_read_reg(sc, sc->t44_address, 1 + sc->t5_msg_size,
868 0 : sc->msg_buf);
869 0 : if (ret) {
870 0 : printf("%s: failed reading t44 and t5\n", sc->sc_dev.dv_xname);
871 0 : return 0;
872 : }
873 :
874 0 : count = sc->msg_buf[0];
875 0 : if (count == 0) {
876 : DPRINTF(("%s: %s: no messages\n", sc->sc_dev.dv_xname,
877 : __func__));
878 : /* flush so we keep getting interrupts */
879 0 : iatp_t5_read_msgs(sc, sc->info.max_report_id);
880 0 : return 0;
881 : }
882 :
883 0 : count--;
884 0 : iatp_proc_msg(sc, sc->msg_buf + 1);
885 :
886 0 : return count;
887 0 : }
888 :
889 : void
890 0 : iatp_t100_proc_msg(struct iatp_softc *sc, uint8_t *msg)
891 : {
892 0 : int id = msg[0] - sc->t100_reportid_min - 2;
893 : int s;
894 : uint8_t status, type = 0, pressure = 0;
895 : uint16_t x, y;
896 :
897 0 : if (id < 0 || !sc->sc_enabled)
898 0 : return;
899 :
900 0 : status = msg[1];
901 0 : x = (msg[3] << 8) | msg[2];
902 0 : y = (msg[5] << 8) | msg[4];
903 :
904 0 : if (status & MXT_T100_DETECT) {
905 0 : type = (status & MXT_T100_TYPE_MASK) >> 4;
906 :
907 0 : if (sc->t100_aux_ampl)
908 0 : pressure = msg[sc->t100_aux_ampl];
909 :
910 0 : if (!pressure && type != MXT_T100_TYPE_HOVERING_FINGER)
911 0 : pressure = 50; /* large enough for synaptics driver */
912 :
913 : DPRINTF(("%s: type=%d x=%d y=%d finger=%d pressure=%d "
914 : "button=%d\n", sc->sc_dev.dv_xname, type, x, y, id,
915 : pressure, sc->button));
916 : } else {
917 : DPRINTF(("%s: closing slot for finger=%d\n",
918 : sc->sc_dev.dv_xname, id));
919 :
920 0 : if (sc->sc_touchpad)
921 0 : x = y = 0;
922 :
923 : pressure = 0;
924 : }
925 :
926 0 : if (sc->sc_touchpad)
927 0 : y = (sc->max_y - y);
928 :
929 : /* TODO: adjust to sc_tsscale? */
930 :
931 0 : s = spltty();
932 :
933 0 : wsmouse_mtstate(sc->sc_wsmousedev, id, x, y, pressure);
934 :
935 : /* on the touchscreen, assume any finger down is clicking */
936 0 : if (!sc->sc_touchpad)
937 0 : wsmouse_buttons(sc->sc_wsmousedev, pressure ? 1 : 0);
938 :
939 0 : wsmouse_input_sync(sc->sc_wsmousedev);
940 :
941 0 : splx(s);
942 0 : }
|