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/bcm5974.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) 2012 Huang Wen Hui
    5  * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/bus.h>
   35 #include <sys/endian.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/module.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/systm.h>
   41 
   42 #include <dev/evdev/input.h>
   43 #include <dev/evdev/evdev.h>
   44 
   45 #define HID_DEBUG_VAR   bcm5974_debug
   46 #include <dev/hid/hid.h>
   47 #include <dev/hid/hidbus.h>
   48 #include <dev/hid/hidquirk.h>
   49 
   50 #include <dev/usb/usb.h>
   51 #include <dev/usb/usbdi.h>
   52 #include <dev/usb/usbhid.h>
   53 #include <dev/usb/usb_ioctl.h>
   54 
   55 #include "usbdevs.h"
   56 
   57 #define BCM5974_BUFFER_MAX      (248 * 4)       /* 4 Type4 SPI frames */
   58 #define BCM5974_TLC_PAGE        HUP_GENERIC_DESKTOP
   59 #define BCM5974_TLC_USAGE       HUG_MOUSE
   60 
   61 /* magic to switch device from HID (default) mode into raw */
   62 /* Type1 & Type2 trackpads */
   63 #define BCM5974_USB_IFACE_INDEX 0
   64 #define BCM5974_USB_REPORT_LEN  8
   65 #define BCM5974_USB_REPORT_ID   0
   66 #define BCM5974_USB_MODE_RAW    0x01
   67 #define BCM5974_USB_MODE_HID    0x08
   68 /* Type4 trackpads */
   69 #define BCM5974_HID_REPORT_LEN  2
   70 #define BCM5974_HID_REPORT_ID   2
   71 #define BCM5974_HID_MODE_RAW    0x01
   72 #define BCM5974_HID_MODE_HID    0x00
   73 
   74 /* Tunables */
   75 static  SYSCTL_NODE(_hw_hid, OID_AUTO, bcm5974, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   76     "HID wellspring touchpad");
   77 
   78 #ifdef HID_DEBUG
   79 enum wsp_log_level {
   80         BCM5974_LLEVEL_DISABLED = 0,
   81         BCM5974_LLEVEL_ERROR,
   82         BCM5974_LLEVEL_DEBUG,           /* for troubleshooting */
   83         BCM5974_LLEVEL_INFO,            /* for diagnostics */
   84 };
   85 /* the default is to only log errors */
   86 static int bcm5974_debug = BCM5974_LLEVEL_ERROR;
   87 
   88 SYSCTL_INT(_hw_hid_bcm5974, OID_AUTO, debug, CTLFLAG_RWTUN,
   89     &bcm5974_debug, BCM5974_LLEVEL_ERROR, "BCM5974 debug level");
   90 #endif                                  /* HID_DEBUG */
   91 
   92 /*
   93  * Some tables, structures, definitions and constant values for the
   94  * touchpad protocol has been copied from Linux's
   95  * "drivers/input/mouse/bcm5974.c" which has the following copyright
   96  * holders under GPLv2. All device specific code in this driver has
   97  * been written from scratch. The decoding algorithm is based on
   98  * output from FreeBSD's usbdump.
   99  *
  100  * Copyright (C) 2008      Henrik Rydberg (rydberg@euromail.se)
  101  * Copyright (C) 2008      Scott Shawcroft (scott.shawcroft@gmail.com)
  102  * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
  103  * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
  104  * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
  105  * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
  106  * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
  107  * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
  108  * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
  109  */
  110 
  111 /* trackpad header types */
  112 enum tp_type {
  113         TYPE1,                  /* plain trackpad */
  114         TYPE2,                  /* button integrated in trackpad */
  115         TYPE3,                  /* additional header fields since June 2013 */
  116         TYPE4,                  /* additional header field for pressure data */
  117         TYPE_CNT
  118 };
  119 
  120 /* list of device capability bits */
  121 #define HAS_INTEGRATED_BUTTON   1
  122 
  123 struct tp_type_params {
  124         uint8_t caps;           /* device capability bitmask */
  125         uint8_t button;         /* offset to button data */
  126         uint8_t offset;         /* offset to trackpad finger data */
  127         uint8_t delta;          /* offset from header to finger struct */
  128 } const static tp[TYPE_CNT] = {
  129         [TYPE1] = {
  130                 .caps = 0,
  131                 .button = 0,
  132                 .offset = 13 * 2,
  133                 .delta = 0,
  134         },
  135         [TYPE2] = {
  136                 .caps = HAS_INTEGRATED_BUTTON,
  137                 .button = 15,
  138                 .offset = 15 * 2,
  139                 .delta = 0,
  140         },
  141         [TYPE3] = {
  142                 .caps = HAS_INTEGRATED_BUTTON,
  143                 .button = 23,
  144                 .offset = 19 * 2,
  145                 .delta = 0,
  146         },
  147         [TYPE4] = {
  148                 .caps = HAS_INTEGRATED_BUTTON,
  149                 .button = 31,
  150                 .offset = 23 * 2,
  151                 .delta = 2,
  152         },
  153 };
  154 
  155 /* trackpad finger structure - little endian */
  156 struct tp_finger {
  157         uint16_t        origin;         /* zero when switching track finger */
  158         uint16_t        abs_x;          /* absolute x coodinate */
  159         uint16_t        abs_y;          /* absolute y coodinate */
  160         uint16_t        rel_x;          /* relative x coodinate */
  161         uint16_t        rel_y;          /* relative y coodinate */
  162         uint16_t        tool_major;     /* tool area, major axis */
  163         uint16_t        tool_minor;     /* tool area, minor axis */
  164         uint16_t        orientation;    /* 16384 when point, else 15 bit angle */
  165         uint16_t        touch_major;    /* touch area, major axis */
  166         uint16_t        touch_minor;    /* touch area, minor axis */
  167         uint16_t        unused[2];      /* zeros */
  168         uint16_t        pressure;       /* pressure on forcetouch touchpad */
  169         uint16_t        multi;          /* one finger: varies, more fingers:
  170                                          * constant */
  171 } __packed;
  172 
  173 #define BCM5974_LE2H(x) ((int32_t)(int16_t)le16toh(x))
  174 
  175 /* trackpad finger data size, empirically at least ten fingers */
  176 #define MAX_FINGERS             MAX_MT_SLOTS
  177 
  178 #define MAX_FINGER_ORIENTATION  16384
  179 
  180 enum {
  181         BCM5974_FLAG_WELLSPRING1,
  182         BCM5974_FLAG_WELLSPRING2,
  183         BCM5974_FLAG_WELLSPRING3,
  184         BCM5974_FLAG_WELLSPRING4,
  185         BCM5974_FLAG_WELLSPRING4A,
  186         BCM5974_FLAG_WELLSPRING5,
  187         BCM5974_FLAG_WELLSPRING6A,
  188         BCM5974_FLAG_WELLSPRING6,
  189         BCM5974_FLAG_WELLSPRING5A,
  190         BCM5974_FLAG_WELLSPRING7,
  191         BCM5974_FLAG_WELLSPRING7A,
  192         BCM5974_FLAG_WELLSPRING8,
  193         BCM5974_FLAG_WELLSPRING9,
  194         BCM5974_FLAG_MAX,
  195 };
  196 
  197 /* device-specific parameters */
  198 struct bcm5974_axis {
  199         int snratio;                    /* signal-to-noise ratio */
  200         int min;                        /* device minimum reading */
  201         int max;                        /* device maximum reading */
  202         int size;                       /* physical size, mm */
  203 };
  204 
  205 /* device-specific configuration */
  206 struct bcm5974_dev_params {
  207         const struct tp_type_params* tp;
  208         struct bcm5974_axis p;          /* finger pressure limits */
  209         struct bcm5974_axis w;          /* finger width limits */
  210         struct bcm5974_axis x;          /* horizontal limits */
  211         struct bcm5974_axis y;          /* vertical limits */
  212         struct bcm5974_axis o;          /* orientation limits */
  213 };
  214 
  215 /* logical signal quality */
  216 #define SN_PRESSURE     45              /* pressure signal-to-noise ratio */
  217 #define SN_WIDTH        25              /* width signal-to-noise ratio */
  218 #define SN_COORD        250             /* coordinate signal-to-noise ratio */
  219 #define SN_ORIENT       10              /* orientation signal-to-noise ratio */
  220 
  221 static const struct bcm5974_dev_params bcm5974_dev_params[BCM5974_FLAG_MAX] = {
  222         [BCM5974_FLAG_WELLSPRING1] = {
  223                 .tp = tp + TYPE1,
  224                 .p = { SN_PRESSURE, 0, 256, 0 },
  225                 .w = { SN_WIDTH, 0, 2048, 0 },
  226                 .x = { SN_COORD, -4824, 5342, 105 },
  227                 .y = { SN_COORD, -172, 5820, 75 },
  228                 .o = { SN_ORIENT,
  229                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  230         },
  231         [BCM5974_FLAG_WELLSPRING2] = {
  232                 .tp = tp + TYPE1,
  233                 .p = { SN_PRESSURE, 0, 256, 0 },
  234                 .w = { SN_WIDTH, 0, 2048, 0 },
  235                 .x = { SN_COORD, -4824, 4824, 105 },
  236                 .y = { SN_COORD, -172, 4290, 75 },
  237                 .o = { SN_ORIENT,
  238                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  239         },
  240         [BCM5974_FLAG_WELLSPRING3] = {
  241                 .tp = tp + TYPE2,
  242                 .p = { SN_PRESSURE, 0, 300, 0 },
  243                 .w = { SN_WIDTH, 0, 2048, 0 },
  244                 .x = { SN_COORD, -4460, 5166, 105 },
  245                 .y = { SN_COORD, -75, 6700, 75 },
  246                 .o = { SN_ORIENT,
  247                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  248         },
  249         [BCM5974_FLAG_WELLSPRING4] = {
  250                 .tp = tp + TYPE2,
  251                 .p = { SN_PRESSURE, 0, 300, 0 },
  252                 .w = { SN_WIDTH, 0, 2048, 0 },
  253                 .x = { SN_COORD, -4620, 5140, 105 },
  254                 .y = { SN_COORD, -150, 6600, 75 },
  255                 .o = { SN_ORIENT,
  256                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  257         },
  258         [BCM5974_FLAG_WELLSPRING4A] = {
  259                 .tp = tp + TYPE2,
  260                 .p = { SN_PRESSURE, 0, 300, 0 },
  261                 .w = { SN_WIDTH, 0, 2048, 0 },
  262                 .x = { SN_COORD, -4616, 5112, 105 },
  263                 .y = { SN_COORD, -142, 5234, 75 },
  264                 .o = { SN_ORIENT,
  265                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  266         },
  267         [BCM5974_FLAG_WELLSPRING5] = {
  268                 .tp = tp + TYPE2,
  269                 .p = { SN_PRESSURE, 0, 300, 0 },
  270                 .w = { SN_WIDTH, 0, 2048, 0 },
  271                 .x = { SN_COORD, -4415, 5050, 105 },
  272                 .y = { SN_COORD, -55, 6680, 75 },
  273                 .o = { SN_ORIENT,
  274                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  275         },
  276         [BCM5974_FLAG_WELLSPRING6] = {
  277                 .tp = tp + TYPE2,
  278                 .p = { SN_PRESSURE, 0, 300, 0 },
  279                 .w = { SN_WIDTH, 0, 2048, 0 },
  280                 .x = { SN_COORD, -4620, 5140, 105 },
  281                 .y = { SN_COORD, -150, 6600, 75 },
  282                 .o = { SN_ORIENT,
  283                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  284         },
  285         [BCM5974_FLAG_WELLSPRING5A] = {
  286                 .tp = tp + TYPE2,
  287                 .p = { SN_PRESSURE, 0, 300, 0 },
  288                 .w = { SN_WIDTH, 0, 2048, 0 },
  289                 .x = { SN_COORD, -4750, 5280, 105 },
  290                 .y = { SN_COORD, -150, 6730, 75 },
  291                 .o = { SN_ORIENT,
  292                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  293         },
  294         [BCM5974_FLAG_WELLSPRING6A] = {
  295                 .tp = tp + TYPE2,
  296                 .p = { SN_PRESSURE, 0, 300, 0 },
  297                 .w = { SN_WIDTH, 0, 2048, 0 },
  298                 .x = { SN_COORD, -4620, 5140, 105 },
  299                 .y = { SN_COORD, -150, 6600, 75 },
  300                 .o = { SN_ORIENT,
  301                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  302         },
  303         [BCM5974_FLAG_WELLSPRING7] = {
  304                 .tp = tp + TYPE2,
  305                 .p = { SN_PRESSURE, 0, 300, 0 },
  306                 .w = { SN_WIDTH, 0, 2048, 0 },
  307                 .x = { SN_COORD, -4750, 5280, 105 },
  308                 .y = { SN_COORD, -150, 6730, 75 },
  309                 .o = { SN_ORIENT,
  310                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  311         },
  312         [BCM5974_FLAG_WELLSPRING7A] = {
  313                 .tp = tp + TYPE2,
  314                 .p = { SN_PRESSURE, 0, 300, 0 },
  315                 .w = { SN_WIDTH, 0, 2048, 0 },
  316                 .x = { SN_COORD, -4750, 5280, 105 },
  317                 .y = { SN_COORD, -150, 6730, 75 },
  318                 .o = { SN_ORIENT,
  319                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  320         },
  321         [BCM5974_FLAG_WELLSPRING8] = {
  322                 .tp = tp + TYPE3,
  323                 .p = { SN_PRESSURE, 0, 300, 0 },
  324                 .w = { SN_WIDTH, 0, 2048, 0 },
  325                 .x = { SN_COORD, -4620, 5140, 105 },
  326                 .y = { SN_COORD, -150, 6600, 75 },
  327                 .o = { SN_ORIENT,
  328                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  329         },
  330         [BCM5974_FLAG_WELLSPRING9] = {
  331                 .tp = tp + TYPE4,
  332                 .p = { SN_PRESSURE, 0, 300, 0 },
  333                 .w = { SN_WIDTH, 0, 2048, 0 },
  334                 .x = { SN_COORD, -4828, 5345, 105 },
  335                 .y = { SN_COORD, -203, 6803, 75 },
  336                 .o = { SN_ORIENT,
  337                     -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
  338         },
  339 };
  340 
  341 #define BCM5974_DEV(v,p,i)      {                                       \
  342         HID_BVPI(BUS_USB, USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i),    \
  343         HID_TLC(BCM5974_TLC_PAGE, BCM5974_TLC_USAGE),                   \
  344 }
  345 
  346 static const struct hid_device_id bcm5974_devs[] = {
  347         /* MacbookAir1.1 */
  348         BCM5974_DEV(APPLE, WELLSPRING_ANSI, BCM5974_FLAG_WELLSPRING1),
  349         BCM5974_DEV(APPLE, WELLSPRING_ISO, BCM5974_FLAG_WELLSPRING1),
  350         BCM5974_DEV(APPLE, WELLSPRING_JIS, BCM5974_FLAG_WELLSPRING1),
  351 
  352         /* MacbookProPenryn, aka wellspring2 */
  353         BCM5974_DEV(APPLE, WELLSPRING2_ANSI, BCM5974_FLAG_WELLSPRING2),
  354         BCM5974_DEV(APPLE, WELLSPRING2_ISO, BCM5974_FLAG_WELLSPRING2),
  355         BCM5974_DEV(APPLE, WELLSPRING2_JIS, BCM5974_FLAG_WELLSPRING2),
  356 
  357         /* Macbook5,1 (unibody), aka wellspring3 */
  358         BCM5974_DEV(APPLE, WELLSPRING3_ANSI, BCM5974_FLAG_WELLSPRING3),
  359         BCM5974_DEV(APPLE, WELLSPRING3_ISO, BCM5974_FLAG_WELLSPRING3),
  360         BCM5974_DEV(APPLE, WELLSPRING3_JIS, BCM5974_FLAG_WELLSPRING3),
  361 
  362         /* MacbookAir3,2 (unibody), aka wellspring4 */
  363         BCM5974_DEV(APPLE, WELLSPRING4_ANSI, BCM5974_FLAG_WELLSPRING4),
  364         BCM5974_DEV(APPLE, WELLSPRING4_ISO, BCM5974_FLAG_WELLSPRING4),
  365         BCM5974_DEV(APPLE, WELLSPRING4_JIS, BCM5974_FLAG_WELLSPRING4),
  366 
  367         /* MacbookAir3,1 (unibody), aka wellspring4 */
  368         BCM5974_DEV(APPLE, WELLSPRING4A_ANSI, BCM5974_FLAG_WELLSPRING4A),
  369         BCM5974_DEV(APPLE, WELLSPRING4A_ISO, BCM5974_FLAG_WELLSPRING4A),
  370         BCM5974_DEV(APPLE, WELLSPRING4A_JIS, BCM5974_FLAG_WELLSPRING4A),
  371 
  372         /* Macbook8 (unibody, March 2011) */
  373         BCM5974_DEV(APPLE, WELLSPRING5_ANSI, BCM5974_FLAG_WELLSPRING5),
  374         BCM5974_DEV(APPLE, WELLSPRING5_ISO, BCM5974_FLAG_WELLSPRING5),
  375         BCM5974_DEV(APPLE, WELLSPRING5_JIS, BCM5974_FLAG_WELLSPRING5),
  376 
  377         /* MacbookAir4,1 (unibody, July 2011) */
  378         BCM5974_DEV(APPLE, WELLSPRING6A_ANSI, BCM5974_FLAG_WELLSPRING6A),
  379         BCM5974_DEV(APPLE, WELLSPRING6A_ISO, BCM5974_FLAG_WELLSPRING6A),
  380         BCM5974_DEV(APPLE, WELLSPRING6A_JIS, BCM5974_FLAG_WELLSPRING6A),
  381 
  382         /* MacbookAir4,2 (unibody, July 2011) */
  383         BCM5974_DEV(APPLE, WELLSPRING6_ANSI, BCM5974_FLAG_WELLSPRING6),
  384         BCM5974_DEV(APPLE, WELLSPRING6_ISO, BCM5974_FLAG_WELLSPRING6),
  385         BCM5974_DEV(APPLE, WELLSPRING6_JIS, BCM5974_FLAG_WELLSPRING6),
  386 
  387         /* Macbook8,2 (unibody) */
  388         BCM5974_DEV(APPLE, WELLSPRING5A_ANSI, BCM5974_FLAG_WELLSPRING5A),
  389         BCM5974_DEV(APPLE, WELLSPRING5A_ISO, BCM5974_FLAG_WELLSPRING5A),
  390         BCM5974_DEV(APPLE, WELLSPRING5A_JIS, BCM5974_FLAG_WELLSPRING5A),
  391 
  392         /* MacbookPro10,1 (unibody, June 2012) */
  393         /* MacbookPro11,1-3 (unibody, June 2013) */
  394         BCM5974_DEV(APPLE, WELLSPRING7_ANSI, BCM5974_FLAG_WELLSPRING7),
  395         BCM5974_DEV(APPLE, WELLSPRING7_ISO, BCM5974_FLAG_WELLSPRING7),
  396         BCM5974_DEV(APPLE, WELLSPRING7_JIS, BCM5974_FLAG_WELLSPRING7),
  397 
  398         /* MacbookPro10,2 (unibody, October 2012) */
  399         BCM5974_DEV(APPLE, WELLSPRING7A_ANSI, BCM5974_FLAG_WELLSPRING7A),
  400         BCM5974_DEV(APPLE, WELLSPRING7A_ISO, BCM5974_FLAG_WELLSPRING7A),
  401         BCM5974_DEV(APPLE, WELLSPRING7A_JIS, BCM5974_FLAG_WELLSPRING7A),
  402 
  403         /* MacbookAir6,2 (unibody, June 2013) */
  404         BCM5974_DEV(APPLE, WELLSPRING8_ANSI, BCM5974_FLAG_WELLSPRING8),
  405         BCM5974_DEV(APPLE, WELLSPRING8_ISO, BCM5974_FLAG_WELLSPRING8),
  406         BCM5974_DEV(APPLE, WELLSPRING8_JIS, BCM5974_FLAG_WELLSPRING8),
  407 
  408         /* MacbookPro12,1 MacbookPro11,4 */
  409         BCM5974_DEV(APPLE, WELLSPRING9_ANSI, BCM5974_FLAG_WELLSPRING9),
  410         BCM5974_DEV(APPLE, WELLSPRING9_ISO, BCM5974_FLAG_WELLSPRING9),
  411         BCM5974_DEV(APPLE, WELLSPRING9_JIS, BCM5974_FLAG_WELLSPRING9),
  412 };
  413 
  414 struct bcm5974_softc {
  415         device_t sc_dev;
  416         struct evdev_dev *sc_evdev;
  417         /* device configuration */
  418         const struct bcm5974_dev_params *sc_params;
  419         bool sc_saved_mode;
  420 };
  421 
  422 static const uint8_t bcm5974_rdesc[] = {
  423         0x05, BCM5974_TLC_PAGE, /* Usage Page (BCM5974_TLC_PAGE)        */
  424         0x09, BCM5974_TLC_USAGE,/* Usage (BCM5974_TLC_USAGE)            */
  425         0xA1, 0x01,             /* Collection (Application)             */
  426         0x06, 0x00, 0xFF,       /*   Usage Page (Vendor Defined 0xFF00) */
  427         0x09, 0x01,             /*   Usage (0x01)                       */
  428         0x15, 0x00,             /*   Logical Minimum (0)                */
  429         0x26, 0xFF, 0x00,       /*   Logical Maximum (255)              */
  430         0x75, 0x08,             /*   Report Size (8)                    */
  431         0x96,                   /*   Report Count (BCM5974_BUFFER_MAX)  */
  432         BCM5974_BUFFER_MAX & 0xFF,
  433         BCM5974_BUFFER_MAX >> 8 & 0xFF,
  434         0x81, 0x02,             /*   Input (Data,Var,Abs)               */
  435         0xC0,                   /* End Collection                       */
  436 };
  437 
  438 /*
  439  * function prototypes
  440  */
  441 static evdev_open_t     bcm5974_ev_open;
  442 static evdev_close_t    bcm5974_ev_close;
  443 static const struct evdev_methods bcm5974_evdev_methods = {
  444         .ev_open =      &bcm5974_ev_open,
  445         .ev_close =     &bcm5974_ev_close,
  446 };
  447 static hid_intr_t       bcm5974_intr;
  448 
  449 /* Device methods. */
  450 static device_identify_t bcm5974_identify;
  451 static device_probe_t   bcm5974_probe;
  452 static device_attach_t  bcm5974_attach;
  453 static device_detach_t  bcm5974_detach;
  454 
  455 /*
  456  * Type1 and Type2 touchpads use keyboard USB interface to switch from HID to
  457  * RAW mode. Although it is possible to extend hkbd driver to support such a
  458  * mode change requests, it's not wanted due to cross device tree dependencies.
  459  * So, find lowest common denominator (struct usb_device of grandparent usbhid
  460  * driver) of touchpad and keyboard drivers and issue direct USB requests.
  461  */
  462 static int
  463 bcm5974_set_device_mode_usb(struct bcm5974_softc *sc, bool on)
  464 {
  465         uint8_t mode_bytes[BCM5974_USB_REPORT_LEN];
  466         struct usb_ctl_request ucr;
  467         int err;
  468 
  469         ucr.ucr_request.bmRequestType = UT_READ_CLASS_INTERFACE;
  470         ucr.ucr_request.bRequest = UR_GET_REPORT;
  471         USETW2(ucr.ucr_request.wValue,
  472             UHID_FEATURE_REPORT, BCM5974_USB_REPORT_ID);
  473         ucr.ucr_request.wIndex[0] = BCM5974_USB_IFACE_INDEX;
  474         ucr.ucr_request.wIndex[1] = 0;
  475         USETW(ucr.ucr_request.wLength, BCM5974_USB_REPORT_LEN);
  476         ucr.ucr_data = mode_bytes;
  477 
  478         err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr);
  479         if (err != 0) {
  480                 DPRINTF("Failed to read device mode (%d)\n", err);
  481                 return (EIO);
  482         }
  483 #if 0
  484         /*
  485          * XXX Need to wait at least 250ms for hardware to get
  486          * ready. The device mode handling appears to be handled
  487          * asynchronously and we should not issue these commands too
  488          * quickly.
  489          */
  490         pause("WHW", hz / 4);
  491 #endif
  492         mode_bytes[0] = on ? BCM5974_USB_MODE_RAW : BCM5974_USB_MODE_HID;
  493         ucr.ucr_request.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  494         ucr.ucr_request.bRequest = UR_SET_REPORT;
  495 
  496         err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr);
  497         if (err != 0) {
  498                 DPRINTF("Failed to write device mode (%d)\n", err);
  499                 return (EIO);
  500         }
  501 
  502         return (0);
  503 }
  504 
  505 static int
  506 bcm5974_set_device_mode_hid(struct bcm5974_softc *sc, bool on)
  507 {
  508         uint8_t mode_bytes[BCM5974_HID_REPORT_LEN] = {
  509                 BCM5974_HID_REPORT_ID,
  510                 on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID,
  511         };
  512 #if 0
  513         int err;
  514 
  515         err = hid_get_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN,
  516             NULL, HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID);
  517         if (err != 0) {
  518                 DPRINTF("Failed to read device mode (%d)\n", err);
  519                 return (err);
  520         }
  521         /*
  522          * XXX Need to wait at least 250ms for hardware to get
  523          * ready. The device mode handling appears to be handled
  524          * asynchronously and we should not issue these commands too
  525          * quickly.
  526          */
  527         pause("WHW", hz / 4);
  528         mode_bytes[1] = on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID;
  529 #endif
  530         return (hid_set_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN,
  531             HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID));
  532 }
  533 
  534 static int
  535 bcm5974_set_device_mode(struct bcm5974_softc *sc, bool on)
  536 {
  537         int err = 0;
  538 
  539         switch (sc->sc_params->tp - tp) {
  540         case TYPE1:
  541         case TYPE2:
  542                 err = bcm5974_set_device_mode_usb(sc, on);
  543                 break;
  544         case TYPE3:     /* Type 3 does not require a mode switch */
  545                 break;
  546         case TYPE4:
  547                 err = bcm5974_set_device_mode_hid(sc, on);
  548                 break;
  549         default:
  550                 KASSERT(0 == 1, ("Unknown trackpad type"));
  551         }
  552 
  553         if (!err)
  554                 sc->sc_saved_mode = on;
  555 
  556         return (err);
  557 }
  558 
  559 static void
  560 bcm5974_identify(driver_t *driver, device_t parent)
  561 {
  562         void *d_ptr;
  563         hid_size_t d_len;
  564 
  565         /*
  566          * The bcm5974 touchpad has no stable RAW mode TLC in its report
  567          * descriptor.  So replace existing HID mode mouse TLC with dummy one
  568          * to set proper transport layer buffer sizes, make driver probe
  569          * simpler and prevent unwanted hms driver attachment.
  570          */
  571         if (HIDBUS_LOOKUP_ID(parent, bcm5974_devs) != NULL &&
  572             hid_get_report_descr(parent, &d_ptr, &d_len) == 0 &&
  573             hid_is_mouse(d_ptr, d_len))
  574                 hid_set_report_descr(parent, bcm5974_rdesc,
  575                     sizeof(bcm5974_rdesc));
  576 }
  577 
  578 static int
  579 bcm5974_probe(device_t dev)
  580 {
  581         int err;
  582 
  583         err = HIDBUS_LOOKUP_DRIVER_INFO(dev, bcm5974_devs);
  584         if (err != 0)
  585                 return (err);
  586 
  587         hidbus_set_desc(dev, "Touchpad");
  588 
  589         return (BUS_PROBE_DEFAULT);
  590 }
  591 
  592 static int
  593 bcm5974_attach(device_t dev)
  594 {
  595         struct bcm5974_softc *sc = device_get_softc(dev);
  596         const struct hid_device_info *hw = hid_get_device_info(dev);
  597         int err;
  598 
  599         DPRINTFN(BCM5974_LLEVEL_INFO, "sc=%p\n", sc);
  600 
  601         sc->sc_dev = dev;
  602 
  603         /* get device specific configuration */
  604         sc->sc_params = bcm5974_dev_params + hidbus_get_driver_info(dev);
  605 
  606         sc->sc_evdev = evdev_alloc();
  607         evdev_set_name(sc->sc_evdev, device_get_desc(dev));
  608         evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
  609         evdev_set_id(sc->sc_evdev, hw->idBus, hw->idVendor, hw->idProduct,
  610             hw->idVersion);
  611         evdev_set_serial(sc->sc_evdev, hw->serial);
  612         evdev_set_methods(sc->sc_evdev, sc, &bcm5974_evdev_methods);
  613         evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER);
  614         evdev_support_event(sc->sc_evdev, EV_SYN);
  615         evdev_support_event(sc->sc_evdev, EV_ABS);
  616         evdev_support_event(sc->sc_evdev, EV_KEY);
  617         evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
  618 
  619 #define BCM5974_ABS(evdev, code, param)                                 \
  620         evdev_support_abs((evdev), (code), (param).min, (param).max,    \
  621         ((param).max - (param).min) / (param).snratio, 0,               \
  622         (param).size != 0 ? ((param).max - (param).min) / (param).size : 0);
  623 
  624         /* finger position */
  625         BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_X, sc->sc_params->x);
  626         BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_Y, sc->sc_params->y);
  627         /* finger pressure */
  628         BCM5974_ABS(sc->sc_evdev, ABS_MT_PRESSURE, sc->sc_params->p);
  629         /* finger touch area */
  630         BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MAJOR, sc->sc_params->w);
  631         BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MINOR, sc->sc_params->w);
  632         /* finger approach area */
  633         BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MAJOR, sc->sc_params->w);
  634         BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MINOR, sc->sc_params->w);
  635         /* finger orientation */
  636         BCM5974_ABS(sc->sc_evdev, ABS_MT_ORIENTATION, sc->sc_params->o);
  637         /* button properties */
  638         evdev_support_key(sc->sc_evdev, BTN_LEFT);
  639         if ((sc->sc_params->tp->caps & HAS_INTEGRATED_BUTTON) != 0)
  640                 evdev_support_prop(sc->sc_evdev, INPUT_PROP_BUTTONPAD);
  641         /* Enable automatic touch assignment for type B MT protocol */
  642         evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT,
  643             0, MAX_FINGERS - 1, 0, 0, 0);
  644         evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID,
  645             -1, MAX_FINGERS - 1, 0, 0, 0);
  646         evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_TRACK);
  647         evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_AUTOREL);
  648         /* Synaptics compatibility events */
  649         evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_STCOMPAT);
  650 
  651         err = evdev_register(sc->sc_evdev);
  652         if (err)
  653                 goto detach;
  654 
  655         hidbus_set_intr(dev, bcm5974_intr, sc);
  656 
  657         return (0);
  658 
  659 detach:
  660         bcm5974_detach(dev);
  661         return (ENOMEM);
  662 }
  663 
  664 static int
  665 bcm5974_detach(device_t dev)
  666 {
  667         struct bcm5974_softc *sc = device_get_softc(dev);
  668 
  669         evdev_free(sc->sc_evdev);
  670 
  671         return (0);
  672 }
  673 
  674 static int
  675 bcm5974_resume(device_t dev)
  676 {
  677         struct bcm5974_softc *sc = device_get_softc(dev);
  678 
  679         bcm5974_set_device_mode(sc, sc->sc_saved_mode);
  680 
  681         return (0);
  682 }
  683 
  684 static void
  685 bcm5974_intr(void *context, void *data, hid_size_t len)
  686 {
  687         struct bcm5974_softc *sc = context;
  688         const struct bcm5974_dev_params *params = sc->sc_params;
  689         union evdev_mt_slot slot_data;
  690         struct tp_finger *f;
  691         int ntouch;                     /* the finger number in touch */
  692         int ibt;                        /* button status */
  693         int i;
  694         int slot;
  695         uint8_t fsize = sizeof(struct tp_finger) + params->tp->delta;
  696 
  697         if ((len < params->tp->offset + fsize) ||
  698             ((len - params->tp->offset) % fsize) != 0) {
  699                 DPRINTFN(BCM5974_LLEVEL_INFO, "Invalid length: %d, %x, %x\n",
  700                     len, sc->tp_data[0], sc->tp_data[1]);
  701                 return;
  702         }
  703 
  704         ibt = ((uint8_t *)data)[params->tp->button];
  705         ntouch = (len - params->tp->offset) / fsize;
  706 
  707         for (i = 0, slot = 0; i != ntouch; i++) {
  708                 f = (struct tp_finger *)(((uint8_t *)data) +
  709                     params->tp->offset + params->tp->delta + i * fsize);
  710                 DPRINTFN(BCM5974_LLEVEL_INFO,
  711                     "[%d]ibt=%d, taps=%d, o=%4d, ax=%5d, ay=%5d, "
  712                     "rx=%5d, ry=%5d, tlmaj=%4d, tlmin=%4d, ot=%4x, "
  713                     "tchmaj=%4d, tchmin=%4d, pressure=%4d, m=%4x\n",
  714                     i, ibt, ntouch, BCM5974_LE2H(f->origin),
  715                     BCM5974_LE2H(f->abs_x), BCM5974_LE2H(f->abs_y),
  716                     BCM5974_LE2H(f->rel_x), BCM5974_LE2H(f->rel_y),
  717                     BCM5974_LE2H(f->tool_major), BCM5974_LE2H(f->tool_minor),
  718                     BCM5974_LE2H(f->orientation), BCM5974_LE2H(f->touch_major),
  719                     BCM5974_LE2H(f->touch_minor), BCM5974_LE2H(f->pressure),
  720                     BCM5974_LE2H(f->multi));
  721 
  722                 if (BCM5974_LE2H(f->touch_major) == 0)
  723                         continue;
  724                 slot_data = (union evdev_mt_slot) {
  725                         .id = slot,
  726                         .x = BCM5974_LE2H(f->abs_x),
  727                         .y = params->y.min + params->y.max -
  728                              BCM5974_LE2H(f->abs_y),
  729                         .p = BCM5974_LE2H(f->pressure),
  730                         .maj = BCM5974_LE2H(f->touch_major) << 1,
  731                         .min = BCM5974_LE2H(f->touch_minor) << 1,
  732                         .w_maj = BCM5974_LE2H(f->tool_major) << 1,
  733                         .w_min = BCM5974_LE2H(f->tool_minor) << 1,
  734                         .ori = params->o.max - BCM5974_LE2H(f->orientation),
  735                 };
  736                 evdev_mt_push_slot(sc->sc_evdev, slot, &slot_data);
  737                 slot++;
  738         }
  739 
  740         evdev_push_key(sc->sc_evdev, BTN_LEFT, ibt);
  741         evdev_sync(sc->sc_evdev);
  742 }
  743 
  744 static int
  745 bcm5974_ev_open(struct evdev_dev *evdev)
  746 {
  747         struct bcm5974_softc *sc = evdev_get_softc(evdev);
  748         int err;
  749 
  750         /*
  751          * By default the touchpad behaves like a HID device, sending
  752          * packets with reportID = 8. Such reports contain only
  753          * limited information. They encode movement deltas and button
  754          * events, but do not include data from the pressure
  755          * sensors. The device input mode can be switched from HID
  756          * reports to raw sensor data using vendor-specific USB
  757          * control commands:
  758          */
  759         err = bcm5974_set_device_mode(sc, true);
  760         if (err != 0) {
  761                 DPRINTF("failed to set mode to RAW MODE (%d)\n", err);
  762                 return (err);
  763         }
  764 
  765         return (hidbus_intr_start(sc->sc_dev));
  766 }
  767 
  768 static int
  769 bcm5974_ev_close(struct evdev_dev *evdev)
  770 {
  771         struct bcm5974_softc *sc = evdev_get_softc(evdev);
  772         int err;
  773 
  774         err = hidbus_intr_stop(sc->sc_dev);
  775         if (err != 0)
  776                 return (err);
  777 
  778         /*
  779          * During re-enumeration of the device we need to force the
  780          * device back into HID mode before switching it to RAW
  781          * mode. Else the device does not work like expected.
  782          */
  783         err = bcm5974_set_device_mode(sc, false);
  784         if (err != 0)
  785                 DPRINTF("Failed to set mode to HID MODE (%d)\n", err);
  786 
  787         return (err);
  788 }
  789 
  790 static device_method_t bcm5974_methods[] = {
  791         /* Device interface */
  792         DEVMETHOD(device_identify,      bcm5974_identify),
  793         DEVMETHOD(device_probe,         bcm5974_probe),
  794         DEVMETHOD(device_attach,        bcm5974_attach),
  795         DEVMETHOD(device_detach,        bcm5974_detach),
  796         DEVMETHOD(device_resume,        bcm5974_resume),
  797         DEVMETHOD_END
  798 };
  799 
  800 static driver_t bcm5974_driver = {
  801         .name = "bcm5974",
  802         .methods = bcm5974_methods,
  803         .size = sizeof(struct bcm5974_softc)
  804 };
  805 
  806 DRIVER_MODULE(bcm5974, hidbus, bcm5974_driver, NULL, NULL);
  807 MODULE_DEPEND(bcm5974, hidbus, 1, 1, 1);
  808 MODULE_DEPEND(bcm5974, hid, 1, 1, 1);
  809 MODULE_DEPEND(bcm5974, evdev, 1, 1, 1);
  810 MODULE_VERSION(bcm5974, 1);
  811 HID_PNP_INFO(bcm5974_devs);

Cache object: 822df85601fd4dfe41168ffd32317df3


[ 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.