LCOV - code coverage report
Current view: top level - dev/i2c - iatp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 339 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13