1f89bd95cSHenrik Rydberg /* 2f89bd95cSHenrik Rydberg * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver 3f89bd95cSHenrik Rydberg * 4f89bd95cSHenrik Rydberg * Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se) 5f89bd95cSHenrik Rydberg * 6f89bd95cSHenrik Rydberg * The USB initialization and package decoding was made by 7f89bd95cSHenrik Rydberg * Scott Shawcroft as part of the touchd user-space driver project: 8f89bd95cSHenrik Rydberg * Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com) 9f89bd95cSHenrik Rydberg * 10f89bd95cSHenrik Rydberg * The BCM5974 driver is based on the appletouch driver: 11f89bd95cSHenrik Rydberg * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) 12f89bd95cSHenrik Rydberg * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) 13f89bd95cSHenrik Rydberg * Copyright (C) 2005 Stelian Pop (stelian@popies.net) 14f89bd95cSHenrik Rydberg * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) 15f89bd95cSHenrik Rydberg * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) 16f89bd95cSHenrik Rydberg * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) 17f89bd95cSHenrik Rydberg * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) 18f89bd95cSHenrik Rydberg * 19f89bd95cSHenrik Rydberg * This program is free software; you can redistribute it and/or modify 20f89bd95cSHenrik Rydberg * it under the terms of the GNU General Public License as published by 21f89bd95cSHenrik Rydberg * the Free Software Foundation; either version 2 of the License, or 22f89bd95cSHenrik Rydberg * (at your option) any later version. 23f89bd95cSHenrik Rydberg * 24f89bd95cSHenrik Rydberg * This program is distributed in the hope that it will be useful, 25f89bd95cSHenrik Rydberg * but WITHOUT ANY WARRANTY; without even the implied warranty of 26f89bd95cSHenrik Rydberg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27f89bd95cSHenrik Rydberg * GNU General Public License for more details. 28f89bd95cSHenrik Rydberg * 29f89bd95cSHenrik Rydberg * You should have received a copy of the GNU General Public License 30f89bd95cSHenrik Rydberg * along with this program; if not, write to the Free Software 31f89bd95cSHenrik Rydberg * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 32f89bd95cSHenrik Rydberg * 33f89bd95cSHenrik Rydberg */ 34f89bd95cSHenrik Rydberg 35f89bd95cSHenrik Rydberg #include <linux/kernel.h> 36f89bd95cSHenrik Rydberg #include <linux/errno.h> 37f89bd95cSHenrik Rydberg #include <linux/init.h> 38f89bd95cSHenrik Rydberg #include <linux/slab.h> 39f89bd95cSHenrik Rydberg #include <linux/module.h> 40f89bd95cSHenrik Rydberg #include <linux/usb/input.h> 41f89bd95cSHenrik Rydberg #include <linux/hid.h> 42f89bd95cSHenrik Rydberg #include <linux/mutex.h> 4351c80b74SHenrik Rydberg #include <linux/input/mt.h> 44f89bd95cSHenrik Rydberg 45f89bd95cSHenrik Rydberg #define USB_VENDOR_ID_APPLE 0x05ac 46f89bd95cSHenrik Rydberg 47f89bd95cSHenrik Rydberg /* MacbookAir, aka wellspring */ 48f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 49f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 50f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 51f89bd95cSHenrik Rydberg /* MacbookProPenryn, aka wellspring2 */ 52f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 53f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 54f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 55158e9287SHenrik Rydberg /* Macbook5,1 (unibody), aka wellspring3 */ 56158e9287SHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 57158e9287SHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 58158e9287SHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 596021afcfSEdgar (gimli) Hucek /* MacbookAir3,2 (unibody), aka wellspring5 */ 606021afcfSEdgar (gimli) Hucek #define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f 616021afcfSEdgar (gimli) Hucek #define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240 626021afcfSEdgar (gimli) Hucek #define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241 636021afcfSEdgar (gimli) Hucek /* MacbookAir3,1 (unibody), aka wellspring4 */ 646021afcfSEdgar (gimli) Hucek #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 656021afcfSEdgar (gimli) Hucek #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 666021afcfSEdgar (gimli) Hucek #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 6747340bd9SAndy Botting /* Macbook8 (unibody, March 2011) */ 6847340bd9SAndy Botting #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 6947340bd9SAndy Botting #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 7047340bd9SAndy Botting #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 711c601beaSPieter-Augustijn Van Malleghem /* MacbookAir4,1 (unibody, July 2011) */ 721c601beaSPieter-Augustijn Van Malleghem #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249 731c601beaSPieter-Augustijn Van Malleghem #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a 741c601beaSPieter-Augustijn Van Malleghem #define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b 75db0b34b0SJoshua V. Dillon /* MacbookAir4,2 (unibody, July 2011) */ 76db0b34b0SJoshua V. Dillon #define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c 77db0b34b0SJoshua V. Dillon #define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d 78db0b34b0SJoshua V. Dillon #define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e 79c331eb58SAndrew Drake /* Macbook8,2 (unibody) */ 80c331eb58SAndrew Drake #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252 81c331eb58SAndrew Drake #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253 82c331eb58SAndrew Drake #define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254 833dde22a9SHenrik Rydberg /* MacbookPro10,1 (unibody, June 2012) */ 843dde22a9SHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262 853dde22a9SHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263 863dde22a9SHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264 878d80da90SDirk Hohndel /* MacbookPro10,2 (unibody, October 2012) */ 888d80da90SDirk Hohndel #define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259 898d80da90SDirk Hohndel #define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a 908d80da90SDirk Hohndel #define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b 91*148c1c8aSDmitry Torokhov /* MacbookAir6,2 (unibody, June 2013) */ 92*148c1c8aSDmitry Torokhov #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0291 93*148c1c8aSDmitry Torokhov #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0292 94*148c1c8aSDmitry Torokhov #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0293 95f89bd95cSHenrik Rydberg 96f89bd95cSHenrik Rydberg #define BCM5974_DEVICE(prod) { \ 97f89bd95cSHenrik Rydberg .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ 98f89bd95cSHenrik Rydberg USB_DEVICE_ID_MATCH_INT_CLASS | \ 99f89bd95cSHenrik Rydberg USB_DEVICE_ID_MATCH_INT_PROTOCOL), \ 100f89bd95cSHenrik Rydberg .idVendor = USB_VENDOR_ID_APPLE, \ 101f89bd95cSHenrik Rydberg .idProduct = (prod), \ 102f89bd95cSHenrik Rydberg .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ 103f89bd95cSHenrik Rydberg .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \ 104f89bd95cSHenrik Rydberg } 105f89bd95cSHenrik Rydberg 106f89bd95cSHenrik Rydberg /* table of devices that work with this driver */ 107f89bd95cSHenrik Rydberg static const struct usb_device_id bcm5974_table[] = { 108f89bd95cSHenrik Rydberg /* MacbookAir1.1 */ 109f89bd95cSHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), 110f89bd95cSHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO), 111f89bd95cSHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_JIS), 112f89bd95cSHenrik Rydberg /* MacbookProPenryn */ 113f89bd95cSHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), 114f89bd95cSHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), 115f89bd95cSHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), 116158e9287SHenrik Rydberg /* Macbook5,1 */ 117158e9287SHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), 118158e9287SHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), 119158e9287SHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), 1206021afcfSEdgar (gimli) Hucek /* MacbookAir3,2 */ 1216021afcfSEdgar (gimli) Hucek BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI), 1226021afcfSEdgar (gimli) Hucek BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO), 1236021afcfSEdgar (gimli) Hucek BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS), 1246021afcfSEdgar (gimli) Hucek /* MacbookAir3,1 */ 1256021afcfSEdgar (gimli) Hucek BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI), 1266021afcfSEdgar (gimli) Hucek BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO), 1276021afcfSEdgar (gimli) Hucek BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), 12847340bd9SAndy Botting /* MacbookPro8 */ 12947340bd9SAndy Botting BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI), 13047340bd9SAndy Botting BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO), 13147340bd9SAndy Botting BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), 1321c601beaSPieter-Augustijn Van Malleghem /* MacbookAir4,1 */ 1331c601beaSPieter-Augustijn Van Malleghem BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI), 1341c601beaSPieter-Augustijn Van Malleghem BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO), 1351c601beaSPieter-Augustijn Van Malleghem BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS), 136db0b34b0SJoshua V. Dillon /* MacbookAir4,2 */ 137db0b34b0SJoshua V. Dillon BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI), 138db0b34b0SJoshua V. Dillon BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO), 139db0b34b0SJoshua V. Dillon BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_JIS), 140c331eb58SAndrew Drake /* MacbookPro8,2 */ 141c331eb58SAndrew Drake BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI), 142c331eb58SAndrew Drake BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO), 143c331eb58SAndrew Drake BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS), 1443dde22a9SHenrik Rydberg /* MacbookPro10,1 */ 1453dde22a9SHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI), 1463dde22a9SHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO), 1473dde22a9SHenrik Rydberg BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS), 1488d80da90SDirk Hohndel /* MacbookPro10,2 */ 1498d80da90SDirk Hohndel BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI), 1508d80da90SDirk Hohndel BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO), 1518d80da90SDirk Hohndel BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS), 152*148c1c8aSDmitry Torokhov /* MacbookAir6,2 */ 153*148c1c8aSDmitry Torokhov BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI), 154*148c1c8aSDmitry Torokhov BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO), 155*148c1c8aSDmitry Torokhov BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS), 156f89bd95cSHenrik Rydberg /* Terminating entry */ 157f89bd95cSHenrik Rydberg {} 158f89bd95cSHenrik Rydberg }; 159f89bd95cSHenrik Rydberg MODULE_DEVICE_TABLE(usb, bcm5974_table); 160f89bd95cSHenrik Rydberg 161f89bd95cSHenrik Rydberg MODULE_AUTHOR("Henrik Rydberg"); 162f89bd95cSHenrik Rydberg MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver"); 163f89bd95cSHenrik Rydberg MODULE_LICENSE("GPL"); 164f89bd95cSHenrik Rydberg 165f89bd95cSHenrik Rydberg #define dprintk(level, format, a...)\ 166f89bd95cSHenrik Rydberg { if (debug >= level) printk(KERN_DEBUG format, ##a); } 167f89bd95cSHenrik Rydberg 168f89bd95cSHenrik Rydberg static int debug = 1; 169f89bd95cSHenrik Rydberg module_param(debug, int, 0644); 170f89bd95cSHenrik Rydberg MODULE_PARM_DESC(debug, "Activate debugging output"); 171f89bd95cSHenrik Rydberg 172f89bd95cSHenrik Rydberg /* button data structure */ 173f89bd95cSHenrik Rydberg struct bt_data { 174f89bd95cSHenrik Rydberg u8 unknown1; /* constant */ 175f89bd95cSHenrik Rydberg u8 button; /* left button */ 176f89bd95cSHenrik Rydberg u8 rel_x; /* relative x coordinate */ 177f89bd95cSHenrik Rydberg u8 rel_y; /* relative y coordinate */ 178f89bd95cSHenrik Rydberg }; 179f89bd95cSHenrik Rydberg 1809894cf0fSHenrik Rydberg /* trackpad header types */ 1819894cf0fSHenrik Rydberg enum tp_type { 182158e9287SHenrik Rydberg TYPE1, /* plain trackpad */ 183*148c1c8aSDmitry Torokhov TYPE2, /* button integrated in trackpad */ 184*148c1c8aSDmitry Torokhov TYPE3 /* additional header fields since June 2013 */ 185f89bd95cSHenrik Rydberg }; 186f89bd95cSHenrik Rydberg 1879894cf0fSHenrik Rydberg /* trackpad finger data offsets, le16-aligned */ 1889894cf0fSHenrik Rydberg #define FINGER_TYPE1 (13 * sizeof(__le16)) 189158e9287SHenrik Rydberg #define FINGER_TYPE2 (15 * sizeof(__le16)) 190*148c1c8aSDmitry Torokhov #define FINGER_TYPE3 (19 * sizeof(__le16)) 191158e9287SHenrik Rydberg 192158e9287SHenrik Rydberg /* trackpad button data offsets */ 193158e9287SHenrik Rydberg #define BUTTON_TYPE2 15 194*148c1c8aSDmitry Torokhov #define BUTTON_TYPE3 23 195158e9287SHenrik Rydberg 196158e9287SHenrik Rydberg /* list of device capability bits */ 197158e9287SHenrik Rydberg #define HAS_INTEGRATED_BUTTON 1 1989894cf0fSHenrik Rydberg 1999894cf0fSHenrik Rydberg /* trackpad finger structure, le16-aligned */ 200f89bd95cSHenrik Rydberg struct tp_finger { 20175e21e3fSHenrik Rydberg __le16 origin; /* zero when switching track finger */ 202f89bd95cSHenrik Rydberg __le16 abs_x; /* absolute x coodinate */ 203f89bd95cSHenrik Rydberg __le16 abs_y; /* absolute y coodinate */ 204f89bd95cSHenrik Rydberg __le16 rel_x; /* relative x coodinate */ 205f89bd95cSHenrik Rydberg __le16 rel_y; /* relative y coodinate */ 206f17953abSHenrik Rydberg __le16 tool_major; /* tool area, major axis */ 207f17953abSHenrik Rydberg __le16 tool_minor; /* tool area, minor axis */ 208f89bd95cSHenrik Rydberg __le16 orientation; /* 16384 when point, else 15 bit angle */ 209f17953abSHenrik Rydberg __le16 touch_major; /* touch area, major axis */ 210f17953abSHenrik Rydberg __le16 touch_minor; /* touch area, minor axis */ 211f89bd95cSHenrik Rydberg __le16 unused[3]; /* zeros */ 212f89bd95cSHenrik Rydberg __le16 multi; /* one finger: varies, more fingers: constant */ 2139894cf0fSHenrik Rydberg } __attribute__((packed,aligned(2))); 214f89bd95cSHenrik Rydberg 2159894cf0fSHenrik Rydberg /* trackpad finger data size, empirically at least ten fingers */ 216f17953abSHenrik Rydberg #define MAX_FINGERS 16 2179894cf0fSHenrik Rydberg #define SIZEOF_FINGER sizeof(struct tp_finger) 218f17953abSHenrik Rydberg #define SIZEOF_ALL_FINGERS (MAX_FINGERS * SIZEOF_FINGER) 2196f2701b7SHenrik Rydberg #define MAX_FINGER_ORIENTATION 16384 220f89bd95cSHenrik Rydberg 221f89bd95cSHenrik Rydberg /* device-specific parameters */ 222f89bd95cSHenrik Rydberg struct bcm5974_param { 2230e726966SHenrik Rydberg int snratio; /* signal-to-noise ratio */ 2240e726966SHenrik Rydberg int min; /* device minimum reading */ 2250e726966SHenrik Rydberg int max; /* device maximum reading */ 226f89bd95cSHenrik Rydberg }; 227f89bd95cSHenrik Rydberg 228f89bd95cSHenrik Rydberg /* device-specific configuration */ 229f89bd95cSHenrik Rydberg struct bcm5974_config { 230f89bd95cSHenrik Rydberg int ansi, iso, jis; /* the product id of this device */ 231158e9287SHenrik Rydberg int caps; /* device capability bitmask */ 232f89bd95cSHenrik Rydberg int bt_ep; /* the endpoint of the button interface */ 233f89bd95cSHenrik Rydberg int bt_datalen; /* data length of the button interface */ 234f89bd95cSHenrik Rydberg int tp_ep; /* the endpoint of the trackpad interface */ 2359894cf0fSHenrik Rydberg enum tp_type tp_type; /* type of trackpad interface */ 2369894cf0fSHenrik Rydberg int tp_offset; /* offset to trackpad finger data */ 237f89bd95cSHenrik Rydberg int tp_datalen; /* data length of the trackpad interface */ 238f89bd95cSHenrik Rydberg struct bcm5974_param p; /* finger pressure limits */ 239f89bd95cSHenrik Rydberg struct bcm5974_param w; /* finger width limits */ 240f89bd95cSHenrik Rydberg struct bcm5974_param x; /* horizontal limits */ 241f89bd95cSHenrik Rydberg struct bcm5974_param y; /* vertical limits */ 2420e726966SHenrik Rydberg struct bcm5974_param o; /* orientation limits */ 243f89bd95cSHenrik Rydberg }; 244f89bd95cSHenrik Rydberg 245f89bd95cSHenrik Rydberg /* logical device structure */ 246f89bd95cSHenrik Rydberg struct bcm5974 { 247f89bd95cSHenrik Rydberg char phys[64]; 248f89bd95cSHenrik Rydberg struct usb_device *udev; /* usb device */ 24988da765fSDmitry Torokhov struct usb_interface *intf; /* our interface */ 250f89bd95cSHenrik Rydberg struct input_dev *input; /* input dev */ 251f89bd95cSHenrik Rydberg struct bcm5974_config cfg; /* device configuration */ 252f89bd95cSHenrik Rydberg struct mutex pm_mutex; /* serialize access to open/suspend */ 253f89bd95cSHenrik Rydberg int opened; /* 1: opened, 0: closed */ 254f89bd95cSHenrik Rydberg struct urb *bt_urb; /* button usb request block */ 255f89bd95cSHenrik Rydberg struct bt_data *bt_data; /* button transferred data */ 256f89bd95cSHenrik Rydberg struct urb *tp_urb; /* trackpad usb request block */ 2579894cf0fSHenrik Rydberg u8 *tp_data; /* trackpad transferred data */ 25851c80b74SHenrik Rydberg const struct tp_finger *index[MAX_FINGERS]; /* finger index data */ 25951c80b74SHenrik Rydberg struct input_mt_pos pos[MAX_FINGERS]; /* position array */ 26051c80b74SHenrik Rydberg int slots[MAX_FINGERS]; /* slot assignments */ 261f89bd95cSHenrik Rydberg }; 262f89bd95cSHenrik Rydberg 263f89bd95cSHenrik Rydberg /* logical signal quality */ 264f89bd95cSHenrik Rydberg #define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ 26551c80b74SHenrik Rydberg #define SN_WIDTH 25 /* width signal-to-noise ratio */ 266f89bd95cSHenrik Rydberg #define SN_COORD 250 /* coordinate signal-to-noise ratio */ 2670e726966SHenrik Rydberg #define SN_ORIENT 10 /* orientation signal-to-noise ratio */ 26875e21e3fSHenrik Rydberg 269f89bd95cSHenrik Rydberg /* device constants */ 270f89bd95cSHenrik Rydberg static const struct bcm5974_config bcm5974_config_table[] = { 271f89bd95cSHenrik Rydberg { 272f89bd95cSHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, 273f89bd95cSHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING_ISO, 274f89bd95cSHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING_JIS, 275158e9287SHenrik Rydberg 0, 276f89bd95cSHenrik Rydberg 0x84, sizeof(struct bt_data), 2779894cf0fSHenrik Rydberg 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, 2780e726966SHenrik Rydberg { SN_PRESSURE, 0, 256 }, 2790e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 2800e726966SHenrik Rydberg { SN_COORD, -4824, 5342 }, 2810e726966SHenrik Rydberg { SN_COORD, -172, 5820 }, 2820e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 283f89bd95cSHenrik Rydberg }, 284f89bd95cSHenrik Rydberg { 285f89bd95cSHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, 286f89bd95cSHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, 287f89bd95cSHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, 288158e9287SHenrik Rydberg 0, 289f89bd95cSHenrik Rydberg 0x84, sizeof(struct bt_data), 2909894cf0fSHenrik Rydberg 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, 2910e726966SHenrik Rydberg { SN_PRESSURE, 0, 256 }, 2920e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 2930e726966SHenrik Rydberg { SN_COORD, -4824, 4824 }, 2940e726966SHenrik Rydberg { SN_COORD, -172, 4290 }, 2950e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 296f89bd95cSHenrik Rydberg }, 297158e9287SHenrik Rydberg { 298158e9287SHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, 299158e9287SHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, 300158e9287SHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, 301158e9287SHenrik Rydberg HAS_INTEGRATED_BUTTON, 302158e9287SHenrik Rydberg 0x84, sizeof(struct bt_data), 303158e9287SHenrik Rydberg 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3040e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3050e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3060e726966SHenrik Rydberg { SN_COORD, -4460, 5166 }, 3070e726966SHenrik Rydberg { SN_COORD, -75, 6700 }, 3080e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 309158e9287SHenrik Rydberg }, 3106021afcfSEdgar (gimli) Hucek { 3116021afcfSEdgar (gimli) Hucek USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI, 3126021afcfSEdgar (gimli) Hucek USB_DEVICE_ID_APPLE_WELLSPRING4_ISO, 3136021afcfSEdgar (gimli) Hucek USB_DEVICE_ID_APPLE_WELLSPRING4_JIS, 3146021afcfSEdgar (gimli) Hucek HAS_INTEGRATED_BUTTON, 3156021afcfSEdgar (gimli) Hucek 0x84, sizeof(struct bt_data), 3166021afcfSEdgar (gimli) Hucek 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3170e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3180e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3190e726966SHenrik Rydberg { SN_COORD, -4620, 5140 }, 3200e726966SHenrik Rydberg { SN_COORD, -150, 6600 }, 3210e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 3226021afcfSEdgar (gimli) Hucek }, 3236021afcfSEdgar (gimli) Hucek { 3246021afcfSEdgar (gimli) Hucek USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI, 3256021afcfSEdgar (gimli) Hucek USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO, 3266021afcfSEdgar (gimli) Hucek USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS, 3276021afcfSEdgar (gimli) Hucek HAS_INTEGRATED_BUTTON, 3286021afcfSEdgar (gimli) Hucek 0x84, sizeof(struct bt_data), 3296021afcfSEdgar (gimli) Hucek 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3300e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3310e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3320e726966SHenrik Rydberg { SN_COORD, -4616, 5112 }, 3330e726966SHenrik Rydberg { SN_COORD, -142, 5234 }, 3340e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 3356021afcfSEdgar (gimli) Hucek }, 33647340bd9SAndy Botting { 33747340bd9SAndy Botting USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI, 33847340bd9SAndy Botting USB_DEVICE_ID_APPLE_WELLSPRING5_ISO, 33947340bd9SAndy Botting USB_DEVICE_ID_APPLE_WELLSPRING5_JIS, 34047340bd9SAndy Botting HAS_INTEGRATED_BUTTON, 34147340bd9SAndy Botting 0x84, sizeof(struct bt_data), 34247340bd9SAndy Botting 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3430e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3440e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3450e726966SHenrik Rydberg { SN_COORD, -4415, 5050 }, 3460e726966SHenrik Rydberg { SN_COORD, -55, 6680 }, 3470e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 34847340bd9SAndy Botting }, 349db0b34b0SJoshua V. Dillon { 350db0b34b0SJoshua V. Dillon USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI, 351db0b34b0SJoshua V. Dillon USB_DEVICE_ID_APPLE_WELLSPRING6_ISO, 352db0b34b0SJoshua V. Dillon USB_DEVICE_ID_APPLE_WELLSPRING6_JIS, 353db0b34b0SJoshua V. Dillon HAS_INTEGRATED_BUTTON, 354db0b34b0SJoshua V. Dillon 0x84, sizeof(struct bt_data), 355db0b34b0SJoshua V. Dillon 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3560e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3570e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3580e726966SHenrik Rydberg { SN_COORD, -4620, 5140 }, 3590e726966SHenrik Rydberg { SN_COORD, -150, 6600 }, 3600e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 361db0b34b0SJoshua V. Dillon }, 362c331eb58SAndrew Drake { 363c331eb58SAndrew Drake USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI, 364c331eb58SAndrew Drake USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO, 365c331eb58SAndrew Drake USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS, 366c331eb58SAndrew Drake HAS_INTEGRATED_BUTTON, 367c331eb58SAndrew Drake 0x84, sizeof(struct bt_data), 368c331eb58SAndrew Drake 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3690e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3700e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3710e726966SHenrik Rydberg { SN_COORD, -4750, 5280 }, 3720e726966SHenrik Rydberg { SN_COORD, -150, 6730 }, 3730e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 374c331eb58SAndrew Drake }, 3751c601beaSPieter-Augustijn Van Malleghem { 3761c601beaSPieter-Augustijn Van Malleghem USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI, 3771c601beaSPieter-Augustijn Van Malleghem USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO, 3781c601beaSPieter-Augustijn Van Malleghem USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS, 3791c601beaSPieter-Augustijn Van Malleghem HAS_INTEGRATED_BUTTON, 3801c601beaSPieter-Augustijn Van Malleghem 0x84, sizeof(struct bt_data), 3811c601beaSPieter-Augustijn Van Malleghem 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3820e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3830e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3840e726966SHenrik Rydberg { SN_COORD, -4620, 5140 }, 3850e726966SHenrik Rydberg { SN_COORD, -150, 6600 }, 3860e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 3871c601beaSPieter-Augustijn Van Malleghem }, 3883dde22a9SHenrik Rydberg { 3893dde22a9SHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI, 3903dde22a9SHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING7_ISO, 3913dde22a9SHenrik Rydberg USB_DEVICE_ID_APPLE_WELLSPRING7_JIS, 3923dde22a9SHenrik Rydberg HAS_INTEGRATED_BUTTON, 3933dde22a9SHenrik Rydberg 0x84, sizeof(struct bt_data), 3943dde22a9SHenrik Rydberg 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 3950e726966SHenrik Rydberg { SN_PRESSURE, 0, 300 }, 3960e726966SHenrik Rydberg { SN_WIDTH, 0, 2048 }, 3970e726966SHenrik Rydberg { SN_COORD, -4750, 5280 }, 3980e726966SHenrik Rydberg { SN_COORD, -150, 6730 }, 3990e726966SHenrik Rydberg { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 4003dde22a9SHenrik Rydberg }, 4018d80da90SDirk Hohndel { 4028d80da90SDirk Hohndel USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI, 4038d80da90SDirk Hohndel USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO, 4048d80da90SDirk Hohndel USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS, 4058d80da90SDirk Hohndel HAS_INTEGRATED_BUTTON, 4068d80da90SDirk Hohndel 0x84, sizeof(struct bt_data), 4078d80da90SDirk Hohndel 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, 4088d80da90SDirk Hohndel { SN_PRESSURE, 0, 300 }, 4098d80da90SDirk Hohndel { SN_WIDTH, 0, 2048 }, 4108d80da90SDirk Hohndel { SN_COORD, -4750, 5280 }, 4118d80da90SDirk Hohndel { SN_COORD, -150, 6730 }, 4128d80da90SDirk Hohndel { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 4138d80da90SDirk Hohndel }, 414*148c1c8aSDmitry Torokhov { 415*148c1c8aSDmitry Torokhov USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI, 416*148c1c8aSDmitry Torokhov USB_DEVICE_ID_APPLE_WELLSPRING8_ISO, 417*148c1c8aSDmitry Torokhov USB_DEVICE_ID_APPLE_WELLSPRING8_JIS, 418*148c1c8aSDmitry Torokhov HAS_INTEGRATED_BUTTON, 419*148c1c8aSDmitry Torokhov 0, sizeof(struct bt_data), 420*148c1c8aSDmitry Torokhov 0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS, 421*148c1c8aSDmitry Torokhov { SN_PRESSURE, 0, 300 }, 422*148c1c8aSDmitry Torokhov { SN_WIDTH, 0, 2048 }, 423*148c1c8aSDmitry Torokhov { SN_COORD, -4620, 5140 }, 424*148c1c8aSDmitry Torokhov { SN_COORD, -150, 6600 }, 425*148c1c8aSDmitry Torokhov { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } 426*148c1c8aSDmitry Torokhov }, 427f89bd95cSHenrik Rydberg {} 428f89bd95cSHenrik Rydberg }; 429f89bd95cSHenrik Rydberg 430f89bd95cSHenrik Rydberg /* return the device-specific configuration by device */ 431f89bd95cSHenrik Rydberg static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev) 432f89bd95cSHenrik Rydberg { 433f89bd95cSHenrik Rydberg u16 id = le16_to_cpu(udev->descriptor.idProduct); 434f89bd95cSHenrik Rydberg const struct bcm5974_config *cfg; 435f89bd95cSHenrik Rydberg 436f89bd95cSHenrik Rydberg for (cfg = bcm5974_config_table; cfg->ansi; ++cfg) 437f89bd95cSHenrik Rydberg if (cfg->ansi == id || cfg->iso == id || cfg->jis == id) 438f89bd95cSHenrik Rydberg return cfg; 439f89bd95cSHenrik Rydberg 440f89bd95cSHenrik Rydberg return bcm5974_config_table; 441f89bd95cSHenrik Rydberg } 442f89bd95cSHenrik Rydberg 443f89bd95cSHenrik Rydberg /* convert 16-bit little endian to signed integer */ 444f89bd95cSHenrik Rydberg static inline int raw2int(__le16 x) 445f89bd95cSHenrik Rydberg { 446f89bd95cSHenrik Rydberg return (signed short)le16_to_cpu(x); 447f89bd95cSHenrik Rydberg } 448f89bd95cSHenrik Rydberg 4490e726966SHenrik Rydberg static void set_abs(struct input_dev *input, unsigned int code, 4500e726966SHenrik Rydberg const struct bcm5974_param *p) 451f89bd95cSHenrik Rydberg { 4520e726966SHenrik Rydberg int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0; 4530e726966SHenrik Rydberg input_set_abs_params(input, code, p->min, p->max, fuzz, 0); 454f89bd95cSHenrik Rydberg } 455f89bd95cSHenrik Rydberg 456f89bd95cSHenrik Rydberg /* setup which logical events to report */ 457f89bd95cSHenrik Rydberg static void setup_events_to_report(struct input_dev *input_dev, 458f89bd95cSHenrik Rydberg const struct bcm5974_config *cfg) 459f89bd95cSHenrik Rydberg { 460f89bd95cSHenrik Rydberg __set_bit(EV_ABS, input_dev->evbit); 461f89bd95cSHenrik Rydberg 4620e726966SHenrik Rydberg /* for synaptics only */ 4630e726966SHenrik Rydberg input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0); 4640e726966SHenrik Rydberg input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0); 4650e726966SHenrik Rydberg 4666f2701b7SHenrik Rydberg /* finger touch area */ 4670e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w); 4680e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w); 4696f2701b7SHenrik Rydberg /* finger approach area */ 4700e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w); 4710e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w); 4726f2701b7SHenrik Rydberg /* finger orientation */ 4730e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o); 4746f2701b7SHenrik Rydberg /* finger position */ 4750e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x); 4760e726966SHenrik Rydberg set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y); 4776f2701b7SHenrik Rydberg 478f89bd95cSHenrik Rydberg __set_bit(EV_KEY, input_dev->evbit); 479f89bd95cSHenrik Rydberg __set_bit(BTN_LEFT, input_dev->keybit); 480c13aea03SHenrik Rydberg 48152965cc0SJussi Pakkanen if (cfg->caps & HAS_INTEGRATED_BUTTON) 48252965cc0SJussi Pakkanen __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); 48352965cc0SJussi Pakkanen 48451c80b74SHenrik Rydberg input_mt_init_slots(input_dev, MAX_FINGERS, 48551c80b74SHenrik Rydberg INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK); 486f89bd95cSHenrik Rydberg } 487f89bd95cSHenrik Rydberg 488f89bd95cSHenrik Rydberg /* report button data as logical button state */ 489f89bd95cSHenrik Rydberg static int report_bt_state(struct bcm5974 *dev, int size) 490f89bd95cSHenrik Rydberg { 491f89bd95cSHenrik Rydberg if (size != sizeof(struct bt_data)) 492f89bd95cSHenrik Rydberg return -EIO; 493f89bd95cSHenrik Rydberg 49453402193SHenrik Rydberg dprintk(7, 49553402193SHenrik Rydberg "bcm5974: button data: %x %x %x %x\n", 49653402193SHenrik Rydberg dev->bt_data->unknown1, dev->bt_data->button, 49753402193SHenrik Rydberg dev->bt_data->rel_x, dev->bt_data->rel_y); 49853402193SHenrik Rydberg 499f89bd95cSHenrik Rydberg input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); 500f89bd95cSHenrik Rydberg input_sync(dev->input); 501f89bd95cSHenrik Rydberg 502f89bd95cSHenrik Rydberg return 0; 503f89bd95cSHenrik Rydberg } 504f89bd95cSHenrik Rydberg 50551c80b74SHenrik Rydberg static void report_finger_data(struct input_dev *input, int slot, 50651c80b74SHenrik Rydberg const struct input_mt_pos *pos, 5076f2701b7SHenrik Rydberg const struct tp_finger *f) 5086f2701b7SHenrik Rydberg { 50951c80b74SHenrik Rydberg input_mt_slot(input, slot); 51051c80b74SHenrik Rydberg input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 51151c80b74SHenrik Rydberg 51257157becSHenrik Rydberg input_report_abs(input, ABS_MT_TOUCH_MAJOR, 513f17953abSHenrik Rydberg raw2int(f->touch_major) << 1); 51457157becSHenrik Rydberg input_report_abs(input, ABS_MT_TOUCH_MINOR, 515f17953abSHenrik Rydberg raw2int(f->touch_minor) << 1); 51657157becSHenrik Rydberg input_report_abs(input, ABS_MT_WIDTH_MAJOR, 517f17953abSHenrik Rydberg raw2int(f->tool_major) << 1); 51857157becSHenrik Rydberg input_report_abs(input, ABS_MT_WIDTH_MINOR, 519f17953abSHenrik Rydberg raw2int(f->tool_minor) << 1); 5206f2701b7SHenrik Rydberg input_report_abs(input, ABS_MT_ORIENTATION, 5216f2701b7SHenrik Rydberg MAX_FINGER_ORIENTATION - raw2int(f->orientation)); 52251c80b74SHenrik Rydberg input_report_abs(input, ABS_MT_POSITION_X, pos->x); 52351c80b74SHenrik Rydberg input_report_abs(input, ABS_MT_POSITION_Y, pos->y); 5246f2701b7SHenrik Rydberg } 5256f2701b7SHenrik Rydberg 5260e726966SHenrik Rydberg static void report_synaptics_data(struct input_dev *input, 5270e726966SHenrik Rydberg const struct bcm5974_config *cfg, 5280e726966SHenrik Rydberg const struct tp_finger *f, int raw_n) 5290e726966SHenrik Rydberg { 5300e726966SHenrik Rydberg int abs_p = 0, abs_w = 0; 5310e726966SHenrik Rydberg 5320e726966SHenrik Rydberg if (raw_n) { 5330e726966SHenrik Rydberg int p = raw2int(f->touch_major); 5340e726966SHenrik Rydberg int w = raw2int(f->tool_major); 5350e726966SHenrik Rydberg if (p > 0 && raw2int(f->origin)) { 5360e726966SHenrik Rydberg abs_p = clamp_val(256 * p / cfg->p.max, 0, 255); 5370e726966SHenrik Rydberg abs_w = clamp_val(16 * w / cfg->w.max, 0, 15); 5380e726966SHenrik Rydberg } 5390e726966SHenrik Rydberg } 5400e726966SHenrik Rydberg 5410e726966SHenrik Rydberg input_report_abs(input, ABS_PRESSURE, abs_p); 5420e726966SHenrik Rydberg input_report_abs(input, ABS_TOOL_WIDTH, abs_w); 5430e726966SHenrik Rydberg } 5440e726966SHenrik Rydberg 545f89bd95cSHenrik Rydberg /* report trackpad data as logical trackpad state */ 546f89bd95cSHenrik Rydberg static int report_tp_state(struct bcm5974 *dev, int size) 547f89bd95cSHenrik Rydberg { 548f89bd95cSHenrik Rydberg const struct bcm5974_config *c = &dev->cfg; 5499894cf0fSHenrik Rydberg const struct tp_finger *f; 550f89bd95cSHenrik Rydberg struct input_dev *input = dev->input; 55151c80b74SHenrik Rydberg int raw_n, i, n = 0; 552f89bd95cSHenrik Rydberg 5539894cf0fSHenrik Rydberg if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) 554f89bd95cSHenrik Rydberg return -EIO; 555f89bd95cSHenrik Rydberg 5569894cf0fSHenrik Rydberg /* finger data, le16-aligned */ 5579894cf0fSHenrik Rydberg f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); 5589894cf0fSHenrik Rydberg raw_n = (size - c->tp_offset) / SIZEOF_FINGER; 5599894cf0fSHenrik Rydberg 56051c80b74SHenrik Rydberg for (i = 0; i < raw_n; i++) { 56151c80b74SHenrik Rydberg if (raw2int(f[i].touch_major) == 0) 56251c80b74SHenrik Rydberg continue; 56351c80b74SHenrik Rydberg dev->pos[n].x = raw2int(f[i].abs_x); 56451c80b74SHenrik Rydberg dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y); 56551c80b74SHenrik Rydberg dev->index[n++] = &f[i]; 56675e21e3fSHenrik Rydberg } 567f89bd95cSHenrik Rydberg 56851c80b74SHenrik Rydberg input_mt_assign_slots(input, dev->slots, dev->pos, n); 56951c80b74SHenrik Rydberg 57051c80b74SHenrik Rydberg for (i = 0; i < n; i++) 57151c80b74SHenrik Rydberg report_finger_data(input, dev->slots[i], 57251c80b74SHenrik Rydberg &dev->pos[i], dev->index[i]); 57351c80b74SHenrik Rydberg 57451c80b74SHenrik Rydberg input_mt_sync_frame(input); 57550635115SHenrik Rydberg 5760e726966SHenrik Rydberg report_synaptics_data(input, c, f, raw_n); 57775e21e3fSHenrik Rydberg 578158e9287SHenrik Rydberg /* type 2 reports button events via ibt only */ 5790e726966SHenrik Rydberg if (c->tp_type == TYPE2) { 5800e726966SHenrik Rydberg int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); 581158e9287SHenrik Rydberg input_report_key(input, BTN_LEFT, ibt); 5820e726966SHenrik Rydberg } 583158e9287SHenrik Rydberg 584*148c1c8aSDmitry Torokhov if (c->tp_type == TYPE3) 585*148c1c8aSDmitry Torokhov input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]); 586*148c1c8aSDmitry Torokhov 587f89bd95cSHenrik Rydberg input_sync(input); 588f89bd95cSHenrik Rydberg 589f89bd95cSHenrik Rydberg return 0; 590f89bd95cSHenrik Rydberg } 591f89bd95cSHenrik Rydberg 592f89bd95cSHenrik Rydberg /* Wellspring initialization constants */ 593f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1 594f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9 595f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300 596f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0 597f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01 598cd72ad3fSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_NORMAL_VALUE 0x08 599f89bd95cSHenrik Rydberg 600cd72ad3fSHenrik Rydberg static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on) 601f89bd95cSHenrik Rydberg { 602f89bd95cSHenrik Rydberg int retval = 0, size; 603*148c1c8aSDmitry Torokhov char *data; 604f89bd95cSHenrik Rydberg 605*148c1c8aSDmitry Torokhov /* Type 3 does not require a mode switch */ 606*148c1c8aSDmitry Torokhov if (dev->cfg.tp_type == TYPE3) 607*148c1c8aSDmitry Torokhov return 0; 608*148c1c8aSDmitry Torokhov 609*148c1c8aSDmitry Torokhov data = kmalloc(8, GFP_KERNEL); 610f89bd95cSHenrik Rydberg if (!data) { 611ab943ca8SGreg Kroah-Hartman dev_err(&dev->intf->dev, "out of memory\n"); 612f89bd95cSHenrik Rydberg retval = -ENOMEM; 613f89bd95cSHenrik Rydberg goto out; 614f89bd95cSHenrik Rydberg } 615f89bd95cSHenrik Rydberg 616f89bd95cSHenrik Rydberg /* read configuration */ 617f89bd95cSHenrik Rydberg size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), 618f89bd95cSHenrik Rydberg BCM5974_WELLSPRING_MODE_READ_REQUEST_ID, 619f89bd95cSHenrik Rydberg USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 620f89bd95cSHenrik Rydberg BCM5974_WELLSPRING_MODE_REQUEST_VALUE, 621f89bd95cSHenrik Rydberg BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); 622f89bd95cSHenrik Rydberg 623f89bd95cSHenrik Rydberg if (size != 8) { 624ab943ca8SGreg Kroah-Hartman dev_err(&dev->intf->dev, "could not read from device\n"); 625f89bd95cSHenrik Rydberg retval = -EIO; 626f89bd95cSHenrik Rydberg goto out; 627f89bd95cSHenrik Rydberg } 628f89bd95cSHenrik Rydberg 629f89bd95cSHenrik Rydberg /* apply the mode switch */ 630cd72ad3fSHenrik Rydberg data[0] = on ? 631cd72ad3fSHenrik Rydberg BCM5974_WELLSPRING_MODE_VENDOR_VALUE : 632cd72ad3fSHenrik Rydberg BCM5974_WELLSPRING_MODE_NORMAL_VALUE; 633f89bd95cSHenrik Rydberg 634f89bd95cSHenrik Rydberg /* write configuration */ 635f89bd95cSHenrik Rydberg size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 636f89bd95cSHenrik Rydberg BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID, 637f89bd95cSHenrik Rydberg USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 638f89bd95cSHenrik Rydberg BCM5974_WELLSPRING_MODE_REQUEST_VALUE, 639f89bd95cSHenrik Rydberg BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); 640f89bd95cSHenrik Rydberg 641f89bd95cSHenrik Rydberg if (size != 8) { 642ab943ca8SGreg Kroah-Hartman dev_err(&dev->intf->dev, "could not write to device\n"); 643f89bd95cSHenrik Rydberg retval = -EIO; 644f89bd95cSHenrik Rydberg goto out; 645f89bd95cSHenrik Rydberg } 646f89bd95cSHenrik Rydberg 647cd72ad3fSHenrik Rydberg dprintk(2, "bcm5974: switched to %s mode.\n", 648cd72ad3fSHenrik Rydberg on ? "wellspring" : "normal"); 649f89bd95cSHenrik Rydberg 650f89bd95cSHenrik Rydberg out: 651f89bd95cSHenrik Rydberg kfree(data); 652f89bd95cSHenrik Rydberg return retval; 653f89bd95cSHenrik Rydberg } 654f89bd95cSHenrik Rydberg 655f89bd95cSHenrik Rydberg static void bcm5974_irq_button(struct urb *urb) 656f89bd95cSHenrik Rydberg { 657f89bd95cSHenrik Rydberg struct bcm5974 *dev = urb->context; 658ab943ca8SGreg Kroah-Hartman struct usb_interface *intf = dev->intf; 659f89bd95cSHenrik Rydberg int error; 660f89bd95cSHenrik Rydberg 661f89bd95cSHenrik Rydberg switch (urb->status) { 662f89bd95cSHenrik Rydberg case 0: 663f89bd95cSHenrik Rydberg break; 664f89bd95cSHenrik Rydberg case -EOVERFLOW: 665f89bd95cSHenrik Rydberg case -ECONNRESET: 666f89bd95cSHenrik Rydberg case -ENOENT: 667f89bd95cSHenrik Rydberg case -ESHUTDOWN: 668ab943ca8SGreg Kroah-Hartman dev_dbg(&intf->dev, "button urb shutting down: %d\n", 669bd028769SGreg Kroah-Hartman urb->status); 670f89bd95cSHenrik Rydberg return; 671f89bd95cSHenrik Rydberg default: 672ab943ca8SGreg Kroah-Hartman dev_dbg(&intf->dev, "button urb status: %d\n", urb->status); 673f89bd95cSHenrik Rydberg goto exit; 674f89bd95cSHenrik Rydberg } 675f89bd95cSHenrik Rydberg 676f89bd95cSHenrik Rydberg if (report_bt_state(dev, dev->bt_urb->actual_length)) 677f89bd95cSHenrik Rydberg dprintk(1, "bcm5974: bad button package, length: %d\n", 678f89bd95cSHenrik Rydberg dev->bt_urb->actual_length); 679f89bd95cSHenrik Rydberg 680f89bd95cSHenrik Rydberg exit: 681f89bd95cSHenrik Rydberg error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC); 682f89bd95cSHenrik Rydberg if (error) 683ab943ca8SGreg Kroah-Hartman dev_err(&intf->dev, "button urb failed: %d\n", error); 684f89bd95cSHenrik Rydberg } 685f89bd95cSHenrik Rydberg 686f89bd95cSHenrik Rydberg static void bcm5974_irq_trackpad(struct urb *urb) 687f89bd95cSHenrik Rydberg { 688f89bd95cSHenrik Rydberg struct bcm5974 *dev = urb->context; 689ab943ca8SGreg Kroah-Hartman struct usb_interface *intf = dev->intf; 690f89bd95cSHenrik Rydberg int error; 691f89bd95cSHenrik Rydberg 692f89bd95cSHenrik Rydberg switch (urb->status) { 693f89bd95cSHenrik Rydberg case 0: 694f89bd95cSHenrik Rydberg break; 695f89bd95cSHenrik Rydberg case -EOVERFLOW: 696f89bd95cSHenrik Rydberg case -ECONNRESET: 697f89bd95cSHenrik Rydberg case -ENOENT: 698f89bd95cSHenrik Rydberg case -ESHUTDOWN: 699ab943ca8SGreg Kroah-Hartman dev_dbg(&intf->dev, "trackpad urb shutting down: %d\n", 700bd028769SGreg Kroah-Hartman urb->status); 701f89bd95cSHenrik Rydberg return; 702f89bd95cSHenrik Rydberg default: 703ab943ca8SGreg Kroah-Hartman dev_dbg(&intf->dev, "trackpad urb status: %d\n", urb->status); 704f89bd95cSHenrik Rydberg goto exit; 705f89bd95cSHenrik Rydberg } 706f89bd95cSHenrik Rydberg 707f89bd95cSHenrik Rydberg /* control response ignored */ 708f89bd95cSHenrik Rydberg if (dev->tp_urb->actual_length == 2) 709f89bd95cSHenrik Rydberg goto exit; 710f89bd95cSHenrik Rydberg 711f89bd95cSHenrik Rydberg if (report_tp_state(dev, dev->tp_urb->actual_length)) 712f89bd95cSHenrik Rydberg dprintk(1, "bcm5974: bad trackpad package, length: %d\n", 713f89bd95cSHenrik Rydberg dev->tp_urb->actual_length); 714f89bd95cSHenrik Rydberg 715f89bd95cSHenrik Rydberg exit: 716f89bd95cSHenrik Rydberg error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); 717f89bd95cSHenrik Rydberg if (error) 718ab943ca8SGreg Kroah-Hartman dev_err(&intf->dev, "trackpad urb failed: %d\n", error); 719f89bd95cSHenrik Rydberg } 720f89bd95cSHenrik Rydberg 721f89bd95cSHenrik Rydberg /* 722f89bd95cSHenrik Rydberg * The Wellspring trackpad, like many recent Apple trackpads, share 723f89bd95cSHenrik Rydberg * the usb device with the keyboard. Since keyboards are usually 724f89bd95cSHenrik Rydberg * handled by the HID system, the device ends up being handled by two 725f89bd95cSHenrik Rydberg * modules. Setting up the device therefore becomes slightly 726f89bd95cSHenrik Rydberg * complicated. To enable multitouch features, a mode switch is 727f89bd95cSHenrik Rydberg * required, which is usually applied via the control interface of the 728f89bd95cSHenrik Rydberg * device. It can be argued where this switch should take place. In 729f89bd95cSHenrik Rydberg * some drivers, like appletouch, the switch is made during 730f89bd95cSHenrik Rydberg * probe. However, the hid module may also alter the state of the 731f89bd95cSHenrik Rydberg * device, resulting in trackpad malfunction under certain 732f89bd95cSHenrik Rydberg * circumstances. To get around this problem, there is at least one 733f89bd95cSHenrik Rydberg * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to 73425985edcSLucas De Marchi * receive a reset_resume request rather than the normal resume. 735f89bd95cSHenrik Rydberg * Since the implementation of reset_resume is equal to mode switch 736f89bd95cSHenrik Rydberg * plus start_traffic, it seems easier to always do the switch when 737f89bd95cSHenrik Rydberg * starting traffic on the device. 738f89bd95cSHenrik Rydberg */ 739f89bd95cSHenrik Rydberg static int bcm5974_start_traffic(struct bcm5974 *dev) 740f89bd95cSHenrik Rydberg { 7411719ec41SLuo Jinghua int error; 7421719ec41SLuo Jinghua 7431719ec41SLuo Jinghua error = bcm5974_wellspring_mode(dev, true); 7441719ec41SLuo Jinghua if (error) { 745f89bd95cSHenrik Rydberg dprintk(1, "bcm5974: mode switch failed\n"); 7461719ec41SLuo Jinghua goto err_out; 747f89bd95cSHenrik Rydberg } 748f89bd95cSHenrik Rydberg 74943f482b4SHenrik Rydberg if (dev->bt_urb) { 7501719ec41SLuo Jinghua error = usb_submit_urb(dev->bt_urb, GFP_KERNEL); 7511719ec41SLuo Jinghua if (error) 7521719ec41SLuo Jinghua goto err_reset_mode; 75343f482b4SHenrik Rydberg } 754f89bd95cSHenrik Rydberg 7551719ec41SLuo Jinghua error = usb_submit_urb(dev->tp_urb, GFP_KERNEL); 7561719ec41SLuo Jinghua if (error) 757f89bd95cSHenrik Rydberg goto err_kill_bt; 758f89bd95cSHenrik Rydberg 759f89bd95cSHenrik Rydberg return 0; 760f89bd95cSHenrik Rydberg 761f89bd95cSHenrik Rydberg err_kill_bt: 762f89bd95cSHenrik Rydberg usb_kill_urb(dev->bt_urb); 7631719ec41SLuo Jinghua err_reset_mode: 7641719ec41SLuo Jinghua bcm5974_wellspring_mode(dev, false); 7651719ec41SLuo Jinghua err_out: 7661719ec41SLuo Jinghua return error; 767f89bd95cSHenrik Rydberg } 768f89bd95cSHenrik Rydberg 769f89bd95cSHenrik Rydberg static void bcm5974_pause_traffic(struct bcm5974 *dev) 770f89bd95cSHenrik Rydberg { 771f89bd95cSHenrik Rydberg usb_kill_urb(dev->tp_urb); 772f89bd95cSHenrik Rydberg usb_kill_urb(dev->bt_urb); 773cd72ad3fSHenrik Rydberg bcm5974_wellspring_mode(dev, false); 774f89bd95cSHenrik Rydberg } 775f89bd95cSHenrik Rydberg 776f89bd95cSHenrik Rydberg /* 777f89bd95cSHenrik Rydberg * The code below implements open/close and manual suspend/resume. 778f89bd95cSHenrik Rydberg * All functions may be called in random order. 779f89bd95cSHenrik Rydberg * 780f89bd95cSHenrik Rydberg * Opening a suspended device fails with EACCES - permission denied. 781f89bd95cSHenrik Rydberg * 782f89bd95cSHenrik Rydberg * Failing a resume leaves the device resumed but closed. 783f89bd95cSHenrik Rydberg */ 784f89bd95cSHenrik Rydberg static int bcm5974_open(struct input_dev *input) 785f89bd95cSHenrik Rydberg { 786f89bd95cSHenrik Rydberg struct bcm5974 *dev = input_get_drvdata(input); 787f89bd95cSHenrik Rydberg int error; 788f89bd95cSHenrik Rydberg 78988da765fSDmitry Torokhov error = usb_autopm_get_interface(dev->intf); 79088da765fSDmitry Torokhov if (error) 79188da765fSDmitry Torokhov return error; 79288da765fSDmitry Torokhov 793f89bd95cSHenrik Rydberg mutex_lock(&dev->pm_mutex); 794f89bd95cSHenrik Rydberg 795f89bd95cSHenrik Rydberg error = bcm5974_start_traffic(dev); 796f89bd95cSHenrik Rydberg if (!error) 797f89bd95cSHenrik Rydberg dev->opened = 1; 798f89bd95cSHenrik Rydberg 799f89bd95cSHenrik Rydberg mutex_unlock(&dev->pm_mutex); 800f89bd95cSHenrik Rydberg 80188da765fSDmitry Torokhov if (error) 80288da765fSDmitry Torokhov usb_autopm_put_interface(dev->intf); 80388da765fSDmitry Torokhov 804f89bd95cSHenrik Rydberg return error; 805f89bd95cSHenrik Rydberg } 806f89bd95cSHenrik Rydberg 807f89bd95cSHenrik Rydberg static void bcm5974_close(struct input_dev *input) 808f89bd95cSHenrik Rydberg { 809f89bd95cSHenrik Rydberg struct bcm5974 *dev = input_get_drvdata(input); 810f89bd95cSHenrik Rydberg 811f89bd95cSHenrik Rydberg mutex_lock(&dev->pm_mutex); 812f89bd95cSHenrik Rydberg 813f89bd95cSHenrik Rydberg bcm5974_pause_traffic(dev); 814f89bd95cSHenrik Rydberg dev->opened = 0; 815f89bd95cSHenrik Rydberg 816f89bd95cSHenrik Rydberg mutex_unlock(&dev->pm_mutex); 81788da765fSDmitry Torokhov 81888da765fSDmitry Torokhov usb_autopm_put_interface(dev->intf); 819f89bd95cSHenrik Rydberg } 820f89bd95cSHenrik Rydberg 821f89bd95cSHenrik Rydberg static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message) 822f89bd95cSHenrik Rydberg { 823f89bd95cSHenrik Rydberg struct bcm5974 *dev = usb_get_intfdata(iface); 824f89bd95cSHenrik Rydberg 825f89bd95cSHenrik Rydberg mutex_lock(&dev->pm_mutex); 826f89bd95cSHenrik Rydberg 827f89bd95cSHenrik Rydberg if (dev->opened) 828f89bd95cSHenrik Rydberg bcm5974_pause_traffic(dev); 829f89bd95cSHenrik Rydberg 830f89bd95cSHenrik Rydberg mutex_unlock(&dev->pm_mutex); 831f89bd95cSHenrik Rydberg 832f89bd95cSHenrik Rydberg return 0; 833f89bd95cSHenrik Rydberg } 834f89bd95cSHenrik Rydberg 835f89bd95cSHenrik Rydberg static int bcm5974_resume(struct usb_interface *iface) 836f89bd95cSHenrik Rydberg { 837f89bd95cSHenrik Rydberg struct bcm5974 *dev = usb_get_intfdata(iface); 838f89bd95cSHenrik Rydberg int error = 0; 839f89bd95cSHenrik Rydberg 840f89bd95cSHenrik Rydberg mutex_lock(&dev->pm_mutex); 841f89bd95cSHenrik Rydberg 842f89bd95cSHenrik Rydberg if (dev->opened) 843f89bd95cSHenrik Rydberg error = bcm5974_start_traffic(dev); 844f89bd95cSHenrik Rydberg 845f89bd95cSHenrik Rydberg mutex_unlock(&dev->pm_mutex); 846f89bd95cSHenrik Rydberg 847f89bd95cSHenrik Rydberg return error; 848f89bd95cSHenrik Rydberg } 849f89bd95cSHenrik Rydberg 850f89bd95cSHenrik Rydberg static int bcm5974_probe(struct usb_interface *iface, 851f89bd95cSHenrik Rydberg const struct usb_device_id *id) 852f89bd95cSHenrik Rydberg { 853f89bd95cSHenrik Rydberg struct usb_device *udev = interface_to_usbdev(iface); 854f89bd95cSHenrik Rydberg const struct bcm5974_config *cfg; 855f89bd95cSHenrik Rydberg struct bcm5974 *dev; 856f89bd95cSHenrik Rydberg struct input_dev *input_dev; 857f89bd95cSHenrik Rydberg int error = -ENOMEM; 858f89bd95cSHenrik Rydberg 859f89bd95cSHenrik Rydberg /* find the product index */ 860f89bd95cSHenrik Rydberg cfg = bcm5974_get_config(udev); 861f89bd95cSHenrik Rydberg 862f89bd95cSHenrik Rydberg /* allocate memory for our device state and initialize it */ 863f89bd95cSHenrik Rydberg dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL); 864f89bd95cSHenrik Rydberg input_dev = input_allocate_device(); 865f89bd95cSHenrik Rydberg if (!dev || !input_dev) { 8666c1d1b24SGreg Kroah-Hartman dev_err(&iface->dev, "out of memory\n"); 867f89bd95cSHenrik Rydberg goto err_free_devs; 868f89bd95cSHenrik Rydberg } 869f89bd95cSHenrik Rydberg 870f89bd95cSHenrik Rydberg dev->udev = udev; 87188da765fSDmitry Torokhov dev->intf = iface; 872f89bd95cSHenrik Rydberg dev->input = input_dev; 873f89bd95cSHenrik Rydberg dev->cfg = *cfg; 874f89bd95cSHenrik Rydberg mutex_init(&dev->pm_mutex); 875f89bd95cSHenrik Rydberg 876f89bd95cSHenrik Rydberg /* setup urbs */ 87743f482b4SHenrik Rydberg if (cfg->tp_type == TYPE1) { 878f89bd95cSHenrik Rydberg dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); 879f89bd95cSHenrik Rydberg if (!dev->bt_urb) 880f89bd95cSHenrik Rydberg goto err_free_devs; 88143f482b4SHenrik Rydberg } 882f89bd95cSHenrik Rydberg 883f89bd95cSHenrik Rydberg dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); 884f89bd95cSHenrik Rydberg if (!dev->tp_urb) 885f89bd95cSHenrik Rydberg goto err_free_bt_urb; 886f89bd95cSHenrik Rydberg 88743f482b4SHenrik Rydberg if (dev->bt_urb) { 888997ea58eSDaniel Mack dev->bt_data = usb_alloc_coherent(dev->udev, 889f89bd95cSHenrik Rydberg dev->cfg.bt_datalen, GFP_KERNEL, 890f89bd95cSHenrik Rydberg &dev->bt_urb->transfer_dma); 891f89bd95cSHenrik Rydberg if (!dev->bt_data) 892f89bd95cSHenrik Rydberg goto err_free_urb; 89343f482b4SHenrik Rydberg } 894f89bd95cSHenrik Rydberg 895997ea58eSDaniel Mack dev->tp_data = usb_alloc_coherent(dev->udev, 896f89bd95cSHenrik Rydberg dev->cfg.tp_datalen, GFP_KERNEL, 897f89bd95cSHenrik Rydberg &dev->tp_urb->transfer_dma); 898f89bd95cSHenrik Rydberg if (!dev->tp_data) 899f89bd95cSHenrik Rydberg goto err_free_bt_buffer; 900f89bd95cSHenrik Rydberg 90143f482b4SHenrik Rydberg if (dev->bt_urb) 902f89bd95cSHenrik Rydberg usb_fill_int_urb(dev->bt_urb, udev, 903f89bd95cSHenrik Rydberg usb_rcvintpipe(udev, cfg->bt_ep), 904f89bd95cSHenrik Rydberg dev->bt_data, dev->cfg.bt_datalen, 905f89bd95cSHenrik Rydberg bcm5974_irq_button, dev, 1); 906f89bd95cSHenrik Rydberg 907f89bd95cSHenrik Rydberg usb_fill_int_urb(dev->tp_urb, udev, 908f89bd95cSHenrik Rydberg usb_rcvintpipe(udev, cfg->tp_ep), 909f89bd95cSHenrik Rydberg dev->tp_data, dev->cfg.tp_datalen, 910f89bd95cSHenrik Rydberg bcm5974_irq_trackpad, dev, 1); 911f89bd95cSHenrik Rydberg 912f89bd95cSHenrik Rydberg /* create bcm5974 device */ 913f89bd95cSHenrik Rydberg usb_make_path(udev, dev->phys, sizeof(dev->phys)); 914f89bd95cSHenrik Rydberg strlcat(dev->phys, "/input0", sizeof(dev->phys)); 915f89bd95cSHenrik Rydberg 916f89bd95cSHenrik Rydberg input_dev->name = "bcm5974"; 917f89bd95cSHenrik Rydberg input_dev->phys = dev->phys; 918f89bd95cSHenrik Rydberg usb_to_input_id(dev->udev, &input_dev->id); 919158e9287SHenrik Rydberg /* report driver capabilities via the version field */ 920158e9287SHenrik Rydberg input_dev->id.version = cfg->caps; 921f89bd95cSHenrik Rydberg input_dev->dev.parent = &iface->dev; 922f89bd95cSHenrik Rydberg 923f89bd95cSHenrik Rydberg input_set_drvdata(input_dev, dev); 924f89bd95cSHenrik Rydberg 925f89bd95cSHenrik Rydberg input_dev->open = bcm5974_open; 926f89bd95cSHenrik Rydberg input_dev->close = bcm5974_close; 927f89bd95cSHenrik Rydberg 928f89bd95cSHenrik Rydberg setup_events_to_report(input_dev, cfg); 929f89bd95cSHenrik Rydberg 930f89bd95cSHenrik Rydberg error = input_register_device(dev->input); 931f89bd95cSHenrik Rydberg if (error) 932f89bd95cSHenrik Rydberg goto err_free_buffer; 933f89bd95cSHenrik Rydberg 934f89bd95cSHenrik Rydberg /* save our data pointer in this interface device */ 935f89bd95cSHenrik Rydberg usb_set_intfdata(iface, dev); 936f89bd95cSHenrik Rydberg 937f89bd95cSHenrik Rydberg return 0; 938f89bd95cSHenrik Rydberg 939f89bd95cSHenrik Rydberg err_free_buffer: 940997ea58eSDaniel Mack usb_free_coherent(dev->udev, dev->cfg.tp_datalen, 941f89bd95cSHenrik Rydberg dev->tp_data, dev->tp_urb->transfer_dma); 942f89bd95cSHenrik Rydberg err_free_bt_buffer: 94343f482b4SHenrik Rydberg if (dev->bt_urb) 944997ea58eSDaniel Mack usb_free_coherent(dev->udev, dev->cfg.bt_datalen, 945f89bd95cSHenrik Rydberg dev->bt_data, dev->bt_urb->transfer_dma); 946f89bd95cSHenrik Rydberg err_free_urb: 947f89bd95cSHenrik Rydberg usb_free_urb(dev->tp_urb); 948f89bd95cSHenrik Rydberg err_free_bt_urb: 949f89bd95cSHenrik Rydberg usb_free_urb(dev->bt_urb); 950f89bd95cSHenrik Rydberg err_free_devs: 951f89bd95cSHenrik Rydberg usb_set_intfdata(iface, NULL); 952f89bd95cSHenrik Rydberg input_free_device(input_dev); 953f89bd95cSHenrik Rydberg kfree(dev); 954f89bd95cSHenrik Rydberg return error; 955f89bd95cSHenrik Rydberg } 956f89bd95cSHenrik Rydberg 957f89bd95cSHenrik Rydberg static void bcm5974_disconnect(struct usb_interface *iface) 958f89bd95cSHenrik Rydberg { 959f89bd95cSHenrik Rydberg struct bcm5974 *dev = usb_get_intfdata(iface); 960f89bd95cSHenrik Rydberg 961f89bd95cSHenrik Rydberg usb_set_intfdata(iface, NULL); 962f89bd95cSHenrik Rydberg 963f89bd95cSHenrik Rydberg input_unregister_device(dev->input); 964997ea58eSDaniel Mack usb_free_coherent(dev->udev, dev->cfg.tp_datalen, 965f89bd95cSHenrik Rydberg dev->tp_data, dev->tp_urb->transfer_dma); 96643f482b4SHenrik Rydberg if (dev->bt_urb) 967997ea58eSDaniel Mack usb_free_coherent(dev->udev, dev->cfg.bt_datalen, 968f89bd95cSHenrik Rydberg dev->bt_data, dev->bt_urb->transfer_dma); 969f89bd95cSHenrik Rydberg usb_free_urb(dev->tp_urb); 970f89bd95cSHenrik Rydberg usb_free_urb(dev->bt_urb); 971f89bd95cSHenrik Rydberg kfree(dev); 972f89bd95cSHenrik Rydberg } 973f89bd95cSHenrik Rydberg 974f89bd95cSHenrik Rydberg static struct usb_driver bcm5974_driver = { 975f89bd95cSHenrik Rydberg .name = "bcm5974", 976f89bd95cSHenrik Rydberg .probe = bcm5974_probe, 977f89bd95cSHenrik Rydberg .disconnect = bcm5974_disconnect, 978f89bd95cSHenrik Rydberg .suspend = bcm5974_suspend, 979f89bd95cSHenrik Rydberg .resume = bcm5974_resume, 980f89bd95cSHenrik Rydberg .id_table = bcm5974_table, 98188da765fSDmitry Torokhov .supports_autosuspend = 1, 982f89bd95cSHenrik Rydberg }; 983f89bd95cSHenrik Rydberg 98408642e7cSGreg Kroah-Hartman module_usb_driver(bcm5974_driver); 985