15aa839c9SVladimir Kondratyev /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35aa839c9SVladimir Kondratyev * 45aa839c9SVladimir Kondratyev * Copyright (c) 2012 Huang Wen Hui 55aa839c9SVladimir Kondratyev * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org> 65aa839c9SVladimir Kondratyev * All rights reserved. 75aa839c9SVladimir Kondratyev * 85aa839c9SVladimir Kondratyev * Redistribution and use in source and binary forms, with or without 95aa839c9SVladimir Kondratyev * modification, are permitted provided that the following conditions 105aa839c9SVladimir Kondratyev * are met: 115aa839c9SVladimir Kondratyev * 1. Redistributions of source code must retain the above copyright 125aa839c9SVladimir Kondratyev * notice, this list of conditions and the following disclaimer. 135aa839c9SVladimir Kondratyev * 2. Redistributions in binary form must reproduce the above copyright 145aa839c9SVladimir Kondratyev * notice, this list of conditions and the following disclaimer in the 155aa839c9SVladimir Kondratyev * documentation and/or other materials provided with the distribution. 165aa839c9SVladimir Kondratyev * 175aa839c9SVladimir Kondratyev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 185aa839c9SVladimir Kondratyev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 195aa839c9SVladimir Kondratyev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 205aa839c9SVladimir Kondratyev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 215aa839c9SVladimir Kondratyev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 225aa839c9SVladimir Kondratyev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 235aa839c9SVladimir Kondratyev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 245aa839c9SVladimir Kondratyev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 255aa839c9SVladimir Kondratyev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 265aa839c9SVladimir Kondratyev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 275aa839c9SVladimir Kondratyev * SUCH DAMAGE. 285aa839c9SVladimir Kondratyev */ 295aa839c9SVladimir Kondratyev 304f345989SVladimir Kondratyev #include "opt_hid.h" 314f345989SVladimir Kondratyev 325aa839c9SVladimir Kondratyev #include <sys/param.h> 335aa839c9SVladimir Kondratyev #include <sys/bus.h> 345aa839c9SVladimir Kondratyev #include <sys/endian.h> 355aa839c9SVladimir Kondratyev #include <sys/kernel.h> 365aa839c9SVladimir Kondratyev #include <sys/malloc.h> 375aa839c9SVladimir Kondratyev #include <sys/module.h> 385aa839c9SVladimir Kondratyev #include <sys/sysctl.h> 395aa839c9SVladimir Kondratyev #include <sys/systm.h> 405aa839c9SVladimir Kondratyev 415aa839c9SVladimir Kondratyev #include <dev/evdev/input.h> 425aa839c9SVladimir Kondratyev #include <dev/evdev/evdev.h> 435aa839c9SVladimir Kondratyev 445aa839c9SVladimir Kondratyev #define HID_DEBUG_VAR bcm5974_debug 455aa839c9SVladimir Kondratyev #include <dev/hid/hid.h> 465aa839c9SVladimir Kondratyev #include <dev/hid/hidbus.h> 475aa839c9SVladimir Kondratyev #include <dev/hid/hidquirk.h> 485aa839c9SVladimir Kondratyev 495aa839c9SVladimir Kondratyev #include <dev/usb/usb.h> 505aa839c9SVladimir Kondratyev #include <dev/usb/usbdi.h> 515aa839c9SVladimir Kondratyev #include <dev/usb/usbhid.h> 525aa839c9SVladimir Kondratyev #include <dev/usb/usb_ioctl.h> 535aa839c9SVladimir Kondratyev 545aa839c9SVladimir Kondratyev #include "usbdevs.h" 555aa839c9SVladimir Kondratyev 561c4edee3SVal Packett #define BCM5974_BUFFER_MAX (246 * 2) /* 2 Type4 SPI frames */ 575aa839c9SVladimir Kondratyev #define BCM5974_TLC_PAGE HUP_GENERIC_DESKTOP 585aa839c9SVladimir Kondratyev #define BCM5974_TLC_USAGE HUG_MOUSE 595aa839c9SVladimir Kondratyev 605aa839c9SVladimir Kondratyev /* magic to switch device from HID (default) mode into raw */ 615aa839c9SVladimir Kondratyev /* Type1 & Type2 trackpads */ 625aa839c9SVladimir Kondratyev #define BCM5974_USB_IFACE_INDEX 0 635aa839c9SVladimir Kondratyev #define BCM5974_USB_REPORT_LEN 8 645aa839c9SVladimir Kondratyev #define BCM5974_USB_REPORT_ID 0 655aa839c9SVladimir Kondratyev #define BCM5974_USB_MODE_RAW 0x01 665aa839c9SVladimir Kondratyev #define BCM5974_USB_MODE_HID 0x08 675aa839c9SVladimir Kondratyev /* Type4 trackpads */ 685aa839c9SVladimir Kondratyev #define BCM5974_HID_REPORT_LEN 2 695aa839c9SVladimir Kondratyev #define BCM5974_HID_REPORT_ID 2 705aa839c9SVladimir Kondratyev #define BCM5974_HID_MODE_RAW 0x01 715aa839c9SVladimir Kondratyev #define BCM5974_HID_MODE_HID 0x00 725aa839c9SVladimir Kondratyev 735aa839c9SVladimir Kondratyev /* Tunables */ 745aa839c9SVladimir Kondratyev static SYSCTL_NODE(_hw_hid, OID_AUTO, bcm5974, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 755aa839c9SVladimir Kondratyev "HID wellspring touchpad"); 765aa839c9SVladimir Kondratyev 775aa839c9SVladimir Kondratyev #ifdef HID_DEBUG 785aa839c9SVladimir Kondratyev enum wsp_log_level { 795aa839c9SVladimir Kondratyev BCM5974_LLEVEL_DISABLED = 0, 805aa839c9SVladimir Kondratyev BCM5974_LLEVEL_ERROR, 815aa839c9SVladimir Kondratyev BCM5974_LLEVEL_DEBUG, /* for troubleshooting */ 825aa839c9SVladimir Kondratyev BCM5974_LLEVEL_INFO, /* for diagnostics */ 835aa839c9SVladimir Kondratyev }; 845aa839c9SVladimir Kondratyev /* the default is to only log errors */ 855aa839c9SVladimir Kondratyev static int bcm5974_debug = BCM5974_LLEVEL_ERROR; 865aa839c9SVladimir Kondratyev 875aa839c9SVladimir Kondratyev SYSCTL_INT(_hw_hid_bcm5974, OID_AUTO, debug, CTLFLAG_RWTUN, 885aa839c9SVladimir Kondratyev &bcm5974_debug, BCM5974_LLEVEL_ERROR, "BCM5974 debug level"); 895aa839c9SVladimir Kondratyev #endif /* HID_DEBUG */ 905aa839c9SVladimir Kondratyev 915aa839c9SVladimir Kondratyev /* 925aa839c9SVladimir Kondratyev * Some tables, structures, definitions and constant values for the 935aa839c9SVladimir Kondratyev * touchpad protocol has been copied from Linux's 945aa839c9SVladimir Kondratyev * "drivers/input/mouse/bcm5974.c" which has the following copyright 955aa839c9SVladimir Kondratyev * holders under GPLv2. All device specific code in this driver has 965aa839c9SVladimir Kondratyev * been written from scratch. The decoding algorithm is based on 975aa839c9SVladimir Kondratyev * output from FreeBSD's usbdump. 985aa839c9SVladimir Kondratyev * 995aa839c9SVladimir Kondratyev * Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se) 1005aa839c9SVladimir Kondratyev * Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com) 1015aa839c9SVladimir Kondratyev * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) 1025aa839c9SVladimir Kondratyev * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) 1035aa839c9SVladimir Kondratyev * Copyright (C) 2005 Stelian Pop (stelian@popies.net) 1045aa839c9SVladimir Kondratyev * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) 1055aa839c9SVladimir Kondratyev * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) 1065aa839c9SVladimir Kondratyev * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) 1075aa839c9SVladimir Kondratyev * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) 1085aa839c9SVladimir Kondratyev */ 1095aa839c9SVladimir Kondratyev 1105aa839c9SVladimir Kondratyev /* trackpad header types */ 1115aa839c9SVladimir Kondratyev enum tp_type { 1125aa839c9SVladimir Kondratyev TYPE1, /* plain trackpad */ 1135aa839c9SVladimir Kondratyev TYPE2, /* button integrated in trackpad */ 1145aa839c9SVladimir Kondratyev TYPE3, /* additional header fields since June 2013 */ 1155aa839c9SVladimir Kondratyev TYPE4, /* additional header field for pressure data */ 116ef8397c2SVal Packett TYPE_MT2U, /* Magic Trackpad 2 USB */ 1175aa839c9SVladimir Kondratyev TYPE_CNT 1185aa839c9SVladimir Kondratyev }; 1195aa839c9SVladimir Kondratyev 1205aa839c9SVladimir Kondratyev /* list of device capability bits */ 1215aa839c9SVladimir Kondratyev #define HAS_INTEGRATED_BUTTON 1 122ef8397c2SVal Packett #define USES_COMPACT_REPORT 2 1235aa839c9SVladimir Kondratyev 1245aa839c9SVladimir Kondratyev struct tp_type_params { 1255aa839c9SVladimir Kondratyev uint8_t caps; /* device capability bitmask */ 1265aa839c9SVladimir Kondratyev uint8_t button; /* offset to button data */ 1275aa839c9SVladimir Kondratyev uint8_t offset; /* offset to trackpad finger data */ 1285aa839c9SVladimir Kondratyev uint8_t delta; /* offset from header to finger struct */ 1295aa839c9SVladimir Kondratyev } const static tp[TYPE_CNT] = { 1305aa839c9SVladimir Kondratyev [TYPE1] = { 1315aa839c9SVladimir Kondratyev .caps = 0, 1325aa839c9SVladimir Kondratyev .button = 0, 1335aa839c9SVladimir Kondratyev .offset = 13 * 2, 1345aa839c9SVladimir Kondratyev .delta = 0, 1355aa839c9SVladimir Kondratyev }, 1365aa839c9SVladimir Kondratyev [TYPE2] = { 1375aa839c9SVladimir Kondratyev .caps = HAS_INTEGRATED_BUTTON, 1385aa839c9SVladimir Kondratyev .button = 15, 1395aa839c9SVladimir Kondratyev .offset = 15 * 2, 1405aa839c9SVladimir Kondratyev .delta = 0, 1415aa839c9SVladimir Kondratyev }, 1425aa839c9SVladimir Kondratyev [TYPE3] = { 1435aa839c9SVladimir Kondratyev .caps = HAS_INTEGRATED_BUTTON, 1445aa839c9SVladimir Kondratyev .button = 23, 1455aa839c9SVladimir Kondratyev .offset = 19 * 2, 1465aa839c9SVladimir Kondratyev .delta = 0, 1475aa839c9SVladimir Kondratyev }, 1485aa839c9SVladimir Kondratyev [TYPE4] = { 1495aa839c9SVladimir Kondratyev .caps = HAS_INTEGRATED_BUTTON, 1505aa839c9SVladimir Kondratyev .button = 31, 1515aa839c9SVladimir Kondratyev .offset = 23 * 2, 1525aa839c9SVladimir Kondratyev .delta = 2, 1535aa839c9SVladimir Kondratyev }, 154ef8397c2SVal Packett [TYPE_MT2U] = { 155ef8397c2SVal Packett .caps = HAS_INTEGRATED_BUTTON | USES_COMPACT_REPORT, 156ef8397c2SVal Packett .button = 1, 157ef8397c2SVal Packett .offset = 12, 158ef8397c2SVal Packett .delta = 0, 159ef8397c2SVal Packett }, 160ef8397c2SVal Packett }; 161ef8397c2SVal Packett 162ef8397c2SVal Packett /* trackpad finger structure - compact version for external "Magic" devices */ 163ef8397c2SVal Packett struct tp_finger_compact { 164ef8397c2SVal Packett uint32_t coords; /* not struct directly due to endian conversion */ 165ef8397c2SVal Packett uint8_t touch_major; 166ef8397c2SVal Packett uint8_t touch_minor; 167ef8397c2SVal Packett uint8_t size; 168ef8397c2SVal Packett uint8_t pressure; 16919c804b7SVladimir Kondratyev uint8_t id_ori; 170ef8397c2SVal Packett } __packed; 171ef8397c2SVal Packett 172ef8397c2SVal Packett _Static_assert((sizeof(struct tp_finger_compact) == 9), "tp_finger struct size must be 9"); 173ef8397c2SVal Packett 1745aa839c9SVladimir Kondratyev /* trackpad finger structure - little endian */ 1755aa839c9SVladimir Kondratyev struct tp_finger { 176fda9ac06SGreg V uint16_t origin; /* zero when switching track finger */ 177fda9ac06SGreg V uint16_t abs_x; /* absolute x coodinate */ 178fda9ac06SGreg V uint16_t abs_y; /* absolute y coodinate */ 179fda9ac06SGreg V uint16_t rel_x; /* relative x coodinate */ 180fda9ac06SGreg V uint16_t rel_y; /* relative y coodinate */ 181fda9ac06SGreg V uint16_t tool_major; /* tool area, major axis */ 182fda9ac06SGreg V uint16_t tool_minor; /* tool area, minor axis */ 183fda9ac06SGreg V uint16_t orientation; /* 16384 when point, else 15 bit angle */ 184fda9ac06SGreg V uint16_t touch_major; /* touch area, major axis */ 185fda9ac06SGreg V uint16_t touch_minor; /* touch area, minor axis */ 186fda9ac06SGreg V uint16_t unused[2]; /* zeros */ 187fda9ac06SGreg V uint16_t pressure; /* pressure on forcetouch touchpad */ 188fda9ac06SGreg V uint16_t multi; /* one finger: varies, more fingers: 1895aa839c9SVladimir Kondratyev * constant */ 1905aa839c9SVladimir Kondratyev } __packed; 1915aa839c9SVladimir Kondratyev 192fda9ac06SGreg V #define BCM5974_LE2H(x) ((int32_t)(int16_t)le16toh(x)) 193fda9ac06SGreg V 1945aa839c9SVladimir Kondratyev /* trackpad finger data size, empirically at least ten fingers */ 1955aa839c9SVladimir Kondratyev #define MAX_FINGERS MAX_MT_SLOTS 1965aa839c9SVladimir Kondratyev 1975aa839c9SVladimir Kondratyev #define MAX_FINGER_ORIENTATION 16384 1985aa839c9SVladimir Kondratyev 1995aa839c9SVladimir Kondratyev enum { 2005aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING1, 2015aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING2, 2025aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING3, 2035aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING4, 2045aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING4A, 2055aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING5, 2065aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING6A, 2075aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING6, 2085aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING5A, 2095aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING7, 2105aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING7A, 2115aa839c9SVladimir Kondratyev BCM5974_FLAG_WELLSPRING8, 2121c4edee3SVal Packett BCM5974_FLAG_WELLSPRING9_MODEL3, 2131c4edee3SVal Packett BCM5974_FLAG_WELLSPRING9_MODEL4, 2141c4edee3SVal Packett #define BCM5974_FLAG_WELLSPRING9_MODEL_SPI BCM5974_FLAG_WELLSPRING9_MODEL4 2151c4edee3SVal Packett BCM5974_FLAG_WELLSPRING9_MODEL5, 2161c4edee3SVal Packett BCM5974_FLAG_WELLSPRING9_MODEL6, 217ef8397c2SVal Packett BCM5974_FLAG_MAGIC_TRACKPAD2_USB, 2185aa839c9SVladimir Kondratyev BCM5974_FLAG_MAX, 2195aa839c9SVladimir Kondratyev }; 2205aa839c9SVladimir Kondratyev 2215aa839c9SVladimir Kondratyev /* device-specific parameters */ 2225aa839c9SVladimir Kondratyev struct bcm5974_axis { 2235aa839c9SVladimir Kondratyev int snratio; /* signal-to-noise ratio */ 2245aa839c9SVladimir Kondratyev int min; /* device minimum reading */ 2255aa839c9SVladimir Kondratyev int max; /* device maximum reading */ 2265aa839c9SVladimir Kondratyev int size; /* physical size, mm */ 2275aa839c9SVladimir Kondratyev }; 2285aa839c9SVladimir Kondratyev 2295aa839c9SVladimir Kondratyev /* device-specific configuration */ 2305aa839c9SVladimir Kondratyev struct bcm5974_dev_params { 2315aa839c9SVladimir Kondratyev const struct tp_type_params* tp; 2325aa839c9SVladimir Kondratyev struct bcm5974_axis p; /* finger pressure limits */ 2335aa839c9SVladimir Kondratyev struct bcm5974_axis w; /* finger width limits */ 2345aa839c9SVladimir Kondratyev struct bcm5974_axis x; /* horizontal limits */ 2355aa839c9SVladimir Kondratyev struct bcm5974_axis y; /* vertical limits */ 2365aa839c9SVladimir Kondratyev struct bcm5974_axis o; /* orientation limits */ 2375aa839c9SVladimir Kondratyev }; 2385aa839c9SVladimir Kondratyev 2395aa839c9SVladimir Kondratyev /* logical signal quality */ 2405aa839c9SVladimir Kondratyev #define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ 2415aa839c9SVladimir Kondratyev #define SN_WIDTH 25 /* width signal-to-noise ratio */ 2425aa839c9SVladimir Kondratyev #define SN_COORD 250 /* coordinate signal-to-noise ratio */ 2435aa839c9SVladimir Kondratyev #define SN_ORIENT 10 /* orientation signal-to-noise ratio */ 2445aa839c9SVladimir Kondratyev 2455aa839c9SVladimir Kondratyev static const struct bcm5974_dev_params bcm5974_dev_params[BCM5974_FLAG_MAX] = { 2465aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING1] = { 2475aa839c9SVladimir Kondratyev .tp = tp + TYPE1, 2485aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 256, 0 }, 2495aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 2505aa839c9SVladimir Kondratyev .x = { SN_COORD, -4824, 5342, 105 }, 2515aa839c9SVladimir Kondratyev .y = { SN_COORD, -172, 5820, 75 }, 2525aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 2535aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 2545aa839c9SVladimir Kondratyev }, 2555aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING2] = { 2565aa839c9SVladimir Kondratyev .tp = tp + TYPE1, 2575aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 256, 0 }, 2585aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 2595aa839c9SVladimir Kondratyev .x = { SN_COORD, -4824, 4824, 105 }, 2605aa839c9SVladimir Kondratyev .y = { SN_COORD, -172, 4290, 75 }, 2615aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 2625aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 2635aa839c9SVladimir Kondratyev }, 2645aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING3] = { 2655aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 2665aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 2675aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 2685aa839c9SVladimir Kondratyev .x = { SN_COORD, -4460, 5166, 105 }, 2695aa839c9SVladimir Kondratyev .y = { SN_COORD, -75, 6700, 75 }, 2705aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 2715aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 2725aa839c9SVladimir Kondratyev }, 2735aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING4] = { 2745aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 2755aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 2765aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 2775aa839c9SVladimir Kondratyev .x = { SN_COORD, -4620, 5140, 105 }, 2785aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6600, 75 }, 2795aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 2805aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 2815aa839c9SVladimir Kondratyev }, 2825aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING4A] = { 2835aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 2845aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 2855aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 2865aa839c9SVladimir Kondratyev .x = { SN_COORD, -4616, 5112, 105 }, 2875aa839c9SVladimir Kondratyev .y = { SN_COORD, -142, 5234, 75 }, 2885aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 2895aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 2905aa839c9SVladimir Kondratyev }, 2915aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING5] = { 2925aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 2935aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 2945aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 2955aa839c9SVladimir Kondratyev .x = { SN_COORD, -4415, 5050, 105 }, 2965aa839c9SVladimir Kondratyev .y = { SN_COORD, -55, 6680, 75 }, 2975aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 2985aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 2995aa839c9SVladimir Kondratyev }, 3005aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING6] = { 3015aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 3025aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 3035aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3045aa839c9SVladimir Kondratyev .x = { SN_COORD, -4620, 5140, 105 }, 3055aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6600, 75 }, 3065aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3075aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3085aa839c9SVladimir Kondratyev }, 3095aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING5A] = { 3105aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 3115aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 3125aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3135aa839c9SVladimir Kondratyev .x = { SN_COORD, -4750, 5280, 105 }, 3145aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6730, 75 }, 3155aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3165aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3175aa839c9SVladimir Kondratyev }, 3185aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING6A] = { 3195aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 3205aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 3215aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3225aa839c9SVladimir Kondratyev .x = { SN_COORD, -4620, 5140, 105 }, 3235aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6600, 75 }, 3245aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3255aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3265aa839c9SVladimir Kondratyev }, 3275aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING7] = { 3285aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 3295aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 3305aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3315aa839c9SVladimir Kondratyev .x = { SN_COORD, -4750, 5280, 105 }, 3325aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6730, 75 }, 3335aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3345aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3355aa839c9SVladimir Kondratyev }, 3365aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING7A] = { 3375aa839c9SVladimir Kondratyev .tp = tp + TYPE2, 3385aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 3395aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3405aa839c9SVladimir Kondratyev .x = { SN_COORD, -4750, 5280, 105 }, 3415aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6730, 75 }, 3425aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3435aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3445aa839c9SVladimir Kondratyev }, 3455aa839c9SVladimir Kondratyev [BCM5974_FLAG_WELLSPRING8] = { 3465aa839c9SVladimir Kondratyev .tp = tp + TYPE3, 3475aa839c9SVladimir Kondratyev .p = { SN_PRESSURE, 0, 300, 0 }, 3485aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3495aa839c9SVladimir Kondratyev .x = { SN_COORD, -4620, 5140, 105 }, 3505aa839c9SVladimir Kondratyev .y = { SN_COORD, -150, 6600, 75 }, 3515aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3525aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3535aa839c9SVladimir Kondratyev }, 354176939bdSVal Packett /* 355176939bdSVal Packett * NOTE: Actually force-sensitive. Pressure has a "size" equal to the max 356176939bdSVal Packett * so that the "resolution" is 1 (i.e. values will be interpreted as grams). 357176939bdSVal Packett * No scientific measurements have been done :) but a really hard press 358176939bdSVal Packett * results in a value around 3500 on model 4. 359176939bdSVal Packett */ 3601c4edee3SVal Packett [BCM5974_FLAG_WELLSPRING9_MODEL3] = { 3615aa839c9SVladimir Kondratyev .tp = tp + TYPE4, 362176939bdSVal Packett .p = { SN_PRESSURE, 0, 4096, 4096 }, 3635aa839c9SVladimir Kondratyev .w = { SN_WIDTH, 0, 2048, 0 }, 3645aa839c9SVladimir Kondratyev .x = { SN_COORD, -4828, 5345, 105 }, 3655aa839c9SVladimir Kondratyev .y = { SN_COORD, -203, 6803, 75 }, 3665aa839c9SVladimir Kondratyev .o = { SN_ORIENT, 3675aa839c9SVladimir Kondratyev -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3685aa839c9SVladimir Kondratyev }, 3691c4edee3SVal Packett [BCM5974_FLAG_WELLSPRING9_MODEL4] = { 3701c4edee3SVal Packett .tp = tp + TYPE4, 3711c4edee3SVal Packett .p = { SN_PRESSURE, 0, 4096, 4096 }, 3721c4edee3SVal Packett .w = { SN_WIDTH, 0, 2048, 0 }, 3731c4edee3SVal Packett .x = { SN_COORD, -5087, 5579, 105 }, 3741c4edee3SVal Packett .y = { SN_COORD, -182, 6089, 75 }, 3751c4edee3SVal Packett .o = { SN_ORIENT, 3761c4edee3SVal Packett -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3771c4edee3SVal Packett }, 3781c4edee3SVal Packett [BCM5974_FLAG_WELLSPRING9_MODEL5] = { 3791c4edee3SVal Packett .tp = tp + TYPE4, 3801c4edee3SVal Packett .p = { SN_PRESSURE, 0, 4096, 4096 }, 3811c4edee3SVal Packett .w = { SN_WIDTH, 0, 2048, 0 }, 3821c4edee3SVal Packett .x = { SN_COORD, -6243, 6749, 105 }, 3831c4edee3SVal Packett .y = { SN_COORD, -170, 7685, 75 }, 3841c4edee3SVal Packett .o = { SN_ORIENT, 3851c4edee3SVal Packett -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3861c4edee3SVal Packett }, 3871c4edee3SVal Packett [BCM5974_FLAG_WELLSPRING9_MODEL6] = { 3881c4edee3SVal Packett .tp = tp + TYPE4, 3891c4edee3SVal Packett .p = { SN_PRESSURE, 0, 4096, 4096 }, 3901c4edee3SVal Packett .w = { SN_WIDTH, 0, 2048, 0 }, 3911c4edee3SVal Packett .x = { SN_COORD, -7456, 7976, 105 }, 3921c4edee3SVal Packett .y = { SN_COORD, -163, 9283, 75 }, 3931c4edee3SVal Packett .o = { SN_ORIENT, 3941c4edee3SVal Packett -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 }, 3951c4edee3SVal Packett }, 396ef8397c2SVal Packett [BCM5974_FLAG_MAGIC_TRACKPAD2_USB] = { 397ef8397c2SVal Packett .tp = tp + TYPE_MT2U, 398ef8397c2SVal Packett .p = { SN_PRESSURE, 0, 256, 256 }, 399ef8397c2SVal Packett .w = { SN_WIDTH, 0, 2048, 0 }, 400c85e6a5cSVladimir Kondratyev .x = { SN_COORD, -3678, 3934, 157 }, 401c85e6a5cSVladimir Kondratyev .y = { SN_COORD, -2478, 2587, 107 }, 40219c804b7SVladimir Kondratyev .o = { SN_ORIENT, -3, 4, 0 }, 403ef8397c2SVal Packett }, 4045aa839c9SVladimir Kondratyev }; 4055aa839c9SVladimir Kondratyev 4065aa839c9SVladimir Kondratyev #define BCM5974_DEV(v,p,i) { \ 4075aa839c9SVladimir Kondratyev HID_BVPI(BUS_USB, USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i), \ 4085aa839c9SVladimir Kondratyev HID_TLC(BCM5974_TLC_PAGE, BCM5974_TLC_USAGE), \ 4095aa839c9SVladimir Kondratyev } 4105aa839c9SVladimir Kondratyev 4111c4edee3SVal Packett #define APPLE_HID "APP000D" 4121c4edee3SVal Packett #define BCM5974_DEV_SPI(hid, i) { \ 4131c4edee3SVal Packett HID_BUS(BUS_SPI), HID_PNP(hid), HID_DRIVER_INFO(i), \ 4141c4edee3SVal Packett HID_TLC(BCM5974_TLC_PAGE, BCM5974_TLC_USAGE), \ 4151c4edee3SVal Packett } 4161c4edee3SVal Packett 4175aa839c9SVladimir Kondratyev static const struct hid_device_id bcm5974_devs[] = { 4185aa839c9SVladimir Kondratyev /* MacbookAir1.1 */ 4195aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING_ANSI, BCM5974_FLAG_WELLSPRING1), 4205aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING_ISO, BCM5974_FLAG_WELLSPRING1), 4215aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING_JIS, BCM5974_FLAG_WELLSPRING1), 4225aa839c9SVladimir Kondratyev 4235aa839c9SVladimir Kondratyev /* MacbookProPenryn, aka wellspring2 */ 4245aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING2_ANSI, BCM5974_FLAG_WELLSPRING2), 4255aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING2_ISO, BCM5974_FLAG_WELLSPRING2), 4265aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING2_JIS, BCM5974_FLAG_WELLSPRING2), 4275aa839c9SVladimir Kondratyev 4285aa839c9SVladimir Kondratyev /* Macbook5,1 (unibody), aka wellspring3 */ 4295aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING3_ANSI, BCM5974_FLAG_WELLSPRING3), 4305aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING3_ISO, BCM5974_FLAG_WELLSPRING3), 4315aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING3_JIS, BCM5974_FLAG_WELLSPRING3), 4325aa839c9SVladimir Kondratyev 4335aa839c9SVladimir Kondratyev /* MacbookAir3,2 (unibody), aka wellspring4 */ 4345aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING4_ANSI, BCM5974_FLAG_WELLSPRING4), 4355aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING4_ISO, BCM5974_FLAG_WELLSPRING4), 4365aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING4_JIS, BCM5974_FLAG_WELLSPRING4), 4375aa839c9SVladimir Kondratyev 4385aa839c9SVladimir Kondratyev /* MacbookAir3,1 (unibody), aka wellspring4 */ 4395aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING4A_ANSI, BCM5974_FLAG_WELLSPRING4A), 4405aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING4A_ISO, BCM5974_FLAG_WELLSPRING4A), 4415aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING4A_JIS, BCM5974_FLAG_WELLSPRING4A), 4425aa839c9SVladimir Kondratyev 4435aa839c9SVladimir Kondratyev /* Macbook8 (unibody, March 2011) */ 4445aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING5_ANSI, BCM5974_FLAG_WELLSPRING5), 4455aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING5_ISO, BCM5974_FLAG_WELLSPRING5), 4465aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING5_JIS, BCM5974_FLAG_WELLSPRING5), 4475aa839c9SVladimir Kondratyev 4485aa839c9SVladimir Kondratyev /* MacbookAir4,1 (unibody, July 2011) */ 4495aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING6A_ANSI, BCM5974_FLAG_WELLSPRING6A), 4505aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING6A_ISO, BCM5974_FLAG_WELLSPRING6A), 4515aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING6A_JIS, BCM5974_FLAG_WELLSPRING6A), 4525aa839c9SVladimir Kondratyev 4535aa839c9SVladimir Kondratyev /* MacbookAir4,2 (unibody, July 2011) */ 4545aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING6_ANSI, BCM5974_FLAG_WELLSPRING6), 4555aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING6_ISO, BCM5974_FLAG_WELLSPRING6), 4565aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING6_JIS, BCM5974_FLAG_WELLSPRING6), 4575aa839c9SVladimir Kondratyev 4585aa839c9SVladimir Kondratyev /* Macbook8,2 (unibody) */ 4595aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING5A_ANSI, BCM5974_FLAG_WELLSPRING5A), 4605aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING5A_ISO, BCM5974_FLAG_WELLSPRING5A), 4615aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING5A_JIS, BCM5974_FLAG_WELLSPRING5A), 4625aa839c9SVladimir Kondratyev 4635aa839c9SVladimir Kondratyev /* MacbookPro10,1 (unibody, June 2012) */ 4645aa839c9SVladimir Kondratyev /* MacbookPro11,1-3 (unibody, June 2013) */ 4655aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING7_ANSI, BCM5974_FLAG_WELLSPRING7), 4665aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING7_ISO, BCM5974_FLAG_WELLSPRING7), 4675aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING7_JIS, BCM5974_FLAG_WELLSPRING7), 4685aa839c9SVladimir Kondratyev 4695aa839c9SVladimir Kondratyev /* MacbookPro10,2 (unibody, October 2012) */ 4705aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING7A_ANSI, BCM5974_FLAG_WELLSPRING7A), 4715aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING7A_ISO, BCM5974_FLAG_WELLSPRING7A), 4725aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING7A_JIS, BCM5974_FLAG_WELLSPRING7A), 4735aa839c9SVladimir Kondratyev 4745aa839c9SVladimir Kondratyev /* MacbookAir6,2 (unibody, June 2013) */ 4755aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING8_ANSI, BCM5974_FLAG_WELLSPRING8), 4765aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING8_ISO, BCM5974_FLAG_WELLSPRING8), 4775aa839c9SVladimir Kondratyev BCM5974_DEV(APPLE, WELLSPRING8_JIS, BCM5974_FLAG_WELLSPRING8), 4785aa839c9SVladimir Kondratyev 4795aa839c9SVladimir Kondratyev /* MacbookPro12,1 MacbookPro11,4 */ 4801c4edee3SVal Packett BCM5974_DEV(APPLE, WELLSPRING9_ANSI, BCM5974_FLAG_WELLSPRING9_MODEL3), 4811c4edee3SVal Packett BCM5974_DEV(APPLE, WELLSPRING9_ISO, BCM5974_FLAG_WELLSPRING9_MODEL3), 4821c4edee3SVal Packett BCM5974_DEV(APPLE, WELLSPRING9_JIS, BCM5974_FLAG_WELLSPRING9_MODEL3), 4831c4edee3SVal Packett 4841c4edee3SVal Packett /* Generic SPI device */ 4851c4edee3SVal Packett BCM5974_DEV_SPI(APPLE_HID, BCM5974_FLAG_WELLSPRING9_MODEL_SPI), 486ef8397c2SVal Packett 487ef8397c2SVal Packett /* External "Magic" devices */ 488ef8397c2SVal Packett BCM5974_DEV(APPLE, MAGIC_TRACKPAD2, BCM5974_FLAG_MAGIC_TRACKPAD2_USB), 4895aa839c9SVladimir Kondratyev }; 4905aa839c9SVladimir Kondratyev 4911c4edee3SVal Packett #define BCM5974_WELLSPRING9_RDESC_SIZE 110 4921c4edee3SVal Packett #define BCM5974_WELLSPRING9_MODEL_OFFSET 106 4931c4edee3SVal Packett 4945aa839c9SVladimir Kondratyev struct bcm5974_softc { 4955aa839c9SVladimir Kondratyev device_t sc_dev; 4965aa839c9SVladimir Kondratyev struct evdev_dev *sc_evdev; 4975aa839c9SVladimir Kondratyev /* device configuration */ 4985aa839c9SVladimir Kondratyev const struct bcm5974_dev_params *sc_params; 49945b6c31aSGreg V bool sc_saved_mode; 5005aa839c9SVladimir Kondratyev }; 5015aa839c9SVladimir Kondratyev 5025aa839c9SVladimir Kondratyev static const uint8_t bcm5974_rdesc[] = { 5035aa839c9SVladimir Kondratyev 0x05, BCM5974_TLC_PAGE, /* Usage Page (BCM5974_TLC_PAGE) */ 5045aa839c9SVladimir Kondratyev 0x09, BCM5974_TLC_USAGE,/* Usage (BCM5974_TLC_USAGE) */ 5055aa839c9SVladimir Kondratyev 0xA1, 0x01, /* Collection (Application) */ 5065aa839c9SVladimir Kondratyev 0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */ 5075aa839c9SVladimir Kondratyev 0x09, 0x01, /* Usage (0x01) */ 5085aa839c9SVladimir Kondratyev 0x15, 0x00, /* Logical Minimum (0) */ 5095aa839c9SVladimir Kondratyev 0x26, 0xFF, 0x00, /* Logical Maximum (255) */ 5105aa839c9SVladimir Kondratyev 0x75, 0x08, /* Report Size (8) */ 5115aa839c9SVladimir Kondratyev 0x96, /* Report Count (BCM5974_BUFFER_MAX) */ 5125aa839c9SVladimir Kondratyev BCM5974_BUFFER_MAX & 0xFF, 5135aa839c9SVladimir Kondratyev BCM5974_BUFFER_MAX >> 8 & 0xFF, 5145aa839c9SVladimir Kondratyev 0x81, 0x02, /* Input (Data,Var,Abs) */ 5155aa839c9SVladimir Kondratyev 0xC0, /* End Collection */ 5165aa839c9SVladimir Kondratyev }; 5175aa839c9SVladimir Kondratyev 5185aa839c9SVladimir Kondratyev /* 5195aa839c9SVladimir Kondratyev * function prototypes 5205aa839c9SVladimir Kondratyev */ 5215aa839c9SVladimir Kondratyev static evdev_open_t bcm5974_ev_open; 5225aa839c9SVladimir Kondratyev static evdev_close_t bcm5974_ev_close; 5235aa839c9SVladimir Kondratyev static const struct evdev_methods bcm5974_evdev_methods = { 5245aa839c9SVladimir Kondratyev .ev_open = &bcm5974_ev_open, 5255aa839c9SVladimir Kondratyev .ev_close = &bcm5974_ev_close, 5265aa839c9SVladimir Kondratyev }; 5275aa839c9SVladimir Kondratyev static hid_intr_t bcm5974_intr; 5285aa839c9SVladimir Kondratyev 5295aa839c9SVladimir Kondratyev /* Device methods. */ 5305aa839c9SVladimir Kondratyev static device_identify_t bcm5974_identify; 5315aa839c9SVladimir Kondratyev static device_probe_t bcm5974_probe; 5325aa839c9SVladimir Kondratyev static device_attach_t bcm5974_attach; 5335aa839c9SVladimir Kondratyev static device_detach_t bcm5974_detach; 5345aa839c9SVladimir Kondratyev 5355aa839c9SVladimir Kondratyev /* 5365aa839c9SVladimir Kondratyev * Type1 and Type2 touchpads use keyboard USB interface to switch from HID to 5375aa839c9SVladimir Kondratyev * RAW mode. Although it is possible to extend hkbd driver to support such a 5385aa839c9SVladimir Kondratyev * mode change requests, it's not wanted due to cross device tree dependencies. 5395aa839c9SVladimir Kondratyev * So, find lowest common denominator (struct usb_device of grandparent usbhid 5405aa839c9SVladimir Kondratyev * driver) of touchpad and keyboard drivers and issue direct USB requests. 5415aa839c9SVladimir Kondratyev */ 5425aa839c9SVladimir Kondratyev static int 5435aa839c9SVladimir Kondratyev bcm5974_set_device_mode_usb(struct bcm5974_softc *sc, bool on) 5445aa839c9SVladimir Kondratyev { 5455aa839c9SVladimir Kondratyev uint8_t mode_bytes[BCM5974_USB_REPORT_LEN]; 5465aa839c9SVladimir Kondratyev struct usb_ctl_request ucr; 5475aa839c9SVladimir Kondratyev int err; 5485aa839c9SVladimir Kondratyev 5495aa839c9SVladimir Kondratyev ucr.ucr_request.bmRequestType = UT_READ_CLASS_INTERFACE; 5505aa839c9SVladimir Kondratyev ucr.ucr_request.bRequest = UR_GET_REPORT; 5515aa839c9SVladimir Kondratyev USETW2(ucr.ucr_request.wValue, 5525aa839c9SVladimir Kondratyev UHID_FEATURE_REPORT, BCM5974_USB_REPORT_ID); 5535aa839c9SVladimir Kondratyev ucr.ucr_request.wIndex[0] = BCM5974_USB_IFACE_INDEX; 5545aa839c9SVladimir Kondratyev ucr.ucr_request.wIndex[1] = 0; 5555aa839c9SVladimir Kondratyev USETW(ucr.ucr_request.wLength, BCM5974_USB_REPORT_LEN); 5565aa839c9SVladimir Kondratyev ucr.ucr_data = mode_bytes; 5575aa839c9SVladimir Kondratyev 5585aa839c9SVladimir Kondratyev err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr); 5595aa839c9SVladimir Kondratyev if (err != 0) { 5605aa839c9SVladimir Kondratyev DPRINTF("Failed to read device mode (%d)\n", err); 5615aa839c9SVladimir Kondratyev return (EIO); 5625aa839c9SVladimir Kondratyev } 5635aa839c9SVladimir Kondratyev #if 0 5645aa839c9SVladimir Kondratyev /* 5655aa839c9SVladimir Kondratyev * XXX Need to wait at least 250ms for hardware to get 5665aa839c9SVladimir Kondratyev * ready. The device mode handling appears to be handled 5675aa839c9SVladimir Kondratyev * asynchronously and we should not issue these commands too 5685aa839c9SVladimir Kondratyev * quickly. 5695aa839c9SVladimir Kondratyev */ 5705aa839c9SVladimir Kondratyev pause("WHW", hz / 4); 5715aa839c9SVladimir Kondratyev #endif 5725aa839c9SVladimir Kondratyev mode_bytes[0] = on ? BCM5974_USB_MODE_RAW : BCM5974_USB_MODE_HID; 5735aa839c9SVladimir Kondratyev ucr.ucr_request.bmRequestType = UT_WRITE_CLASS_INTERFACE; 5745aa839c9SVladimir Kondratyev ucr.ucr_request.bRequest = UR_SET_REPORT; 5755aa839c9SVladimir Kondratyev 5765aa839c9SVladimir Kondratyev err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr); 5775aa839c9SVladimir Kondratyev if (err != 0) { 5785aa839c9SVladimir Kondratyev DPRINTF("Failed to write device mode (%d)\n", err); 5795aa839c9SVladimir Kondratyev return (EIO); 5805aa839c9SVladimir Kondratyev } 5815aa839c9SVladimir Kondratyev 5825aa839c9SVladimir Kondratyev return (0); 5835aa839c9SVladimir Kondratyev } 5845aa839c9SVladimir Kondratyev 5855aa839c9SVladimir Kondratyev static int 5865aa839c9SVladimir Kondratyev bcm5974_set_device_mode_hid(struct bcm5974_softc *sc, bool on) 5875aa839c9SVladimir Kondratyev { 5885aa839c9SVladimir Kondratyev uint8_t mode_bytes[BCM5974_HID_REPORT_LEN] = { 5895aa839c9SVladimir Kondratyev BCM5974_HID_REPORT_ID, 5905aa839c9SVladimir Kondratyev on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID, 5915aa839c9SVladimir Kondratyev }; 5925aa839c9SVladimir Kondratyev #if 0 5935aa839c9SVladimir Kondratyev int err; 5945aa839c9SVladimir Kondratyev 5955aa839c9SVladimir Kondratyev err = hid_get_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN, 5965aa839c9SVladimir Kondratyev NULL, HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID); 5975aa839c9SVladimir Kondratyev if (err != 0) { 5985aa839c9SVladimir Kondratyev DPRINTF("Failed to read device mode (%d)\n", err); 5995aa839c9SVladimir Kondratyev return (err); 6005aa839c9SVladimir Kondratyev } 6015aa839c9SVladimir Kondratyev /* 6025aa839c9SVladimir Kondratyev * XXX Need to wait at least 250ms for hardware to get 6035aa839c9SVladimir Kondratyev * ready. The device mode handling appears to be handled 6045aa839c9SVladimir Kondratyev * asynchronously and we should not issue these commands too 6055aa839c9SVladimir Kondratyev * quickly. 6065aa839c9SVladimir Kondratyev */ 6075aa839c9SVladimir Kondratyev pause("WHW", hz / 4); 6085aa839c9SVladimir Kondratyev mode_bytes[1] = on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID; 6095aa839c9SVladimir Kondratyev #endif 6105aa839c9SVladimir Kondratyev return (hid_set_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN, 6115aa839c9SVladimir Kondratyev HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID)); 6125aa839c9SVladimir Kondratyev } 6135aa839c9SVladimir Kondratyev 6145aa839c9SVladimir Kondratyev static int 6155aa839c9SVladimir Kondratyev bcm5974_set_device_mode(struct bcm5974_softc *sc, bool on) 6165aa839c9SVladimir Kondratyev { 6175aa839c9SVladimir Kondratyev int err = 0; 6185aa839c9SVladimir Kondratyev 6195aa839c9SVladimir Kondratyev switch (sc->sc_params->tp - tp) { 6205aa839c9SVladimir Kondratyev case TYPE1: 6215aa839c9SVladimir Kondratyev case TYPE2: 6225aa839c9SVladimir Kondratyev err = bcm5974_set_device_mode_usb(sc, on); 6235aa839c9SVladimir Kondratyev break; 6245aa839c9SVladimir Kondratyev case TYPE3: /* Type 3 does not require a mode switch */ 6255aa839c9SVladimir Kondratyev break; 6265aa839c9SVladimir Kondratyev case TYPE4: 627ef8397c2SVal Packett case TYPE_MT2U: 6285aa839c9SVladimir Kondratyev err = bcm5974_set_device_mode_hid(sc, on); 6295aa839c9SVladimir Kondratyev break; 6305aa839c9SVladimir Kondratyev default: 6315aa839c9SVladimir Kondratyev KASSERT(0 == 1, ("Unknown trackpad type")); 6325aa839c9SVladimir Kondratyev } 6335aa839c9SVladimir Kondratyev 63445b6c31aSGreg V if (!err) 63545b6c31aSGreg V sc->sc_saved_mode = on; 63645b6c31aSGreg V 6375aa839c9SVladimir Kondratyev return (err); 6385aa839c9SVladimir Kondratyev } 6395aa839c9SVladimir Kondratyev 6401c4edee3SVal Packett static uintptr_t 6411c4edee3SVal Packett bcm5974_get_wsp9_model(device_t dev) 6421c4edee3SVal Packett { 6431c4edee3SVal Packett const struct hid_device_info *hw = hid_get_device_info(dev); 6441c4edee3SVal Packett static uint8_t rdesc[BCM5974_WELLSPRING9_RDESC_SIZE]; 6451c4edee3SVal Packett uint8_t model_byte = 0; 6461c4edee3SVal Packett 6471c4edee3SVal Packett bus_topo_assert(); 6481c4edee3SVal Packett 6491c4edee3SVal Packett if (hw->rdescsize == sizeof(rdesc) && 6501c4edee3SVal Packett hid_get_rdesc(dev, rdesc, sizeof(rdesc)) == 0) { 6511c4edee3SVal Packett model_byte = rdesc[BCM5974_WELLSPRING9_MODEL_OFFSET]; 6521c4edee3SVal Packett switch (model_byte) { 6531c4edee3SVal Packett case 3: 6541c4edee3SVal Packett /* MacbookPro12,1 MacbookPro11,4 */ 6551c4edee3SVal Packett return (BCM5974_FLAG_WELLSPRING9_MODEL3); 6561c4edee3SVal Packett case 4: 6571c4edee3SVal Packett /* Macbook8,1 Macbook9,1 Macbook10,1 */ 6581c4edee3SVal Packett return (BCM5974_FLAG_WELLSPRING9_MODEL4); 6591c4edee3SVal Packett case 5: 6601c4edee3SVal Packett /* 6611c4edee3SVal Packett * MacbookPro13,1 MacbookPro13,2 6621c4edee3SVal Packett * MacbookPro14,1 MacbookPro14,2 6631c4edee3SVal Packett */ 6641c4edee3SVal Packett return (BCM5974_FLAG_WELLSPRING9_MODEL5); 6651c4edee3SVal Packett case 6: 6661c4edee3SVal Packett /* MacbookPro13,3 MacbookPro14,3 */ 6671c4edee3SVal Packett return (BCM5974_FLAG_WELLSPRING9_MODEL6); 6681c4edee3SVal Packett } 6691c4edee3SVal Packett } 6701c4edee3SVal Packett 6711c4edee3SVal Packett device_printf(dev, "Unexpected trackpad descriptor len=%u model_byte=" 6721c4edee3SVal Packett "%u, not extracting model\n", hw->rdescsize, model_byte); 6731c4edee3SVal Packett 6741c4edee3SVal Packett /* Fallback for unknown SPI versions */ 6751c4edee3SVal Packett return (BCM5974_FLAG_WELLSPRING9_MODEL_SPI); 6761c4edee3SVal Packett } 6771c4edee3SVal Packett 6785aa839c9SVladimir Kondratyev static void 6795aa839c9SVladimir Kondratyev bcm5974_identify(driver_t *driver, device_t parent) 6805aa839c9SVladimir Kondratyev { 6815aa839c9SVladimir Kondratyev void *d_ptr; 6825aa839c9SVladimir Kondratyev hid_size_t d_len; 6835aa839c9SVladimir Kondratyev 6845aa839c9SVladimir Kondratyev /* 6855aa839c9SVladimir Kondratyev * The bcm5974 touchpad has no stable RAW mode TLC in its report 6865aa839c9SVladimir Kondratyev * descriptor. So replace existing HID mode mouse TLC with dummy one 6875aa839c9SVladimir Kondratyev * to set proper transport layer buffer sizes, make driver probe 6885aa839c9SVladimir Kondratyev * simpler and prevent unwanted hms driver attachment. 6895aa839c9SVladimir Kondratyev */ 6905aa839c9SVladimir Kondratyev if (HIDBUS_LOOKUP_ID(parent, bcm5974_devs) != NULL && 6915aa839c9SVladimir Kondratyev hid_get_report_descr(parent, &d_ptr, &d_len) == 0 && 6925aa839c9SVladimir Kondratyev hid_is_mouse(d_ptr, d_len)) 6935aa839c9SVladimir Kondratyev hid_set_report_descr(parent, bcm5974_rdesc, 6945aa839c9SVladimir Kondratyev sizeof(bcm5974_rdesc)); 6955aa839c9SVladimir Kondratyev } 6965aa839c9SVladimir Kondratyev 6975aa839c9SVladimir Kondratyev static int 6985aa839c9SVladimir Kondratyev bcm5974_probe(device_t dev) 6995aa839c9SVladimir Kondratyev { 7005aa839c9SVladimir Kondratyev int err; 7015aa839c9SVladimir Kondratyev 7025aa839c9SVladimir Kondratyev err = HIDBUS_LOOKUP_DRIVER_INFO(dev, bcm5974_devs); 7035aa839c9SVladimir Kondratyev if (err != 0) 7045aa839c9SVladimir Kondratyev return (err); 7055aa839c9SVladimir Kondratyev 7065aa839c9SVladimir Kondratyev hidbus_set_desc(dev, "Touchpad"); 7075aa839c9SVladimir Kondratyev 7085aa839c9SVladimir Kondratyev return (BUS_PROBE_DEFAULT); 7095aa839c9SVladimir Kondratyev } 7105aa839c9SVladimir Kondratyev 7115aa839c9SVladimir Kondratyev static int 7125aa839c9SVladimir Kondratyev bcm5974_attach(device_t dev) 7135aa839c9SVladimir Kondratyev { 7145aa839c9SVladimir Kondratyev struct bcm5974_softc *sc = device_get_softc(dev); 7155aa839c9SVladimir Kondratyev const struct hid_device_info *hw = hid_get_device_info(dev); 7161c4edee3SVal Packett uintptr_t drv_info; 7175aa839c9SVladimir Kondratyev int err; 7185aa839c9SVladimir Kondratyev 7195aa839c9SVladimir Kondratyev DPRINTFN(BCM5974_LLEVEL_INFO, "sc=%p\n", sc); 7205aa839c9SVladimir Kondratyev 7215aa839c9SVladimir Kondratyev sc->sc_dev = dev; 7225aa839c9SVladimir Kondratyev 7235aa839c9SVladimir Kondratyev /* get device specific configuration */ 7241c4edee3SVal Packett drv_info = hidbus_get_driver_info(dev); 7251c4edee3SVal Packett if (drv_info == BCM5974_FLAG_WELLSPRING9_MODEL_SPI) 7261c4edee3SVal Packett drv_info = bcm5974_get_wsp9_model(dev); 7271c4edee3SVal Packett sc->sc_params = bcm5974_dev_params + drv_info; 7285aa839c9SVladimir Kondratyev 7295aa839c9SVladimir Kondratyev sc->sc_evdev = evdev_alloc(); 7305aa839c9SVladimir Kondratyev evdev_set_name(sc->sc_evdev, device_get_desc(dev)); 7315aa839c9SVladimir Kondratyev evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev)); 7325aa839c9SVladimir Kondratyev evdev_set_id(sc->sc_evdev, hw->idBus, hw->idVendor, hw->idProduct, 7335aa839c9SVladimir Kondratyev hw->idVersion); 7345aa839c9SVladimir Kondratyev evdev_set_serial(sc->sc_evdev, hw->serial); 7355aa839c9SVladimir Kondratyev evdev_set_methods(sc->sc_evdev, sc, &bcm5974_evdev_methods); 7365aa839c9SVladimir Kondratyev evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER); 7375aa839c9SVladimir Kondratyev evdev_support_event(sc->sc_evdev, EV_SYN); 7385aa839c9SVladimir Kondratyev evdev_support_event(sc->sc_evdev, EV_ABS); 7395aa839c9SVladimir Kondratyev evdev_support_event(sc->sc_evdev, EV_KEY); 7405aa839c9SVladimir Kondratyev evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */ 7415aa839c9SVladimir Kondratyev 7425aa839c9SVladimir Kondratyev #define BCM5974_ABS(evdev, code, param) \ 7435aa839c9SVladimir Kondratyev evdev_support_abs((evdev), (code), (param).min, (param).max, \ 7445aa839c9SVladimir Kondratyev ((param).max - (param).min) / (param).snratio, 0, \ 7455aa839c9SVladimir Kondratyev (param).size != 0 ? ((param).max - (param).min) / (param).size : 0); 7465aa839c9SVladimir Kondratyev 7475aa839c9SVladimir Kondratyev /* finger position */ 7485aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_X, sc->sc_params->x); 7495aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_Y, sc->sc_params->y); 7505aa839c9SVladimir Kondratyev /* finger pressure */ 7515aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_PRESSURE, sc->sc_params->p); 7525aa839c9SVladimir Kondratyev /* finger touch area */ 7535aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MAJOR, sc->sc_params->w); 7545aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MINOR, sc->sc_params->w); 7555aa839c9SVladimir Kondratyev /* finger approach area */ 756ef8397c2SVal Packett if ((sc->sc_params->tp->caps & USES_COMPACT_REPORT) == 0) { 7575aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MAJOR, sc->sc_params->w); 7585aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MINOR, sc->sc_params->w); 759ef8397c2SVal Packett } 7605aa839c9SVladimir Kondratyev /* finger orientation */ 7615aa839c9SVladimir Kondratyev BCM5974_ABS(sc->sc_evdev, ABS_MT_ORIENTATION, sc->sc_params->o); 7625aa839c9SVladimir Kondratyev /* button properties */ 7635aa839c9SVladimir Kondratyev evdev_support_key(sc->sc_evdev, BTN_LEFT); 7645aa839c9SVladimir Kondratyev if ((sc->sc_params->tp->caps & HAS_INTEGRATED_BUTTON) != 0) 7655aa839c9SVladimir Kondratyev evdev_support_prop(sc->sc_evdev, INPUT_PROP_BUTTONPAD); 7665aa839c9SVladimir Kondratyev /* Enable automatic touch assignment for type B MT protocol */ 7675aa839c9SVladimir Kondratyev evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT, 7685aa839c9SVladimir Kondratyev 0, MAX_FINGERS - 1, 0, 0, 0); 7695aa839c9SVladimir Kondratyev evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID, 7705aa839c9SVladimir Kondratyev -1, MAX_FINGERS - 1, 0, 0, 0); 771ef8397c2SVal Packett if ((sc->sc_params->tp->caps & USES_COMPACT_REPORT) == 0) 7725aa839c9SVladimir Kondratyev evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_TRACK); 7735aa839c9SVladimir Kondratyev evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_AUTOREL); 7745aa839c9SVladimir Kondratyev /* Synaptics compatibility events */ 7755aa839c9SVladimir Kondratyev evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_STCOMPAT); 7765aa839c9SVladimir Kondratyev 7775aa839c9SVladimir Kondratyev err = evdev_register(sc->sc_evdev); 7785aa839c9SVladimir Kondratyev if (err) 7795aa839c9SVladimir Kondratyev goto detach; 7805aa839c9SVladimir Kondratyev 7815aa839c9SVladimir Kondratyev hidbus_set_intr(dev, bcm5974_intr, sc); 7825aa839c9SVladimir Kondratyev 7835aa839c9SVladimir Kondratyev return (0); 7845aa839c9SVladimir Kondratyev 7855aa839c9SVladimir Kondratyev detach: 7865aa839c9SVladimir Kondratyev bcm5974_detach(dev); 7875aa839c9SVladimir Kondratyev return (ENOMEM); 7885aa839c9SVladimir Kondratyev } 7895aa839c9SVladimir Kondratyev 7905aa839c9SVladimir Kondratyev static int 7915aa839c9SVladimir Kondratyev bcm5974_detach(device_t dev) 7925aa839c9SVladimir Kondratyev { 7935aa839c9SVladimir Kondratyev struct bcm5974_softc *sc = device_get_softc(dev); 7945aa839c9SVladimir Kondratyev 7955aa839c9SVladimir Kondratyev evdev_free(sc->sc_evdev); 7965aa839c9SVladimir Kondratyev 7975aa839c9SVladimir Kondratyev return (0); 7985aa839c9SVladimir Kondratyev } 7995aa839c9SVladimir Kondratyev 80045b6c31aSGreg V static int 80145b6c31aSGreg V bcm5974_resume(device_t dev) 80245b6c31aSGreg V { 80345b6c31aSGreg V struct bcm5974_softc *sc = device_get_softc(dev); 80445b6c31aSGreg V 80545b6c31aSGreg V bcm5974_set_device_mode(sc, sc->sc_saved_mode); 80645b6c31aSGreg V 80745b6c31aSGreg V return (0); 80845b6c31aSGreg V } 80945b6c31aSGreg V 8105aa839c9SVladimir Kondratyev static void 8115aa839c9SVladimir Kondratyev bcm5974_intr(void *context, void *data, hid_size_t len) 8125aa839c9SVladimir Kondratyev { 8135aa839c9SVladimir Kondratyev struct bcm5974_softc *sc = context; 8145aa839c9SVladimir Kondratyev const struct bcm5974_dev_params *params = sc->sc_params; 8155aa839c9SVladimir Kondratyev union evdev_mt_slot slot_data; 8165aa839c9SVladimir Kondratyev struct tp_finger *f; 817ef8397c2SVal Packett struct tp_finger_compact *fc; 81819c804b7SVladimir Kondratyev int coords; 8195aa839c9SVladimir Kondratyev int ntouch; /* the finger number in touch */ 8205aa839c9SVladimir Kondratyev int ibt; /* button status */ 8215aa839c9SVladimir Kondratyev int i; 8225aa839c9SVladimir Kondratyev int slot; 823*9097284bSVladimir Kondratyev uint8_t id; 8245aa839c9SVladimir Kondratyev uint8_t fsize = sizeof(struct tp_finger) + params->tp->delta; 8255aa839c9SVladimir Kondratyev 826ef8397c2SVal Packett if ((params->tp->caps & USES_COMPACT_REPORT) != 0) 827ef8397c2SVal Packett fsize = sizeof(struct tp_finger_compact) + params->tp->delta; 828ef8397c2SVal Packett 8295aa839c9SVladimir Kondratyev if ((len < params->tp->offset + fsize) || 8305aa839c9SVladimir Kondratyev ((len - params->tp->offset) % fsize) != 0) { 8315aa839c9SVladimir Kondratyev DPRINTFN(BCM5974_LLEVEL_INFO, "Invalid length: %d, %x, %x\n", 8324f345989SVladimir Kondratyev len, params->tp->offset, fsize); 8335aa839c9SVladimir Kondratyev return; 8345aa839c9SVladimir Kondratyev } 8355aa839c9SVladimir Kondratyev 8365aa839c9SVladimir Kondratyev ibt = ((uint8_t *)data)[params->tp->button]; 8375aa839c9SVladimir Kondratyev ntouch = (len - params->tp->offset) / fsize; 8385aa839c9SVladimir Kondratyev 8395aa839c9SVladimir Kondratyev for (i = 0, slot = 0; i != ntouch; i++) { 840ef8397c2SVal Packett if ((params->tp->caps & USES_COMPACT_REPORT) != 0) { 841ef8397c2SVal Packett fc = (struct tp_finger_compact *)(((uint8_t *)data) + 842ef8397c2SVal Packett params->tp->offset + params->tp->delta + i * fsize); 84319c804b7SVladimir Kondratyev coords = (int)le32toh(fc->coords); 844*9097284bSVladimir Kondratyev id = fc->id_ori & 0x0f; 845*9097284bSVladimir Kondratyev slot = evdev_mt_id_to_slot(sc->sc_evdev, id); 846ef8397c2SVal Packett DPRINTFN(BCM5974_LLEVEL_INFO, 847ef8397c2SVal Packett "[%d]ibt=%d, taps=%d, x=%5d, y=%5d, state=%4d, " 848ef8397c2SVal Packett "tchmaj=%4d, tchmin=%4d, size=%4d, pressure=%4d, " 849*9097284bSVladimir Kondratyev "ot=%4x, id=%4x, slot=%d\n", 85019c804b7SVladimir Kondratyev i, ibt, ntouch, coords << 19 >> 19, 85119c804b7SVladimir Kondratyev coords << 6 >> 19, (u_int)coords >> 30, 85219c804b7SVladimir Kondratyev fc->touch_major, fc->touch_minor, fc->size, 853*9097284bSVladimir Kondratyev fc->pressure, fc->id_ori >> 5, id, slot); 854*9097284bSVladimir Kondratyev if (fc->touch_major == 0 || slot == -1) 855ef8397c2SVal Packett continue; 856ef8397c2SVal Packett slot_data = (union evdev_mt_slot) { 857*9097284bSVladimir Kondratyev .id = id, 85819c804b7SVladimir Kondratyev .x = coords << 19 >> 19, 85919c804b7SVladimir Kondratyev .y = params->y.min + params->y.max - 86019c804b7SVladimir Kondratyev ((coords << 6) >> 19), 861ef8397c2SVal Packett .p = fc->pressure, 862ef8397c2SVal Packett .maj = fc->touch_major << 2, 863ef8397c2SVal Packett .min = fc->touch_minor << 2, 86419c804b7SVladimir Kondratyev .ori = (int)(fc->id_ori >> 5) - 4, 865ef8397c2SVal Packett }; 866ef8397c2SVal Packett evdev_mt_push_slot(sc->sc_evdev, slot, &slot_data); 867ef8397c2SVal Packett continue; 868ef8397c2SVal Packett } 8695aa839c9SVladimir Kondratyev f = (struct tp_finger *)(((uint8_t *)data) + 8705aa839c9SVladimir Kondratyev params->tp->offset + params->tp->delta + i * fsize); 8715aa839c9SVladimir Kondratyev DPRINTFN(BCM5974_LLEVEL_INFO, 8725aa839c9SVladimir Kondratyev "[%d]ibt=%d, taps=%d, o=%4d, ax=%5d, ay=%5d, " 8735aa839c9SVladimir Kondratyev "rx=%5d, ry=%5d, tlmaj=%4d, tlmin=%4d, ot=%4x, " 874fda9ac06SGreg V "tchmaj=%4d, tchmin=%4d, pressure=%4d, m=%4x\n", 875fda9ac06SGreg V i, ibt, ntouch, BCM5974_LE2H(f->origin), 876fda9ac06SGreg V BCM5974_LE2H(f->abs_x), BCM5974_LE2H(f->abs_y), 877fda9ac06SGreg V BCM5974_LE2H(f->rel_x), BCM5974_LE2H(f->rel_y), 878fda9ac06SGreg V BCM5974_LE2H(f->tool_major), BCM5974_LE2H(f->tool_minor), 879fda9ac06SGreg V BCM5974_LE2H(f->orientation), BCM5974_LE2H(f->touch_major), 880fda9ac06SGreg V BCM5974_LE2H(f->touch_minor), BCM5974_LE2H(f->pressure), 881fda9ac06SGreg V BCM5974_LE2H(f->multi)); 8825aa839c9SVladimir Kondratyev 883fda9ac06SGreg V if (BCM5974_LE2H(f->touch_major) == 0) 8845aa839c9SVladimir Kondratyev continue; 8855aa839c9SVladimir Kondratyev slot_data = (union evdev_mt_slot) { 8865aa839c9SVladimir Kondratyev .id = slot, 887fda9ac06SGreg V .x = BCM5974_LE2H(f->abs_x), 888fda9ac06SGreg V .y = params->y.min + params->y.max - 889fda9ac06SGreg V BCM5974_LE2H(f->abs_y), 890fda9ac06SGreg V .p = BCM5974_LE2H(f->pressure), 891fda9ac06SGreg V .maj = BCM5974_LE2H(f->touch_major) << 1, 892fda9ac06SGreg V .min = BCM5974_LE2H(f->touch_minor) << 1, 893fda9ac06SGreg V .w_maj = BCM5974_LE2H(f->tool_major) << 1, 894fda9ac06SGreg V .w_min = BCM5974_LE2H(f->tool_minor) << 1, 895fda9ac06SGreg V .ori = params->o.max - BCM5974_LE2H(f->orientation), 8965aa839c9SVladimir Kondratyev }; 8975aa839c9SVladimir Kondratyev evdev_mt_push_slot(sc->sc_evdev, slot, &slot_data); 8985aa839c9SVladimir Kondratyev slot++; 8995aa839c9SVladimir Kondratyev } 9005aa839c9SVladimir Kondratyev 9015aa839c9SVladimir Kondratyev evdev_push_key(sc->sc_evdev, BTN_LEFT, ibt); 9025aa839c9SVladimir Kondratyev evdev_sync(sc->sc_evdev); 9035aa839c9SVladimir Kondratyev } 9045aa839c9SVladimir Kondratyev 9055aa839c9SVladimir Kondratyev static int 9065aa839c9SVladimir Kondratyev bcm5974_ev_open(struct evdev_dev *evdev) 9075aa839c9SVladimir Kondratyev { 9085aa839c9SVladimir Kondratyev struct bcm5974_softc *sc = evdev_get_softc(evdev); 9095aa839c9SVladimir Kondratyev int err; 9105aa839c9SVladimir Kondratyev 9115aa839c9SVladimir Kondratyev /* 9125aa839c9SVladimir Kondratyev * By default the touchpad behaves like a HID device, sending 9135aa839c9SVladimir Kondratyev * packets with reportID = 8. Such reports contain only 9145aa839c9SVladimir Kondratyev * limited information. They encode movement deltas and button 9155aa839c9SVladimir Kondratyev * events, but do not include data from the pressure 9165aa839c9SVladimir Kondratyev * sensors. The device input mode can be switched from HID 9175aa839c9SVladimir Kondratyev * reports to raw sensor data using vendor-specific USB 9185aa839c9SVladimir Kondratyev * control commands: 9195aa839c9SVladimir Kondratyev */ 9205aa839c9SVladimir Kondratyev err = bcm5974_set_device_mode(sc, true); 9215aa839c9SVladimir Kondratyev if (err != 0) { 9225aa839c9SVladimir Kondratyev DPRINTF("failed to set mode to RAW MODE (%d)\n", err); 9235aa839c9SVladimir Kondratyev return (err); 9245aa839c9SVladimir Kondratyev } 9255aa839c9SVladimir Kondratyev 9264151ac9fSVladimir Kondratyev return (hid_intr_start(sc->sc_dev)); 9275aa839c9SVladimir Kondratyev } 9285aa839c9SVladimir Kondratyev 9295aa839c9SVladimir Kondratyev static int 9305aa839c9SVladimir Kondratyev bcm5974_ev_close(struct evdev_dev *evdev) 9315aa839c9SVladimir Kondratyev { 9325aa839c9SVladimir Kondratyev struct bcm5974_softc *sc = evdev_get_softc(evdev); 9335aa839c9SVladimir Kondratyev int err; 9345aa839c9SVladimir Kondratyev 9354151ac9fSVladimir Kondratyev err = hid_intr_stop(sc->sc_dev); 9365aa839c9SVladimir Kondratyev if (err != 0) 9375aa839c9SVladimir Kondratyev return (err); 9385aa839c9SVladimir Kondratyev 9395aa839c9SVladimir Kondratyev /* 9405aa839c9SVladimir Kondratyev * During re-enumeration of the device we need to force the 9415aa839c9SVladimir Kondratyev * device back into HID mode before switching it to RAW 9425aa839c9SVladimir Kondratyev * mode. Else the device does not work like expected. 9435aa839c9SVladimir Kondratyev */ 9445aa839c9SVladimir Kondratyev err = bcm5974_set_device_mode(sc, false); 9455aa839c9SVladimir Kondratyev if (err != 0) 9465aa839c9SVladimir Kondratyev DPRINTF("Failed to set mode to HID MODE (%d)\n", err); 9475aa839c9SVladimir Kondratyev 9485aa839c9SVladimir Kondratyev return (err); 9495aa839c9SVladimir Kondratyev } 9505aa839c9SVladimir Kondratyev 9515aa839c9SVladimir Kondratyev static device_method_t bcm5974_methods[] = { 9525aa839c9SVladimir Kondratyev /* Device interface */ 9535aa839c9SVladimir Kondratyev DEVMETHOD(device_identify, bcm5974_identify), 9545aa839c9SVladimir Kondratyev DEVMETHOD(device_probe, bcm5974_probe), 9555aa839c9SVladimir Kondratyev DEVMETHOD(device_attach, bcm5974_attach), 9565aa839c9SVladimir Kondratyev DEVMETHOD(device_detach, bcm5974_detach), 95745b6c31aSGreg V DEVMETHOD(device_resume, bcm5974_resume), 9585aa839c9SVladimir Kondratyev DEVMETHOD_END 9595aa839c9SVladimir Kondratyev }; 9605aa839c9SVladimir Kondratyev 9615aa839c9SVladimir Kondratyev static driver_t bcm5974_driver = { 9625aa839c9SVladimir Kondratyev .name = "bcm5974", 9635aa839c9SVladimir Kondratyev .methods = bcm5974_methods, 9645aa839c9SVladimir Kondratyev .size = sizeof(struct bcm5974_softc) 9655aa839c9SVladimir Kondratyev }; 9665aa839c9SVladimir Kondratyev 9677eeede15SJohn Baldwin DRIVER_MODULE(bcm5974, hidbus, bcm5974_driver, NULL, NULL); 9685aa839c9SVladimir Kondratyev MODULE_DEPEND(bcm5974, hidbus, 1, 1, 1); 9695aa839c9SVladimir Kondratyev MODULE_DEPEND(bcm5974, hid, 1, 1, 1); 9705aa839c9SVladimir Kondratyev MODULE_DEPEND(bcm5974, evdev, 1, 1, 1); 9715aa839c9SVladimir Kondratyev MODULE_VERSION(bcm5974, 1); 9725aa839c9SVladimir Kondratyev HID_PNP_INFO(bcm5974_devs); 973