The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/hid/hmt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2014-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 /*
   32  * MS Windows 7/8/10 compatible HID Multi-touch Device driver.
   33  * https://msdn.microsoft.com/en-us/library/windows/hardware/jj151569(v=vs.85).aspx
   34  * http://download.microsoft.com/download/7/d/d/7dd44bb7-2a7a-4505-ac1c-7227d3d96d5b/hid-over-i2c-protocol-spec-v1-0.docx
   35  * https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
   36  */
   37 
   38 #include "opt_hid.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/bus.h>
   42 #include <sys/kernel.h>
   43 #include <sys/lock.h>
   44 #include <sys/malloc.h>
   45 #include <sys/module.h>
   46 #include <sys/mutex.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/systm.h>
   49 
   50 #include <dev/evdev/evdev.h>
   51 #include <dev/evdev/input.h>
   52 
   53 #define HID_DEBUG_VAR   hmt_debug
   54 #include <dev/hid/hid.h>
   55 #include <dev/hid/hidbus.h>
   56 #include <dev/hid/hidquirk.h>
   57 
   58 #include <dev/hid/hconf.h>
   59 
   60 static SYSCTL_NODE(_hw_hid, OID_AUTO, hmt, CTLFLAG_RW, 0,
   61     "MSWindows 7/8/10 compatible HID Multi-touch Device");
   62 #ifdef HID_DEBUG
   63 static int hmt_debug = 0;
   64 SYSCTL_INT(_hw_hid_hmt, OID_AUTO, debug, CTLFLAG_RWTUN,
   65     &hmt_debug, 1, "Debug level");
   66 #endif
   67 static bool hmt_timestamps = 0;
   68 SYSCTL_BOOL(_hw_hid_hmt, OID_AUTO, timestamps, CTLFLAG_RDTUN,
   69     &hmt_timestamps, 1, "Enable hardware timestamp reporting");
   70 
   71 #define HMT_BTN_MAX     8       /* Number of buttons supported */
   72 
   73 enum hmt_type {
   74         HMT_TYPE_UNKNOWN = 0,   /* HID report descriptor is not probed */
   75         HMT_TYPE_UNSUPPORTED,   /* Repdescr does not belong to MT device */
   76         HMT_TYPE_TOUCHPAD,
   77         HMT_TYPE_TOUCHSCREEN,
   78 };
   79 
   80 enum {
   81         HMT_TIP_SWITCH,
   82 #define HMT_SLOT        HMT_TIP_SWITCH
   83         HMT_WIDTH,
   84 #define HMT_MAJOR       HMT_WIDTH
   85         HMT_HEIGHT,
   86 #define HMT_MINOR       HMT_HEIGHT
   87         HMT_ORIENTATION,
   88         HMT_X,
   89         HMT_Y,
   90         HMT_CONTACTID,
   91         HMT_PRESSURE,
   92         HMT_IN_RANGE,
   93         HMT_CONFIDENCE,
   94         HMT_TOOL_X,
   95         HMT_TOOL_Y,
   96         HMT_N_USAGES,
   97 };
   98 
   99 #define HMT_NO_CODE     (ABS_MAX + 10)
  100 #define HMT_NO_USAGE    -1
  101 
  102 struct hmt_hid_map_item {
  103         char            name[5];
  104         int32_t         usage;          /* HID usage */
  105         uint32_t        code;           /* Evdev event code */
  106         bool            required;       /* Required for MT Digitizers */
  107 };
  108 
  109 static const struct hmt_hid_map_item hmt_hid_map[HMT_N_USAGES] = {
  110         [HMT_TIP_SWITCH] = {    /* HMT_SLOT */
  111                 .name = "TIP",
  112                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH),
  113                 .code = ABS_MT_SLOT,
  114                 .required = true,
  115         },
  116         [HMT_WIDTH] = {         /* HMT_MAJOR */
  117                 .name = "WDTH",
  118                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_WIDTH),
  119                 .code = ABS_MT_TOUCH_MAJOR,
  120                 .required = false,
  121         },
  122         [HMT_HEIGHT] = {        /* HMT_MINOR */
  123                 .name = "HGHT",
  124                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_HEIGHT),
  125                 .code = ABS_MT_TOUCH_MINOR,
  126                 .required = false,
  127         },
  128         [HMT_ORIENTATION] = {
  129                 .name = "ORIE",
  130                 .usage = HMT_NO_USAGE,
  131                 .code = ABS_MT_ORIENTATION,
  132                 .required = false,
  133         },
  134         [HMT_X] = {
  135                 .name = "X",
  136                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
  137                 .code = ABS_MT_POSITION_X,
  138                 .required = true,
  139         },
  140         [HMT_Y] = {
  141                 .name = "Y",
  142                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
  143                 .code = ABS_MT_POSITION_Y,
  144                 .required = true,
  145         },
  146         [HMT_CONTACTID] = {
  147                 .name = "C_ID",
  148                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
  149                 .code = ABS_MT_TRACKING_ID,
  150                 .required = true,
  151         },
  152         [HMT_PRESSURE] = {
  153                 .name = "PRES",
  154                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_PRESSURE),
  155                 .code = ABS_MT_PRESSURE,
  156                 .required = false,
  157         },
  158         [HMT_IN_RANGE] = {
  159                 .name = "RANG",
  160                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE),
  161                 .code = ABS_MT_DISTANCE,
  162                 .required = false,
  163         },
  164         [HMT_CONFIDENCE] = {
  165                 .name = "CONF",
  166                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE),
  167                 .code = HMT_NO_CODE,
  168                 .required = false,
  169         },
  170         [HMT_TOOL_X] = {        /* Shares HID usage with HMT_X */
  171                 .name = "TL_X",
  172                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
  173                 .code = ABS_MT_TOOL_X,
  174                 .required = false,
  175         },
  176         [HMT_TOOL_Y] = {        /* Shares HID usage with HMT_Y */
  177                 .name = "TL_Y",
  178                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
  179                 .code = ABS_MT_TOOL_Y,
  180                 .required = false,
  181         },
  182 };
  183 
  184 struct hmt_softc {
  185         device_t                dev;
  186         enum hmt_type           type;
  187 
  188         struct hid_absinfo      ai[HMT_N_USAGES];
  189         struct hid_location     locs[MAX_MT_SLOTS][HMT_N_USAGES];
  190         struct hid_location     cont_count_loc;
  191         struct hid_location     btn_loc[HMT_BTN_MAX];
  192         struct hid_location     int_btn_loc;
  193         struct hid_location     scan_time_loc;
  194         int32_t                 scan_time_max;
  195         int32_t                 scan_time;
  196         int32_t                 timestamp;
  197         bool                    touch;
  198         bool                    prev_touch;
  199 
  200         struct evdev_dev        *evdev;
  201 
  202         uint32_t                slot_data[HMT_N_USAGES];
  203         uint8_t                 caps[howmany(HMT_N_USAGES, 8)];
  204         uint8_t                 buttons[howmany(HMT_BTN_MAX, 8)];
  205         uint32_t                nconts_per_report;
  206         uint32_t                nconts_todo;
  207         uint8_t                 report_id;
  208         uint32_t                max_button;
  209         bool                    has_int_button;
  210         bool                    is_clickpad;
  211         bool                    do_timestamps;
  212 #ifdef IICHID_SAMPLING
  213         bool                    iichid_sampling;
  214 #endif
  215 
  216         struct hid_location     cont_max_loc;
  217         uint32_t                cont_max_rlen;
  218         uint8_t                 cont_max_rid;
  219         struct hid_location     btn_type_loc;
  220         uint32_t                btn_type_rlen;
  221         uint8_t                 btn_type_rid;
  222         uint32_t                thqa_cert_rlen;
  223         uint8_t                 thqa_cert_rid;
  224 };
  225 
  226 #define HMT_FOREACH_USAGE(caps, usage)                  \
  227         for ((usage) = 0; (usage) < HMT_N_USAGES; ++(usage))    \
  228                 if (isset((caps), (usage)))
  229 
  230 static enum hmt_type hmt_hid_parse(struct hmt_softc *, const void *,
  231     hid_size_t, uint32_t, uint8_t);
  232 static int hmt_set_input_mode(struct hmt_softc *, enum hconf_input_mode);
  233 
  234 static hid_intr_t       hmt_intr;
  235 
  236 static device_probe_t   hmt_probe;
  237 static device_attach_t  hmt_attach;
  238 static device_detach_t  hmt_detach;
  239 
  240 static evdev_open_t     hmt_ev_open;
  241 static evdev_close_t    hmt_ev_close;
  242 
  243 static const struct evdev_methods hmt_evdev_methods = {
  244         .ev_open = &hmt_ev_open,
  245         .ev_close = &hmt_ev_close,
  246 };
  247 
  248 static const struct hid_device_id hmt_devs[] = {
  249         { HID_TLC(HUP_DIGITIZERS, HUD_TOUCHSCREEN) },
  250         { HID_TLC(HUP_DIGITIZERS, HUD_TOUCHPAD) },
  251 };
  252 
  253 static int
  254 hmt_ev_close(struct evdev_dev *evdev)
  255 {
  256         return (hidbus_intr_stop(evdev_get_softc(evdev)));
  257 }
  258 
  259 static int
  260 hmt_ev_open(struct evdev_dev *evdev)
  261 {
  262         return (hidbus_intr_start(evdev_get_softc(evdev)));
  263 }
  264 
  265 static int
  266 hmt_probe(device_t dev)
  267 {
  268         struct hmt_softc *sc = device_get_softc(dev);
  269         void *d_ptr;
  270         hid_size_t d_len;
  271         int err;
  272 
  273         err = HIDBUS_LOOKUP_DRIVER_INFO(dev, hmt_devs);
  274         if (err != 0)
  275                 return (err);
  276 
  277         err = hid_get_report_descr(dev, &d_ptr, &d_len);
  278         if (err != 0) {
  279                 device_printf(dev, "could not retrieve report descriptor from "
  280                      "device: %d\n", err);
  281                 return (ENXIO);
  282         }
  283 
  284         /* Check if report descriptor belongs to a HID multitouch device */
  285         if (sc->type == HMT_TYPE_UNKNOWN)
  286                 sc->type = hmt_hid_parse(sc, d_ptr, d_len,
  287                     hidbus_get_usage(dev), hidbus_get_index(dev));
  288         if (sc->type == HMT_TYPE_UNSUPPORTED)
  289                 return (ENXIO);
  290 
  291         hidbus_set_desc(dev,
  292             sc->type == HMT_TYPE_TOUCHPAD ? "TouchPad" : "TouchScreen");
  293 
  294         return (BUS_PROBE_DEFAULT);
  295 }
  296 
  297 static int
  298 hmt_attach(device_t dev)
  299 {
  300         struct hmt_softc *sc = device_get_softc(dev);
  301         const struct hid_device_info *hw = hid_get_device_info(dev);
  302         void *d_ptr;
  303         uint8_t *fbuf = NULL;
  304         hid_size_t d_len, fsize;
  305         uint32_t cont_count_max;
  306         int nbuttons, btn;
  307         size_t i;
  308         int err;
  309 
  310         err = hid_get_report_descr(dev, &d_ptr, &d_len);
  311         if (err != 0) {
  312                 device_printf(dev, "could not retrieve report descriptor from "
  313                     "device: %d\n", err);
  314                 return (ENXIO);
  315         }
  316 
  317         sc->dev = dev;
  318 
  319         fsize = hid_report_size_max(d_ptr, d_len, hid_feature, NULL);
  320         if (fsize != 0)
  321                 fbuf = malloc(fsize, M_TEMP, M_WAITOK | M_ZERO);
  322 
  323         /* Fetch and parse "Contact count maximum" feature report */
  324         if (sc->cont_max_rlen > 1) {
  325                 err = hid_get_report(dev, fbuf, sc->cont_max_rlen, NULL,
  326                     HID_FEATURE_REPORT, sc->cont_max_rid);
  327                 if (err == 0) {
  328                         cont_count_max = hid_get_udata(fbuf + 1,
  329                             sc->cont_max_rlen - 1, &sc->cont_max_loc);
  330                         /*
  331                          * Feature report is a primary source of
  332                          * 'Contact Count Maximum'
  333                          */
  334                         if (cont_count_max > 0)
  335                                 sc->ai[HMT_SLOT].max = cont_count_max - 1;
  336                 } else
  337                         DPRINTF("hid_get_report error=%d\n", err);
  338         } else
  339                 DPRINTF("Feature report %hhu size invalid: %u\n",
  340                     sc->cont_max_rid, sc->cont_max_rlen);
  341 
  342         /* Fetch and parse "Button type" feature report */
  343         if (sc->btn_type_rlen > 1 && sc->btn_type_rid != sc->cont_max_rid) {
  344                 bzero(fbuf, fsize);
  345                 err = hid_get_report(dev, fbuf, sc->btn_type_rlen, NULL,
  346                     HID_FEATURE_REPORT, sc->btn_type_rid);
  347         }
  348         if (sc->btn_type_rlen > 1) {
  349                 if (err == 0)
  350                         sc->is_clickpad = hid_get_udata(fbuf + 1,
  351                             sc->btn_type_rlen - 1, &sc->btn_type_loc) == 0;
  352                 else
  353                         DPRINTF("hid_get_report error=%d\n", err);
  354         }
  355 
  356         /* Fetch THQA certificate to enable some devices like WaveShare */
  357         if (sc->thqa_cert_rlen > 1 && sc->thqa_cert_rid != sc->cont_max_rid)
  358                 (void)hid_get_report(dev, fbuf, sc->thqa_cert_rlen, NULL,
  359                     HID_FEATURE_REPORT, sc->thqa_cert_rid);
  360 
  361         free(fbuf, M_TEMP);
  362 
  363         /* Switch touchpad in to absolute multitouch mode */
  364         if (sc->type == HMT_TYPE_TOUCHPAD) {
  365                 err = hmt_set_input_mode(sc, HCONF_INPUT_MODE_MT_TOUCHPAD);
  366                 if (err != 0)
  367                         DPRINTF("Failed to set input mode: %d\n", err);
  368         }
  369 
  370         /* Cap contact count maximum to MAX_MT_SLOTS */
  371         if (sc->ai[HMT_SLOT].max >= MAX_MT_SLOTS) {
  372                 DPRINTF("Hardware reported %d contacts while only %d is "
  373                     "supported\n", (int)sc->ai[HMT_SLOT].max+1, MAX_MT_SLOTS);
  374                 sc->ai[HMT_SLOT].max = MAX_MT_SLOTS - 1;
  375         }
  376 
  377         if (hid_test_quirk(hw, HQ_MT_TIMESTAMP) || hmt_timestamps)
  378                 sc->do_timestamps = true;
  379 #ifdef IICHID_SAMPLING
  380         if (hid_test_quirk(hw, HQ_IICHID_SAMPLING))
  381                 sc->iichid_sampling = true;
  382 #endif
  383 
  384         hidbus_set_intr(dev, hmt_intr, sc);
  385 
  386         sc->evdev = evdev_alloc();
  387         evdev_set_name(sc->evdev, device_get_desc(dev));
  388         evdev_set_phys(sc->evdev, device_get_nameunit(dev));
  389         evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct,
  390             hw->idVersion);
  391         evdev_set_serial(sc->evdev, hw->serial);
  392         evdev_set_methods(sc->evdev, dev, &hmt_evdev_methods);
  393         evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT);
  394         evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
  395         switch (sc->type) {
  396         case HMT_TYPE_TOUCHSCREEN:
  397                 evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT);
  398                 break;
  399         case HMT_TYPE_TOUCHPAD:
  400                 evdev_support_prop(sc->evdev, INPUT_PROP_POINTER);
  401                 if (sc->is_clickpad)
  402                         evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD);
  403                 break;
  404         default:
  405                 KASSERT(0, ("hmt_attach: unsupported touch device type"));
  406         }
  407         evdev_support_event(sc->evdev, EV_SYN);
  408         evdev_support_event(sc->evdev, EV_ABS);
  409         if (sc->do_timestamps) {
  410                 evdev_support_event(sc->evdev, EV_MSC);
  411                 evdev_support_msc(sc->evdev, MSC_TIMESTAMP);
  412         }
  413 #ifdef IICHID_SAMPLING
  414         if (sc->iichid_sampling)
  415                 evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_AUTOREL);
  416 #endif
  417         nbuttons = 0;
  418         if (sc->max_button != 0 || sc->has_int_button) {
  419                 evdev_support_event(sc->evdev, EV_KEY);
  420                 if (sc->has_int_button)
  421                         evdev_support_key(sc->evdev, BTN_LEFT);
  422                 for (btn = 0; btn < sc->max_button; ++btn) {
  423                         if (isset(sc->buttons, btn)) {
  424                                 evdev_support_key(sc->evdev, BTN_MOUSE + btn);
  425                                 nbuttons++;
  426                         }
  427                 }
  428         }
  429         HMT_FOREACH_USAGE(sc->caps, i) {
  430                 if (hmt_hid_map[i].code != HMT_NO_CODE)
  431                         evdev_support_abs(sc->evdev, hmt_hid_map[i].code,
  432                             sc->ai[i].min, sc->ai[i].max, 0, 0, sc->ai[i].res);
  433         }
  434 
  435         err = evdev_register(sc->evdev);
  436         if (err) {
  437                 hmt_detach(dev);
  438                 return (ENXIO);
  439         }
  440 
  441         /* Announce information about the touch device */
  442         device_printf(sc->dev, "Multitouch %s with %d external button%s%s\n",
  443             sc->type == HMT_TYPE_TOUCHSCREEN ? "touchscreen" : "touchpad",
  444             nbuttons, nbuttons != 1 ? "s" : "",
  445             sc->is_clickpad ? ", click-pad" : "");
  446         device_printf(sc->dev,
  447             "%d contacts with [%s%s%s%s%s] properties. Report range [%d:%d] - [%d:%d]\n",
  448             (int)sc->ai[HMT_SLOT].max + 1,
  449             isset(sc->caps, HMT_IN_RANGE) ? "R" : "",
  450             isset(sc->caps, HMT_CONFIDENCE) ? "C" : "",
  451             isset(sc->caps, HMT_WIDTH) ? "W" : "",
  452             isset(sc->caps, HMT_HEIGHT) ? "H" : "",
  453             isset(sc->caps, HMT_PRESSURE) ? "P" : "",
  454             (int)sc->ai[HMT_X].min, (int)sc->ai[HMT_Y].min,
  455             (int)sc->ai[HMT_X].max, (int)sc->ai[HMT_Y].max);
  456 
  457         return (0);
  458 }
  459 
  460 static int
  461 hmt_detach(device_t dev)
  462 {
  463         struct hmt_softc *sc = device_get_softc(dev);
  464 
  465         evdev_free(sc->evdev);
  466 
  467         return (0);
  468 }
  469 
  470 static void
  471 hmt_intr(void *context, void *buf, hid_size_t len)
  472 {
  473         struct hmt_softc *sc = context;
  474         size_t usage;
  475         uint32_t *slot_data = sc->slot_data;
  476         uint32_t cont, btn;
  477         uint32_t cont_count;
  478         uint32_t width;
  479         uint32_t height;
  480         uint32_t int_btn = 0;
  481         uint32_t left_btn = 0;
  482         int32_t slot;
  483         uint32_t scan_time;
  484         int32_t delta;
  485         uint8_t id;
  486 
  487 #ifdef IICHID_SAMPLING
  488         /*
  489          * Special packet of zero length is generated by iichid driver running
  490          * in polling mode at the start of inactivity period to workaround
  491          * "stuck touch" problem caused by miss of finger release events.
  492          * This snippet is to be removed after GPIO interrupt support is added.
  493          */
  494         if (sc->iichid_sampling && len == 0) {
  495                 sc->prev_touch = false;
  496                 sc->timestamp = 0;
  497                 for (slot = 0; slot <= sc->ai[HMT_SLOT].max; slot++) {
  498                         evdev_push_abs(sc->evdev, ABS_MT_SLOT, slot);
  499                         evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1);
  500                 }
  501                 evdev_sync(sc->evdev);
  502                 return;
  503         }
  504 #endif
  505 
  506         /* Ignore irrelevant reports */
  507         id = sc->report_id != 0 ? *(uint8_t *)buf : 0;
  508         if (sc->report_id != id) {
  509                 DPRINTF("Skip report with unexpected ID: %hhu\n", id);
  510                 return;
  511         }
  512 
  513         /* Strip leading "report ID" byte */
  514         if (sc->report_id != 0) {
  515                 len--;
  516                 buf = (uint8_t *)buf + 1;
  517         }
  518 
  519         /*
  520          * "In Parallel mode, devices report all contact information in a
  521          * single packet. Each physical contact is represented by a logical
  522          * collection that is embedded in the top-level collection."
  523          *
  524          * Since additional contacts that were not present will still be in the
  525          * report with contactid=0 but contactids are zero-based, find
  526          * contactcount first.
  527          */
  528         cont_count = hid_get_udata(buf, len, &sc->cont_count_loc);
  529         /*
  530          * "In Hybrid mode, the number of contacts that can be reported in one
  531          * report is less than the maximum number of contacts that the device
  532          * supports. For example, a device that supports a maximum of
  533          * 4 concurrent physical contacts, can set up its top-level collection
  534          * to deliver a maximum of two contacts in one report. If four contact
  535          * points are present, the device can break these up into two serial
  536          * reports that deliver two contacts each.
  537          *
  538          * "When a device delivers data in this manner, the Contact Count usage
  539          * value in the first report should reflect the total number of
  540          * contacts that are being delivered in the hybrid reports. The other
  541          * serial reports should have a contact count of zero (0)."
  542          */
  543         if (cont_count != 0)
  544                 sc->nconts_todo = cont_count;
  545 
  546 #ifdef HID_DEBUG
  547         DPRINTFN(6, "cont_count:%2u", (unsigned)cont_count);
  548         if (hmt_debug >= 6) {
  549                 HMT_FOREACH_USAGE(sc->caps, usage) {
  550                         if (hmt_hid_map[usage].usage != HMT_NO_USAGE)
  551                                 printf(" %-4s", hmt_hid_map[usage].name);
  552                 }
  553                 printf("\n");
  554         }
  555 #endif
  556 
  557         /* Find the number of contacts reported in current report */
  558         cont_count = MIN(sc->nconts_todo, sc->nconts_per_report);
  559 
  560         /* Use protocol Type B for reporting events */
  561         for (cont = 0; cont < cont_count; cont++) {
  562                 bzero(slot_data, sizeof(sc->slot_data));
  563                 HMT_FOREACH_USAGE(sc->caps, usage) {
  564                         if (sc->locs[cont][usage].size > 0)
  565                                 slot_data[usage] = hid_get_udata(
  566                                     buf, len, &sc->locs[cont][usage]);
  567                 }
  568 
  569                 slot = evdev_get_mt_slot_by_tracking_id(sc->evdev,
  570                     slot_data[HMT_CONTACTID]);
  571 
  572 #ifdef HID_DEBUG
  573                 DPRINTFN(6, "cont%01x: data = ", cont);
  574                 if (hmt_debug >= 6) {
  575                         HMT_FOREACH_USAGE(sc->caps, usage) {
  576                                 if (hmt_hid_map[usage].usage != HMT_NO_USAGE)
  577                                         printf("%04x ", slot_data[usage]);
  578                         }
  579                         printf("slot = %d\n", (int)slot);
  580                 }
  581 #endif
  582 
  583                 if (slot == -1) {
  584                         DPRINTF("Slot overflow for contact_id %u\n",
  585                             (unsigned)slot_data[HMT_CONTACTID]);
  586                         continue;
  587                 }
  588 
  589                 if (slot_data[HMT_TIP_SWITCH] != 0 &&
  590                     !(isset(sc->caps, HMT_CONFIDENCE) &&
  591                       slot_data[HMT_CONFIDENCE] == 0)) {
  592                         /* This finger is in proximity of the sensor */
  593                         sc->touch = true;
  594                         slot_data[HMT_SLOT] = slot;
  595                         slot_data[HMT_IN_RANGE] = !slot_data[HMT_IN_RANGE];
  596                         /* Divided by two to match visual scale of touch */
  597                         width = slot_data[HMT_WIDTH] >> 1;
  598                         height = slot_data[HMT_HEIGHT] >> 1;
  599                         slot_data[HMT_ORIENTATION] = width > height;
  600                         slot_data[HMT_MAJOR] = MAX(width, height);
  601                         slot_data[HMT_MINOR] = MIN(width, height);
  602 
  603                         HMT_FOREACH_USAGE(sc->caps, usage)
  604                                 if (hmt_hid_map[usage].code != HMT_NO_CODE)
  605                                         evdev_push_abs(sc->evdev,
  606                                             hmt_hid_map[usage].code,
  607                                             slot_data[usage]);
  608                 } else {
  609                         evdev_push_abs(sc->evdev, ABS_MT_SLOT, slot);
  610                         evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1);
  611                 }
  612         }
  613 
  614         sc->nconts_todo -= cont_count;
  615         if (sc->do_timestamps && sc->nconts_todo == 0) {
  616                 /* HUD_SCAN_TIME is measured in 100us, convert to us. */
  617                 scan_time = hid_get_udata(buf, len, &sc->scan_time_loc);
  618                 if (sc->prev_touch) {
  619                         delta = scan_time - sc->scan_time;
  620                         if (delta < 0)
  621                                 delta += sc->scan_time_max;
  622                 } else
  623                         delta = 0;
  624                 sc->scan_time = scan_time;
  625                 sc->timestamp += delta * 100;
  626                 evdev_push_msc(sc->evdev, MSC_TIMESTAMP, sc->timestamp);
  627                 sc->prev_touch = sc->touch;
  628                 sc->touch = false;
  629                 if (!sc->prev_touch)
  630                         sc->timestamp = 0;
  631         }
  632         if (sc->nconts_todo == 0) {
  633                 /* Report both the click and external left btns as BTN_LEFT */
  634                 if (sc->has_int_button)
  635                         int_btn = hid_get_data(buf, len, &sc->int_btn_loc);
  636                 if (isset(sc->buttons, 0))
  637                         left_btn = hid_get_data(buf, len, &sc->btn_loc[0]);
  638                 if (sc->has_int_button || isset(sc->buttons, 0))
  639                         evdev_push_key(sc->evdev, BTN_LEFT,
  640                             (int_btn != 0) | (left_btn != 0));
  641                 for (btn = 1; btn < sc->max_button; ++btn) {
  642                         if (isset(sc->buttons, btn))
  643                                 evdev_push_key(sc->evdev, BTN_MOUSE + btn,
  644                                     hid_get_data(buf,
  645                                                  len,
  646                                                  &sc->btn_loc[btn]) != 0);
  647                 }
  648                 evdev_sync(sc->evdev);
  649         }
  650 }
  651 
  652 static enum hmt_type
  653 hmt_hid_parse(struct hmt_softc *sc, const void *d_ptr, hid_size_t d_len,
  654     uint32_t tlc_usage, uint8_t tlc_index)
  655 {
  656         struct hid_absinfo ai;
  657         struct hid_item hi;
  658         struct hid_data *hd;
  659         uint32_t flags;
  660         size_t i;
  661         size_t cont = 0;
  662         enum hmt_type type;
  663         uint32_t left_btn, btn;
  664         int32_t cont_count_max = 0;
  665         uint8_t report_id = 0;
  666         bool finger_coll = false;
  667         bool cont_count_found = false;
  668         bool scan_time_found = false;
  669         bool has_int_button = false;
  670 
  671 #define HMT_HI_ABSOLUTE(hi)     \
  672         (((hi).flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
  673 #define HUMS_THQA_CERT  0xC5
  674 
  675         /*
  676          * Get left button usage taking in account MS Precision Touchpad specs.
  677          * For Windows PTP report descriptor assigns buttons in following way:
  678          * Button 1 - Indicates Button State for touchpad button integrated
  679          *            with digitizer.
  680          * Button 2 - Indicates Button State for external button for primary
  681          *            (default left) clicking.
  682          * Button 3 - Indicates Button State for external button for secondary
  683          *            (default right) clicking.
  684          * If a device only supports external buttons, it must still use
  685          * Button 2 and Button 3 to reference the external buttons.
  686          */
  687         switch (tlc_usage) {
  688         case HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN):
  689                 type = HMT_TYPE_TOUCHSCREEN;
  690                 left_btn = 1;
  691                 break;
  692         case HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD):
  693                 type = HMT_TYPE_TOUCHPAD;
  694                 left_btn = 2;
  695                 break;
  696         default:
  697                 return (HMT_TYPE_UNSUPPORTED);
  698         }
  699 
  700         /* Parse features for mandatory maximum contact count usage */
  701         if (!hidbus_locate(d_ptr, d_len,
  702             HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX), hid_feature,
  703             tlc_index, 0, &sc->cont_max_loc, &flags, &sc->cont_max_rid, &ai) ||
  704             (flags & (HIO_VARIABLE | HIO_RELATIVE)) != HIO_VARIABLE)
  705                 return (HMT_TYPE_UNSUPPORTED);
  706 
  707         cont_count_max = ai.max;
  708 
  709         /* Parse features for button type usage */
  710         if (hidbus_locate(d_ptr, d_len,
  711             HID_USAGE2(HUP_DIGITIZERS, HUD_BUTTON_TYPE), hid_feature,
  712             tlc_index, 0, &sc->btn_type_loc, &flags, &sc->btn_type_rid, NULL)
  713             && (flags & (HIO_VARIABLE | HIO_RELATIVE)) != HIO_VARIABLE)
  714                 sc->btn_type_rid = 0;
  715 
  716         /* Parse features for THQA certificate report ID */
  717         hidbus_locate(d_ptr, d_len, HID_USAGE2(HUP_MICROSOFT, HUMS_THQA_CERT),
  718             hid_feature, tlc_index, 0, NULL, NULL, &sc->thqa_cert_rid, NULL);
  719 
  720         /* Parse input for other parameters */
  721         hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
  722         HIDBUS_FOREACH_ITEM(hd, &hi, tlc_index) {
  723                 switch (hi.kind) {
  724                 case hid_collection:
  725                         if (hi.collevel == 2 &&
  726                             hi.usage == HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER))
  727                                 finger_coll = true;
  728                         break;
  729                 case hid_endcollection:
  730                         if (hi.collevel == 1 && finger_coll) {
  731                                 finger_coll = false;
  732                                 cont++;
  733                         }
  734                         break;
  735                 case hid_input:
  736                         /*
  737                          * Ensure that all usages belong to the same report
  738                          */
  739                         if (HMT_HI_ABSOLUTE(hi) &&
  740                             (report_id == 0 || report_id == hi.report_ID))
  741                                 report_id = hi.report_ID;
  742                         else
  743                                 break;
  744 
  745                         if (hi.collevel == 1 && left_btn == 2 &&
  746                             hi.usage == HID_USAGE2(HUP_BUTTON, 1)) {
  747                                 has_int_button = true;
  748                                 sc->int_btn_loc = hi.loc;
  749                                 break;
  750                         }
  751                         if (hi.collevel == 1 &&
  752                             hi.usage >= HID_USAGE2(HUP_BUTTON, left_btn) &&
  753                             hi.usage <= HID_USAGE2(HUP_BUTTON, HMT_BTN_MAX)) {
  754                                 btn = (hi.usage & 0xFFFF) - left_btn;
  755                                 setbit(sc->buttons, btn);
  756                                 sc->btn_loc[btn] = hi.loc;
  757                                 if (btn >= sc->max_button)
  758                                         sc->max_button = btn + 1;
  759                                 break;
  760                         }
  761                         if (hi.collevel == 1 && hi.usage ==
  762                             HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT)) {
  763                                 cont_count_found = true;
  764                                 sc->cont_count_loc = hi.loc;
  765                                 break;
  766                         }
  767                         /* Scan time is required but clobbered by evdev */
  768                         if (hi.collevel == 1 && hi.usage ==
  769                             HID_USAGE2(HUP_DIGITIZERS, HUD_SCAN_TIME)) {
  770                                 scan_time_found = true;
  771                                 sc->scan_time_loc = hi.loc;
  772                                 sc->scan_time_max = hi.logical_maximum;
  773                                 break;
  774                         }
  775 
  776                         if (!finger_coll || hi.collevel != 2)
  777                                 break;
  778                         if (cont >= MAX_MT_SLOTS) {
  779                                 DPRINTF("Finger %zu ignored\n", cont);
  780                                 break;
  781                         }
  782 
  783                         for (i = 0; i < HMT_N_USAGES; i++) {
  784                                 if (hi.usage == hmt_hid_map[i].usage) {
  785                                         /*
  786                                          * HUG_X usage is an array mapped to
  787                                          * both ABS_MT_POSITION and ABS_MT_TOOL
  788                                          * events. So don`t stop search if we
  789                                          * already have HUG_X mapping done.
  790                                          */
  791                                         if (sc->locs[cont][i].size)
  792                                                 continue;
  793                                         sc->locs[cont][i] = hi.loc;
  794                                         /*
  795                                          * Hid parser returns valid logical and
  796                                          * physical sizes for first finger only
  797                                          * at least on ElanTS 0x04f3:0x0012.
  798                                          */
  799                                         if (cont > 0)
  800                                                 break;
  801                                         setbit(sc->caps, i);
  802                                         sc->ai[i] = (struct hid_absinfo) {
  803                                             .max = hi.logical_maximum,
  804                                             .min = hi.logical_minimum,
  805                                             .res = hid_item_resolution(&hi),
  806                                         };
  807                                         break;
  808                                 }
  809                         }
  810                         break;
  811                 default:
  812                         break;
  813                 }
  814         }
  815         hid_end_parse(hd);
  816 
  817         /* Check for required HID Usages */
  818         if (!cont_count_found || !scan_time_found || cont == 0)
  819                 return (HMT_TYPE_UNSUPPORTED);
  820         for (i = 0; i < HMT_N_USAGES; i++) {
  821                 if (hmt_hid_map[i].required && isclr(sc->caps, i))
  822                         return (HMT_TYPE_UNSUPPORTED);
  823         }
  824 
  825         /* Touchpads must have at least one button */
  826         if (type == HMT_TYPE_TOUCHPAD && !sc->max_button && !has_int_button)
  827                 return (HMT_TYPE_UNSUPPORTED);
  828 
  829         /*
  830          * According to specifications 'Contact Count Maximum' should be read
  831          * from Feature Report rather than from HID descriptor. Set sane
  832          * default value now to handle the case of 'Get Report' request failure
  833          */
  834         if (cont_count_max < 1)
  835                 cont_count_max = cont;
  836 
  837         /* Set number of MT protocol type B slots */
  838         sc->ai[HMT_SLOT] = (struct hid_absinfo) {
  839                 .min = 0,
  840                 .max = cont_count_max - 1,
  841                 .res = 0,
  842         };
  843 
  844         /* Report touch orientation if both width and height are supported */
  845         if (isset(sc->caps, HMT_WIDTH) && isset(sc->caps, HMT_HEIGHT)) {
  846                 setbit(sc->caps, HMT_ORIENTATION);
  847                 sc->ai[HMT_ORIENTATION].max = 1;
  848         }
  849 
  850         sc->cont_max_rlen = hid_report_size(d_ptr, d_len, hid_feature,
  851             sc->cont_max_rid);
  852         if (sc->btn_type_rid > 0)
  853                 sc->btn_type_rlen = hid_report_size(d_ptr, d_len,
  854                     hid_feature, sc->btn_type_rid);
  855         if (sc->thqa_cert_rid > 0)
  856                 sc->thqa_cert_rlen = hid_report_size(d_ptr, d_len,
  857                     hid_feature, sc->thqa_cert_rid);
  858 
  859         sc->report_id = report_id;
  860         sc->nconts_per_report = cont;
  861         sc->has_int_button = has_int_button;
  862 
  863         return (type);
  864 }
  865 
  866 static int
  867 hmt_set_input_mode(struct hmt_softc *sc, enum hconf_input_mode mode)
  868 {
  869         devclass_t hconf_devclass;
  870         device_t hconf;
  871         int  err;
  872 
  873         GIANT_REQUIRED;
  874 
  875         /* Find touchpad's configuration TLC */
  876         hconf = hidbus_find_child(device_get_parent(sc->dev),
  877             HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIG));
  878         if (hconf == NULL)
  879                 return (ENXIO);
  880 
  881         /* Ensure that hconf driver is attached to configuration TLC */
  882         if (device_is_alive(hconf) == 0)
  883                 device_probe_and_attach(hconf);
  884         if (device_is_attached(hconf) == 0)
  885                 return (ENXIO);
  886         hconf_devclass = devclass_find("hconf");
  887         if (device_get_devclass(hconf) != hconf_devclass)
  888                 return (ENXIO);
  889 
  890         /* hconf_set_input_mode can drop the Giant while sleeping */
  891         device_busy(hconf);
  892         err = hconf_set_input_mode(hconf, mode);
  893         device_unbusy(hconf);
  894 
  895         return (err);
  896 }
  897 
  898 static devclass_t hmt_devclass;
  899 
  900 static device_method_t hmt_methods[] = {
  901         DEVMETHOD(device_probe,         hmt_probe),
  902         DEVMETHOD(device_attach,        hmt_attach),
  903         DEVMETHOD(device_detach,        hmt_detach),
  904 
  905         DEVMETHOD_END
  906 };
  907 
  908 static driver_t hmt_driver = {
  909         .name = "hmt",
  910         .methods = hmt_methods,
  911         .size = sizeof(struct hmt_softc),
  912 };
  913 
  914 DRIVER_MODULE(hmt, hidbus, hmt_driver, hmt_devclass, NULL, 0);
  915 MODULE_DEPEND(hmt, hidbus, 1, 1, 1);
  916 MODULE_DEPEND(hmt, hid, 1, 1, 1);
  917 MODULE_DEPEND(hmt, hconf, 1, 1, 1);
  918 MODULE_DEPEND(hmt, evdev, 1, 1, 1);
  919 MODULE_VERSION(hmt, 1);
  920 HID_PNP_INFO(hmt_devs);

Cache object: 97fc649fb3ed59a74ea15ae4bd352c96


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.