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

          Line data    Source code
       1             : /*      $OpenBSD: ubcmtp.c,v 1.18 2018/07/30 15:56:30 jcs Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2013-2014, joshua stein <jcs@openbsd.org>
       5             :  * All rights reserved.
       6             :  *
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  * 3. The name of the copyright holder may not be used to endorse or
      16             :  *    promote products derived from this software without specific
      17             :  *    prior written permission.
      18             :  *
      19             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND
      20             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      21             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      22             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE
      23             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      24             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      25             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      26             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      27             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      28             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      29             :  * SUCH DAMAGE.
      30             :  */
      31             : 
      32             : /*
      33             :  * Apple USB multitouch trackpad (Broadcom BCM5974) driver
      34             :  *
      35             :  * Protocol info/magic from bcm5974 Linux driver by Henrik Rydberg, et al.
      36             :  */
      37             : 
      38             : #include <sys/param.h>
      39             : #include <sys/device.h>
      40             : #include <sys/errno.h>
      41             : #include <sys/malloc.h>
      42             : 
      43             : #include <sys/ioctl.h>
      44             : #include <sys/systm.h>
      45             : #include <sys/tty.h>
      46             : 
      47             : #include <dev/usb/usb.h>
      48             : #include <dev/usb/usbdi.h>
      49             : #include <dev/usb/usbdevs.h>
      50             : #include <dev/usb/uhidev.h>
      51             : #include <dev/usb/usbhid.h>
      52             : 
      53             : #include <dev/wscons/wsconsio.h>
      54             : #include <dev/wscons/wsmousevar.h>
      55             : 
      56             : /* #define UBCMTP_DEBUG */
      57             : 
      58             : #ifdef UBCMTP_DEBUG
      59             : #define DPRINTF(x...)   do { printf(x); } while (0);
      60             : #else
      61             : #define DPRINTF(x...)
      62             : #endif
      63             : 
      64             : /* magic to switch device from HID (default) mode into raw */
      65             : #define UBCMTP_WELLSPRING_MODE_RAW      0x01
      66             : #define UBCMTP_WELLSPRING_MODE_HID      0x08
      67             : #define UBCMTP_WELLSPRING_MODE_LEN      8
      68             : #define UBCMTP_WELLSPRING9_MODE_RAW     0x01
      69             : #define UBCMTP_WELLSPRING9_MODE_HID     0x00
      70             : #define UBCMTP_WELLSPRING9_MODE_LEN     2
      71             : 
      72             : struct ubcmtp_button {
      73             :         uint8_t         unused;
      74             :         uint8_t         button;
      75             :         uint8_t         rel_x;
      76             :         uint8_t         rel_y;
      77             : };
      78             : 
      79             : struct ubcmtp_finger {
      80             :         uint16_t        origin;
      81             :         uint16_t        abs_x;
      82             :         uint16_t        abs_y;
      83             :         uint16_t        rel_x;
      84             :         uint16_t        rel_y;
      85             :         uint16_t        tool_major;
      86             :         uint16_t        tool_minor;
      87             :         uint16_t        orientation;
      88             :         uint16_t        touch_major;
      89             :         uint16_t        touch_minor;
      90             :         uint16_t        unused[2];
      91             :         uint16_t        pressure;
      92             :         uint16_t        multi;
      93             : } __packed __attribute((aligned(2)));
      94             : 
      95             : #define UBCMTP_MAX_FINGERS      16
      96             : #define UBCMTP_ALL_FINGER_SIZE  (UBCMTP_MAX_FINGERS * sizeof(struct ubcmtp_finger))
      97             : 
      98             : #define UBCMTP_TYPE1            1
      99             : #define UBCMTP_TYPE1_TPOFF      (13 * sizeof(uint16_t))
     100             : #define UBCMTP_TYPE1_TPLEN      UBCMTP_TYPE1_TPOFF + UBCMTP_ALL_FINGER_SIZE
     101             : #define UBCMTP_TYPE1_TPIFACE    1
     102             : #define UBCMTP_TYPE1_BTIFACE    2
     103             : 
     104             : #define UBCMTP_TYPE2            2
     105             : #define UBCMTP_TYPE2_TPOFF      (15 * sizeof(uint16_t))
     106             : #define UBCMTP_TYPE2_TPLEN      UBCMTP_TYPE2_TPOFF + UBCMTP_ALL_FINGER_SIZE
     107             : #define UBCMTP_TYPE2_TPIFACE    1
     108             : #define UBCMTP_TYPE2_BTOFF      15
     109             : 
     110             : #define UBCMTP_TYPE3            3
     111             : #define UBCMTP_TYPE3_TPOFF      (19 * sizeof(uint16_t))
     112             : #define UBCMTP_TYPE3_TPLEN      UBCMTP_TYPE3_TPOFF + UBCMTP_ALL_FINGER_SIZE
     113             : #define UBCMTP_TYPE3_TPIFACE    2
     114             : #define UBCMTP_TYPE3_BTOFF      23
     115             : 
     116             : #define UBCMTP_TYPE4            4
     117             : #define UBCMTP_TYPE4_TPOFF      (24 * sizeof(uint16_t))
     118             : #define UBCMTP_TYPE4_TPLEN      UBCMTP_TYPE4_TPOFF + UBCMTP_ALL_FINGER_SIZE
     119             : #define UBCMTP_TYPE4_TPIFACE    2
     120             : #define UBCMTP_TYPE4_BTOFF      31
     121             : 
     122             : #define UBCMTP_FINGER_ORIENT    16384
     123             : #define UBCMTP_SN_PRESSURE      45
     124             : #define UBCMTP_SN_WIDTH         25
     125             : #define UBCMTP_SN_COORD         250
     126             : #define UBCMTP_SN_ORIENT        10
     127             : 
     128             : /* Identify clickpads in ubcmtp_configure. */
     129             : #define IS_CLICKPAD(ubcmtp_type) (ubcmtp_type != UBCMTP_TYPE1)
     130             : 
     131             : /* Use a constant, synaptics-compatible pressure value for now. */
     132             : #define DEFAULT_PRESSURE        40
     133             : 
     134             : struct ubcmtp_limit {
     135             :         int limit;
     136             :         int min;
     137             :         int max;
     138             : };
     139             : 
     140             : struct ubcmtp_dev {
     141             :         int vendor;                     /* vendor */
     142             :         int ansi, iso, jis;             /* 3 types of product */
     143             :         int type;                       /* 1 (normal) or 2 (integrated btn) */
     144             :         struct ubcmtp_limit l_pressure; /* finger pressure */
     145             :         struct ubcmtp_limit l_width;    /* finger width */
     146             :         struct ubcmtp_limit l_x;
     147             :         struct ubcmtp_limit l_y;
     148             :         struct ubcmtp_limit l_orientation;
     149             : };
     150             : 
     151             : static struct ubcmtp_dev ubcmtp_devices[] = {
     152             :         /* type 1 devices with separate buttons */
     153             :         {
     154             :                 USB_VENDOR_APPLE,
     155             :                 /* MacbookAir */
     156             :                 USB_PRODUCT_APPLE_WELLSPRING_ANSI,
     157             :                 USB_PRODUCT_APPLE_WELLSPRING_ISO,
     158             :                 USB_PRODUCT_APPLE_WELLSPRING_JIS,
     159             :                 UBCMTP_TYPE1,
     160             :                 { UBCMTP_SN_PRESSURE, 0, 256 },
     161             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     162             :                 { UBCMTP_SN_COORD, -4824, 5342 },
     163             :                 { UBCMTP_SN_COORD, -172, 5820 },
     164             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     165             :         },
     166             :         {
     167             :                 USB_VENDOR_APPLE,
     168             :                 /* MacbookProPenryn */
     169             :                 USB_PRODUCT_APPLE_WELLSPRING2_ANSI,
     170             :                 USB_PRODUCT_APPLE_WELLSPRING2_ISO,
     171             :                 USB_PRODUCT_APPLE_WELLSPRING2_JIS,
     172             :                 UBCMTP_TYPE1,
     173             :                 { UBCMTP_SN_PRESSURE, 0, 256 },
     174             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     175             :                 { UBCMTP_SN_COORD, -4824, 4824 },
     176             :                 { UBCMTP_SN_COORD, -172, 4290 },
     177             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     178             :         },
     179             :         /* type 2 devices with integrated buttons */
     180             :         {
     181             :                 USB_VENDOR_APPLE,
     182             :                 /* Macbook5,1 */
     183             :                 USB_PRODUCT_APPLE_WELLSPRING3_ANSI,
     184             :                 USB_PRODUCT_APPLE_WELLSPRING3_ISO,
     185             :                 USB_PRODUCT_APPLE_WELLSPRING3_JIS,
     186             :                 UBCMTP_TYPE2,
     187             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     188             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     189             :                 { UBCMTP_SN_COORD, -4460, 5166 },
     190             :                 { UBCMTP_SN_COORD, -75, 6700 },
     191             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     192             :         },
     193             :         {
     194             :                 USB_VENDOR_APPLE,
     195             :                 /* MacbookAir3,1 */
     196             :                 USB_PRODUCT_APPLE_WELLSPRING4A_ANSI,
     197             :                 USB_PRODUCT_APPLE_WELLSPRING4A_ISO,
     198             :                 USB_PRODUCT_APPLE_WELLSPRING4A_JIS,
     199             :                 UBCMTP_TYPE2,
     200             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     201             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     202             :                 { UBCMTP_SN_COORD, -4616, 5112 },
     203             :                 { UBCMTP_SN_COORD, -142, 5234 },
     204             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     205             :         },
     206             :         {
     207             :                 USB_VENDOR_APPLE,
     208             :                 /* MacbookAir3,2 */
     209             :                 USB_PRODUCT_APPLE_WELLSPRING4_ANSI,
     210             :                 USB_PRODUCT_APPLE_WELLSPRING4_ISO,
     211             :                 USB_PRODUCT_APPLE_WELLSPRING4_JIS,
     212             :                 UBCMTP_TYPE2,
     213             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     214             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     215             :                 { UBCMTP_SN_COORD, -4620, 5140 },
     216             :                 { UBCMTP_SN_COORD, -150, 6600 },
     217             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     218             :         },
     219             :         {
     220             :                 USB_VENDOR_APPLE,
     221             :                 /* Macbook8 */
     222             :                 USB_PRODUCT_APPLE_WELLSPRING5_ANSI,
     223             :                 USB_PRODUCT_APPLE_WELLSPRING5_ISO,
     224             :                 USB_PRODUCT_APPLE_WELLSPRING5_JIS,
     225             :                 UBCMTP_TYPE2,
     226             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     227             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     228             :                 { UBCMTP_SN_COORD, -4415, 5050 },
     229             :                 { UBCMTP_SN_COORD, -55, 6680 },
     230             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     231             :         },
     232             :         {
     233             :                 USB_VENDOR_APPLE,
     234             :                 /* Macbook8,2 */
     235             :                 USB_PRODUCT_APPLE_WELLSPRING5A_ANSI,
     236             :                 USB_PRODUCT_APPLE_WELLSPRING5A_ISO,
     237             :                 USB_PRODUCT_APPLE_WELLSPRING5A_JIS,
     238             :                 UBCMTP_TYPE2,
     239             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     240             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     241             :                 { UBCMTP_SN_COORD, -4750, 5280 },
     242             :                 { UBCMTP_SN_COORD, -150, 6730 },
     243             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     244             :         },
     245             :         {
     246             :                 USB_VENDOR_APPLE,
     247             :                 /* MacbookAir4,2 */
     248             :                 USB_PRODUCT_APPLE_WELLSPRING6_ANSI,
     249             :                 USB_PRODUCT_APPLE_WELLSPRING6_ISO,
     250             :                 USB_PRODUCT_APPLE_WELLSPRING6_JIS,
     251             :                 UBCMTP_TYPE2,
     252             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     253             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     254             :                 { UBCMTP_SN_COORD, -4620, 5140 },
     255             :                 { UBCMTP_SN_COORD, -150, 6600 },
     256             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     257             :         },
     258             :         {
     259             :                 USB_VENDOR_APPLE,
     260             :                 /* MacbookAir4,1 */
     261             :                 USB_PRODUCT_APPLE_WELLSPRING6A_ANSI,
     262             :                 USB_PRODUCT_APPLE_WELLSPRING6A_ISO,
     263             :                 USB_PRODUCT_APPLE_WELLSPRING6A_JIS,
     264             :                 UBCMTP_TYPE2,
     265             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     266             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     267             :                 { UBCMTP_SN_COORD, -4620, 5140 },
     268             :                 { UBCMTP_SN_COORD, -150, 6600 },
     269             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     270             :         },
     271             :         {
     272             :                 USB_VENDOR_APPLE,
     273             :                 /* MacbookPro10,1 */
     274             :                 USB_PRODUCT_APPLE_WELLSPRING7_ANSI,
     275             :                 USB_PRODUCT_APPLE_WELLSPRING7_ISO,
     276             :                 USB_PRODUCT_APPLE_WELLSPRING7_JIS,
     277             :                 UBCMTP_TYPE2,
     278             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     279             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     280             :                 { UBCMTP_SN_COORD, -4750, 5280 },
     281             :                 { UBCMTP_SN_COORD, -150, 6730 },
     282             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     283             :         },
     284             :         {
     285             :                 USB_VENDOR_APPLE,
     286             :                 /* MacbookPro10,2 */
     287             :                 USB_PRODUCT_APPLE_WELLSPRING7A_ANSI,
     288             :                 USB_PRODUCT_APPLE_WELLSPRING7A_ISO,
     289             :                 USB_PRODUCT_APPLE_WELLSPRING7A_JIS,
     290             :                 UBCMTP_TYPE2,
     291             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     292             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     293             :                 { UBCMTP_SN_COORD, -4750, 5280 },
     294             :                 { UBCMTP_SN_COORD, -150, 6730 },
     295             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     296             :         },
     297             :         {
     298             :                 USB_VENDOR_APPLE,
     299             :                 /* MacbookAir6,1 */
     300             :                 USB_PRODUCT_APPLE_WELLSPRING8_ANSI,
     301             :                 USB_PRODUCT_APPLE_WELLSPRING8_ISO,
     302             :                 USB_PRODUCT_APPLE_WELLSPRING8_JIS,
     303             :                 UBCMTP_TYPE3,
     304             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     305             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     306             :                 { UBCMTP_SN_COORD, -4620, 5140 },
     307             :                 { UBCMTP_SN_COORD, -150, 6600 },
     308             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     309             :         },
     310             :         {
     311             :                 USB_VENDOR_APPLE,
     312             :                 /* MacbookPro12,1 */
     313             :                 USB_PRODUCT_APPLE_WELLSPRING9_ANSI,
     314             :                 USB_PRODUCT_APPLE_WELLSPRING9_ISO,
     315             :                 USB_PRODUCT_APPLE_WELLSPRING9_JIS,
     316             :                 UBCMTP_TYPE4,
     317             :                 { UBCMTP_SN_PRESSURE, 0, 300 },
     318             :                 { UBCMTP_SN_WIDTH, 0, 2048 },
     319             :                 { UBCMTP_SN_COORD, -4828, 5345 },
     320             :                 { UBCMTP_SN_COORD, -203, 6803 },
     321             :                 { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT },
     322             :         },
     323             : };
     324             : 
     325             : struct ubcmtp_softc {
     326             :         struct device           sc_dev;         /* base device */
     327             : 
     328             :         struct ubcmtp_dev       *dev_type;
     329             : 
     330             :         struct uhidev           sc_hdev;
     331             :         struct usbd_device      *sc_udev;
     332             :         struct device           *sc_wsmousedev;
     333             : 
     334             :         int                     tp_ifacenum;    /* trackpad interface number */
     335             :         struct usbd_interface   *sc_tp_iface;   /* trackpad interface */
     336             :         struct usbd_pipe        *sc_tp_pipe;    /* trackpad pipe */
     337             :         int                     sc_tp_epaddr;   /* endpoint addr */
     338             :         int                     tp_maxlen;      /* max size of tp data */
     339             :         int                     tp_offset;      /* finger offset into data */
     340             :         uint8_t                 *tp_pkt;
     341             : 
     342             :         int                     bt_ifacenum;    /* button interface number */
     343             :         struct usbd_interface   *sc_bt_iface;   /* button interface */
     344             :         struct usbd_pipe        *sc_bt_pipe;    /* button pipe */
     345             :         int                     sc_bt_epaddr;   /* endpoint addr */
     346             :         int                     bt_maxlen;      /* max size of button data */
     347             :         uint8_t                 *bt_pkt;
     348             : 
     349             :         uint32_t                sc_status;
     350             : #define UBCMTP_ENABLED          1
     351             : 
     352             :         struct mtpoint          frame[UBCMTP_MAX_FINGERS];
     353             :         int                     contacts;
     354             :         int                     btn;
     355             : };
     356             : 
     357             : int     ubcmtp_enable(void *);
     358             : void    ubcmtp_disable(void *);
     359             : int     ubcmtp_ioctl(void *, unsigned long, caddr_t, int, struct proc *);
     360             : int     ubcmtp_raw_mode(struct ubcmtp_softc *, int);
     361             : int     ubcmtp_setup_pipes(struct ubcmtp_softc *);
     362             : void    ubcmtp_bt_intr(struct usbd_xfer *, void *, usbd_status);
     363             : void    ubcmtp_tp_intr(struct usbd_xfer *, void *, usbd_status);
     364             : 
     365             : int     ubcmtp_match(struct device *, void *, void *);
     366             : void    ubcmtp_attach(struct device *, struct device *, void *);
     367             : int     ubcmtp_detach(struct device *, int);
     368             : int     ubcmtp_activate(struct device *, int);
     369             : int     ubcmtp_configure(struct ubcmtp_softc *);
     370             : 
     371             : const struct wsmouse_accessops ubcmtp_accessops = {
     372             :         ubcmtp_enable,
     373             :         ubcmtp_ioctl,
     374             :         ubcmtp_disable,
     375             : };
     376             : 
     377             : struct cfdriver ubcmtp_cd = {
     378             :         NULL, "ubcmtp", DV_DULL
     379             : };
     380             : 
     381             : const struct cfattach ubcmtp_ca = {
     382             :         sizeof(struct ubcmtp_softc), ubcmtp_match, ubcmtp_attach, ubcmtp_detach,
     383             :         ubcmtp_activate,
     384             : };
     385             : 
     386             : int
     387           0 : ubcmtp_match(struct device *parent, void *match, void *aux)
     388             : {
     389           0 :         struct usb_attach_arg *uaa = aux;
     390             :         usb_interface_descriptor_t *id;
     391             :         int i;
     392             : 
     393           0 :         if (uaa->iface == NULL)
     394           0 :                 return (UMATCH_NONE);
     395             : 
     396           0 :         for (i = 0; i < nitems(ubcmtp_devices); i++) {
     397           0 :                 if (uaa->vendor == ubcmtp_devices[i].vendor && (
     398           0 :                     uaa->product == ubcmtp_devices[i].ansi ||
     399           0 :                     uaa->product == ubcmtp_devices[i].iso ||
     400           0 :                     uaa->product == ubcmtp_devices[i].jis)) {
     401             :                         /*
     402             :                          * The USB keyboard/mouse device will have one keyboard
     403             :                          * HID and two mouse HIDs, though only one will have a
     404             :                          * protocol of mouse -- we only want to take control of
     405             :                          * that one.
     406             :                          */
     407           0 :                         id = usbd_get_interface_descriptor(uaa->iface);
     408           0 :                         if (id->bInterfaceProtocol == UIPROTO_BOOT_MOUSE)
     409           0 :                                 return (UMATCH_VENDOR_PRODUCT_CONF_IFACE);
     410             :                 }
     411             :         }
     412             : 
     413           0 :         return (UMATCH_NONE);
     414           0 : }
     415             : 
     416             : void
     417           0 : ubcmtp_attach(struct device *parent, struct device *self, void *aux)
     418             : {
     419           0 :         struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self;
     420           0 :         struct usb_attach_arg *uaa = aux;
     421           0 :         struct usbd_device *dev = uaa->device;
     422           0 :         struct wsmousedev_attach_args a;
     423             :         usb_device_descriptor_t *udd;
     424             :         int i;
     425             : 
     426           0 :         sc->sc_udev = uaa->device;
     427           0 :         sc->sc_status = 0;
     428             : 
     429           0 :         if ((udd = usbd_get_device_descriptor(dev)) == NULL) {
     430           0 :                 printf("ubcmtp: failed getting device descriptor\n");
     431           0 :                 return;
     432             :         }
     433             : 
     434           0 :         for (i = 0; i < nitems(ubcmtp_devices); i++) {
     435           0 :                 if (uaa->vendor == ubcmtp_devices[i].vendor && (
     436           0 :                     uaa->product == ubcmtp_devices[i].ansi ||
     437           0 :                     uaa->product == ubcmtp_devices[i].iso ||
     438           0 :                     uaa->product == ubcmtp_devices[i].jis)) {
     439           0 :                         sc->dev_type = &ubcmtp_devices[i];
     440             :                         DPRINTF("%s: attached to 0x%x/0x%x type %d\n",
     441             :                             sc->sc_dev.dv_xname, uaa->vendor, uaa->product,
     442             :                             sc->dev_type->type);
     443           0 :                         break;
     444             :                 }
     445             :         }
     446             : 
     447           0 :         if (sc->dev_type == NULL) {
     448             :                 /* how did we match then? */
     449           0 :                 printf("%s: failed looking up device in table\n",
     450           0 :                     sc->sc_dev.dv_xname);
     451           0 :                 return;
     452             :         }
     453             : 
     454           0 :         switch (sc->dev_type->type) {
     455             :         case UBCMTP_TYPE1:
     456           0 :                 sc->tp_maxlen = UBCMTP_TYPE1_TPLEN;
     457           0 :                 sc->tp_offset = UBCMTP_TYPE1_TPOFF;
     458           0 :                 sc->tp_ifacenum = UBCMTP_TYPE1_TPIFACE;
     459             : 
     460             :                 /* button offsets */
     461           0 :                 sc->bt_maxlen = sizeof(struct ubcmtp_button);
     462           0 :                 sc->bt_ifacenum = UBCMTP_TYPE1_BTIFACE;
     463           0 :                 break;
     464             : 
     465             :         case UBCMTP_TYPE2:
     466           0 :                 sc->tp_maxlen = UBCMTP_TYPE2_TPLEN;
     467           0 :                 sc->tp_offset = UBCMTP_TYPE2_TPOFF;
     468           0 :                 sc->tp_ifacenum = UBCMTP_TYPE2_TPIFACE;
     469           0 :                 break;
     470             : 
     471             :         case UBCMTP_TYPE3:
     472           0 :                 sc->tp_maxlen = UBCMTP_TYPE3_TPLEN;
     473           0 :                 sc->tp_offset = UBCMTP_TYPE3_TPOFF;
     474           0 :                 sc->tp_ifacenum = UBCMTP_TYPE3_TPIFACE;
     475           0 :                 break;
     476             : 
     477             :         case UBCMTP_TYPE4:
     478           0 :                 sc->tp_maxlen = UBCMTP_TYPE4_TPLEN;
     479           0 :                 sc->tp_offset = UBCMTP_TYPE4_TPOFF;
     480           0 :                 sc->tp_ifacenum = UBCMTP_TYPE4_TPIFACE;
     481           0 :                 break;
     482             :         }
     483             : 
     484           0 :         a.accessops = &ubcmtp_accessops;
     485           0 :         a.accesscookie = sc;
     486             : 
     487           0 :         sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
     488           0 :         if (sc->sc_wsmousedev != NULL && ubcmtp_configure(sc))
     489           0 :                 ubcmtp_disable(sc);
     490           0 : }
     491             : 
     492             : int
     493           0 : ubcmtp_detach(struct device *self, int flags)
     494             : {
     495           0 :         struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self;
     496             :         int ret = 0;
     497             : 
     498           0 :         if (sc->sc_wsmousedev != NULL)
     499           0 :                 ret = config_detach(sc->sc_wsmousedev, flags);
     500             : 
     501           0 :         return (ret);
     502             : }
     503             : 
     504             : int
     505           0 : ubcmtp_activate(struct device *self, int act)
     506             : {
     507           0 :         struct ubcmtp_softc *sc = (struct ubcmtp_softc *)self;
     508             :         int rv = 0;
     509             : 
     510           0 :         if (act == DVACT_DEACTIVATE) {
     511           0 :                 if (sc->sc_wsmousedev != NULL)
     512           0 :                         rv = config_deactivate(sc->sc_wsmousedev);
     513           0 :                 usbd_deactivate(sc->sc_udev);
     514           0 :         }
     515             : 
     516           0 :         return (rv);
     517             : }
     518             : 
     519             : int
     520           0 : ubcmtp_configure(struct ubcmtp_softc *sc)
     521             : {
     522           0 :         struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
     523             : 
     524           0 :         hw->type = WSMOUSE_TYPE_TOUCHPAD;
     525           0 :         hw->hw_type = (IS_CLICKPAD(sc->dev_type->type)
     526             :             ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD);
     527           0 :         hw->x_min = sc->dev_type->l_x.min;
     528           0 :         hw->x_max = sc->dev_type->l_x.max;
     529           0 :         hw->y_min = sc->dev_type->l_y.min;
     530           0 :         hw->y_max = sc->dev_type->l_y.max;
     531           0 :         hw->mt_slots = UBCMTP_MAX_FINGERS;
     532           0 :         hw->flags = WSMOUSEHW_MT_TRACKING;
     533             : 
     534           0 :         return wsmouse_configure(sc->sc_wsmousedev, NULL, 0);
     535             : }
     536             : 
     537             : int
     538           0 : ubcmtp_enable(void *v)
     539             : {
     540           0 :         struct ubcmtp_softc *sc = v;
     541             : 
     542           0 :         if (sc->sc_status & UBCMTP_ENABLED)
     543           0 :                 return (EBUSY);
     544             : 
     545           0 :         if (usbd_is_dying(sc->sc_udev))
     546           0 :                 return (EIO);
     547             : 
     548           0 :         if (ubcmtp_raw_mode(sc, 1) != 0) {
     549           0 :                 printf("%s: failed to enter raw mode\n", sc->sc_dev.dv_xname);
     550           0 :                 return (1);
     551             :         }
     552             : 
     553           0 :         if (ubcmtp_setup_pipes(sc) == 0) {
     554           0 :                 sc->sc_status |= UBCMTP_ENABLED;
     555           0 :                 return (0);
     556             :         } else
     557           0 :                 return (1);
     558           0 : }
     559             : 
     560             : void
     561           0 : ubcmtp_disable(void *v)
     562             : {
     563           0 :         struct ubcmtp_softc *sc = v;
     564             : 
     565           0 :         if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED))
     566           0 :                 return;
     567             : 
     568           0 :         sc->sc_status &= ~UBCMTP_ENABLED;
     569             : 
     570           0 :         ubcmtp_raw_mode(sc, 0);
     571             : 
     572           0 :         if (sc->sc_tp_pipe != NULL) {
     573           0 :                 usbd_abort_pipe(sc->sc_tp_pipe);
     574           0 :                 usbd_close_pipe(sc->sc_tp_pipe);
     575           0 :                 sc->sc_tp_pipe = NULL;
     576           0 :         }
     577           0 :         if (sc->sc_bt_pipe != NULL) {
     578           0 :                 usbd_abort_pipe(sc->sc_bt_pipe);
     579           0 :                 usbd_close_pipe(sc->sc_bt_pipe);
     580           0 :                 sc->sc_bt_pipe = NULL;
     581           0 :         }
     582             : 
     583           0 :         if (sc->tp_pkt != NULL) {
     584           0 :                 free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen);
     585           0 :                 sc->tp_pkt = NULL;
     586           0 :         }
     587           0 :         if (sc->bt_pkt != NULL) {
     588           0 :                 free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen);
     589           0 :                 sc->bt_pkt = NULL;
     590           0 :         }
     591           0 : }
     592             : 
     593             : int
     594           0 : ubcmtp_ioctl(void *v, unsigned long cmd, caddr_t data, int flag, struct proc *p)
     595             : {
     596           0 :         struct ubcmtp_softc *sc = v;
     597           0 :         struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
     598             :         int wsmode;
     599             : 
     600             :         DPRINTF("%s: in %s with cmd 0x%lx\n", sc->sc_dev.dv_xname, __func__,
     601             :             cmd);
     602             : 
     603           0 :         switch (cmd) {
     604             :         case WSMOUSEIO_GTYPE: {
     605           0 :                 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
     606           0 :                 *(u_int *)data = hw->type;
     607             :                 break;
     608             :         }
     609             : 
     610             :         case WSMOUSEIO_GCALIBCOORDS:
     611           0 :                 wsmc->minx = sc->dev_type->l_x.min;
     612           0 :                 wsmc->maxx = sc->dev_type->l_x.max;
     613           0 :                 wsmc->miny = sc->dev_type->l_y.min;
     614           0 :                 wsmc->maxy = sc->dev_type->l_y.max;
     615           0 :                 wsmc->swapxy = 0;
     616           0 :                 wsmc->resx = 0;
     617           0 :                 wsmc->resy = 0;
     618           0 :                 break;
     619             : 
     620             :         case WSMOUSEIO_SETMODE:
     621           0 :                 wsmode = *(u_int *)data;
     622           0 :                 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) {
     623           0 :                         printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname,
     624             :                             wsmode);
     625           0 :                         return (EINVAL);
     626             :                 }
     627           0 :                 wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
     628             : 
     629             :                 DPRINTF("%s: changing mode to %s\n",
     630             :                     sc->sc_dev.dv_xname, (wsmode == WSMOUSE_COMPAT ? "compat" :
     631             :                     "native"));
     632             : 
     633           0 :                 break;
     634             : 
     635             :         default:
     636           0 :                 return (-1);
     637             :         }
     638             : 
     639           0 :         return (0);
     640           0 : }
     641             : 
     642             : int
     643           0 : ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable)
     644             : {
     645           0 :         usb_device_request_t r;
     646             :         usbd_status err;
     647           0 :         uint8_t buf[8];
     648             : 
     649             :         /* type 3 has no raw mode */
     650           0 :         if (sc->dev_type->type == UBCMTP_TYPE3)
     651           0 :                 return (0);
     652             : 
     653           0 :         r.bRequest = UR_GET_REPORT;
     654           0 :         r.bmRequestType = UT_READ_CLASS_INTERFACE;
     655           0 :         if (sc->dev_type->type < UBCMTP_TYPE4) {
     656           0 :                 USETW2(r.wValue, UHID_FEATURE_REPORT, 0);
     657           0 :                 USETW(r.wIndex, 0);
     658           0 :                 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN);
     659           0 :         } else {
     660           0 :                 USETW2(r.wValue, UHID_FEATURE_REPORT, 2);
     661           0 :                 USETW(r.wIndex, 2);
     662           0 :                 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN);
     663             :         }
     664             : 
     665           0 :         err = usbd_do_request(sc->sc_udev, &r, buf);
     666           0 :         if (err != USBD_NORMAL_COMPLETION) {
     667           0 :                 printf("%s: %s: failed to get feature report\n",
     668           0 :                     sc->sc_dev.dv_xname, __func__);
     669           0 :                 return (err);
     670             :         }
     671             : 
     672             :         /* toggle magic byte and write everything back */
     673           0 :         if (sc->dev_type->type < UBCMTP_TYPE4)
     674           0 :                 buf[0] = (enable ? UBCMTP_WELLSPRING_MODE_RAW :
     675             :                     UBCMTP_WELLSPRING_MODE_HID);
     676             :         else
     677           0 :                 buf[1] = (enable ? UBCMTP_WELLSPRING9_MODE_RAW :
     678             :                     UBCMTP_WELLSPRING9_MODE_HID);
     679             : 
     680           0 :         r.bRequest = UR_SET_REPORT;
     681           0 :         r.bmRequestType = UT_WRITE_CLASS_INTERFACE;
     682           0 :         if (sc->dev_type->type < UBCMTP_TYPE4) {
     683           0 :                 USETW2(r.wValue, UHID_FEATURE_REPORT, 0);
     684           0 :                 USETW(r.wIndex, 0);
     685           0 :                 USETW(r.wLength, UBCMTP_WELLSPRING_MODE_LEN);
     686           0 :         } else {
     687           0 :                 USETW2(r.wValue, UHID_FEATURE_REPORT, 2);
     688           0 :                 USETW(r.wIndex, 2);
     689           0 :                 USETW(r.wLength, UBCMTP_WELLSPRING9_MODE_LEN);
     690             :         }
     691             : 
     692           0 :         err = usbd_do_request(sc->sc_udev, &r, buf);
     693           0 :         if (err != USBD_NORMAL_COMPLETION) {
     694           0 :                 printf("%s: %s: failed to toggle raw mode\n",
     695           0 :                     sc->sc_dev.dv_xname, __func__);
     696           0 :                 return (err);
     697             :         }
     698             : 
     699           0 :         return (0);
     700           0 : }
     701             : 
     702             : int
     703           0 : ubcmtp_setup_pipes(struct ubcmtp_softc *sc)
     704             : {
     705             :         usbd_status err;
     706             :         usb_endpoint_descriptor_t *ed;
     707             : 
     708           0 :         if (sc->dev_type->type == UBCMTP_TYPE1) {
     709             :                 /* setup physical button pipe */
     710             : 
     711           0 :                 if ((err = usbd_device2interface_handle(sc->sc_udev,
     712           0 :                     sc->bt_ifacenum, &sc->sc_bt_iface)) != 0) {
     713           0 :                         printf("%s: failed getting button interface\n",
     714           0 :                             sc->sc_dev.dv_xname);
     715           0 :                         goto fail1;
     716             :                 }
     717           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_bt_iface, 0);
     718           0 :                 if (ed == NULL) {
     719           0 :                         printf("%s: failed getting button endpoint descriptor\n",
     720           0 :                             sc->sc_dev.dv_xname);
     721           0 :                         goto fail1;
     722             :                 }
     723           0 :                 sc->sc_bt_epaddr = ed->bEndpointAddress;
     724           0 :                 sc->bt_pkt = malloc(sc->bt_maxlen, M_USBDEV, M_WAITOK);
     725           0 :                 if (sc->bt_pkt == NULL)
     726             :                         goto fail1;
     727             : 
     728             :                 DPRINTF("%s: button iface at 0x%x, max size %d\n",
     729             :                     sc->sc_dev.dv_xname, sc->sc_bt_epaddr, sc->bt_maxlen);
     730             : 
     731           0 :                 err = usbd_open_pipe_intr(sc->sc_bt_iface, sc->sc_bt_epaddr,
     732           0 :                     USBD_SHORT_XFER_OK, &sc->sc_bt_pipe, sc, sc->bt_pkt,
     733           0 :                     sc->bt_maxlen, ubcmtp_bt_intr, USBD_DEFAULT_INTERVAL);
     734           0 :                 if (err != USBD_NORMAL_COMPLETION) {
     735           0 :                         printf("%s: failed opening button pipe\n",
     736           0 :                             sc->sc_dev.dv_xname);
     737           0 :                         goto fail1;
     738             :                 }
     739             :         }
     740             : 
     741             :         /* setup trackpad data pipe */
     742             : 
     743           0 :         if ((err = usbd_device2interface_handle(sc->sc_udev, sc->tp_ifacenum,
     744           0 :             &sc->sc_tp_iface)) != 0) {
     745           0 :                 printf("%s: failed getting trackpad data interface\n",
     746           0 :                     sc->sc_dev.dv_xname);
     747           0 :                 goto fail2;
     748             :         }
     749           0 :         ed = usbd_interface2endpoint_descriptor(sc->sc_tp_iface, 0);
     750           0 :         if (ed == NULL) {
     751           0 :                 printf("%s: failed getting trackpad data endpoint descriptor\n",
     752           0 :                     sc->sc_dev.dv_xname);
     753           0 :                 goto fail2;
     754             :         }
     755           0 :         sc->sc_tp_epaddr = ed->bEndpointAddress;
     756           0 :         sc->tp_pkt = malloc(sc->tp_maxlen, M_USBDEV, M_WAITOK);
     757           0 :         if (sc->tp_pkt == NULL)
     758             :                 goto fail2;
     759             : 
     760             :         DPRINTF("%s: trackpad data iface at 0x%x, max size %d\n",
     761             :             sc->sc_dev.dv_xname, sc->sc_tp_epaddr, sc->tp_maxlen);
     762             : 
     763           0 :         err = usbd_open_pipe_intr(sc->sc_tp_iface, sc->sc_tp_epaddr,
     764           0 :             USBD_SHORT_XFER_OK, &sc->sc_tp_pipe, sc, sc->tp_pkt, sc->tp_maxlen,
     765             :             ubcmtp_tp_intr, USBD_DEFAULT_INTERVAL);
     766           0 :         if (err != USBD_NORMAL_COMPLETION) {
     767           0 :                 printf("%s: error opening trackpad data pipe\n",
     768           0 :                     sc->sc_dev.dv_xname);
     769           0 :                 goto fail2;
     770             :         }
     771             : 
     772           0 :         return (0);
     773             : 
     774             : fail2:
     775           0 :         if (sc->sc_tp_pipe != NULL) {
     776           0 :                 usbd_abort_pipe(sc->sc_tp_pipe);
     777           0 :                 usbd_close_pipe(sc->sc_tp_pipe);
     778           0 :         }
     779           0 :         if (sc->tp_pkt != NULL)
     780           0 :                 free(sc->tp_pkt, M_USBDEV, sc->tp_maxlen);
     781             : fail1:
     782           0 :         if (sc->sc_bt_pipe != NULL) {
     783           0 :                 usbd_abort_pipe(sc->sc_bt_pipe);
     784           0 :                 usbd_close_pipe(sc->sc_bt_pipe);
     785           0 :         }
     786           0 :         if (sc->bt_pkt != NULL)
     787           0 :                 free(sc->bt_pkt, M_USBDEV, sc->bt_maxlen);
     788             : 
     789           0 :         return (1);
     790           0 : }
     791             : 
     792             : void
     793           0 : ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
     794             : {
     795           0 :         struct ubcmtp_softc *sc = priv;
     796             :         struct ubcmtp_finger *pkt;
     797           0 :         u_int32_t pktlen;
     798             :         int i, s, btn, contacts, fingers;
     799             : 
     800           0 :         if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED))
     801           0 :                 return;
     802             : 
     803           0 :         if (status != USBD_NORMAL_COMPLETION) {
     804             :                 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname,
     805             :                     __func__, status);
     806             : 
     807           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     808           0 :                         return;
     809           0 :                 if (status == USBD_STALLED)
     810           0 :                         usbd_clear_endpoint_stall_async(sc->sc_tp_pipe);
     811           0 :                 return;
     812             :         }
     813             : 
     814           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &pktlen, NULL);
     815             : 
     816           0 :         if (sc->tp_pkt == NULL || pktlen < sc->tp_offset)
     817           0 :                 return;
     818             : 
     819           0 :         pkt = (struct ubcmtp_finger *)(sc->tp_pkt + sc->tp_offset);
     820           0 :         fingers = (pktlen - sc->tp_offset) / sizeof(struct ubcmtp_finger);
     821             : 
     822             :         contacts = 0;
     823           0 :         for (i = 0; i < fingers; i++) {
     824           0 :                 if ((int16_t)letoh16(pkt[i].touch_major) == 0)
     825             :                         continue; /* finger lifted */
     826           0 :                 sc->frame[contacts].x = (int16_t)letoh16(pkt[i].abs_x);
     827           0 :                 sc->frame[contacts].y = (int16_t)letoh16(pkt[i].abs_y);
     828           0 :                 sc->frame[contacts].pressure = DEFAULT_PRESSURE;
     829           0 :                 contacts++;
     830           0 :         }
     831             : 
     832           0 :         btn = sc->btn;
     833           0 :         if (sc->dev_type->type == UBCMTP_TYPE2)
     834           0 :                 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE2_BTOFF]));
     835           0 :         else if (sc->dev_type->type == UBCMTP_TYPE3)
     836           0 :                 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE3_BTOFF]));
     837           0 :         else if (sc->dev_type->type == UBCMTP_TYPE4)
     838           0 :                 sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE4_BTOFF]));
     839             : 
     840           0 :         if (contacts || sc->contacts || sc->btn != btn) {
     841           0 :                 sc->contacts = contacts;
     842           0 :                 s = spltty();
     843           0 :                 wsmouse_buttons(sc->sc_wsmousedev, sc->btn);
     844           0 :                 wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts);
     845           0 :                 wsmouse_input_sync(sc->sc_wsmousedev);
     846           0 :                 splx(s);
     847           0 :         }
     848           0 : }
     849             : 
     850             : /* hardware button interrupt */
     851             : void
     852           0 : ubcmtp_bt_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
     853             : {
     854           0 :         struct ubcmtp_softc *sc = priv;
     855             :         struct ubcmtp_button *pkt;
     856           0 :         u_int32_t len;
     857             : 
     858           0 :         if (usbd_is_dying(sc->sc_udev) || !(sc->sc_status & UBCMTP_ENABLED))
     859           0 :                 return;
     860             : 
     861           0 :         if (status != USBD_NORMAL_COMPLETION) {
     862             :                 DPRINTF("%s: %s with status 0x%x\n", sc->sc_dev.dv_xname,
     863             :                     __func__, status);
     864           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     865           0 :                         return;
     866           0 :                 if (status == USBD_STALLED)
     867           0 :                         usbd_clear_endpoint_stall_async(sc->sc_tp_pipe);
     868           0 :                 return;
     869             :         }
     870             : 
     871           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
     872             : 
     873           0 :         if (sc->bt_pkt == NULL || len < sizeof(struct ubcmtp_button))
     874           0 :                 return;
     875             : 
     876           0 :         pkt = (struct ubcmtp_button *)(sc->bt_pkt);
     877             : 
     878             :         DPRINTF("%s: button interrupt (%d, %d, %d, %d)", sc->sc_dev.dv_xname,
     879             :             pkt->unused, pkt->button, pkt->rel_x, pkt->rel_y);
     880             : 
     881           0 :         if (pkt->button != sc->btn) {
     882           0 :                 sc->btn = pkt->button;
     883           0 :                 wsmouse_buttons(sc->sc_wsmousedev, sc->btn);
     884           0 :                 wsmouse_input_sync(sc->sc_wsmousedev);
     885           0 :         }
     886           0 : }

Generated by: LCOV version 1.13