1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se)
6*4882a593Smuzhiyun * Copyright (C) 2015 John Horan (knasher@gmail.com)
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * The USB initialization and package decoding was made by
9*4882a593Smuzhiyun * Scott Shawcroft as part of the touchd user-space driver project:
10*4882a593Smuzhiyun * Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com)
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * The BCM5974 driver is based on the appletouch driver:
13*4882a593Smuzhiyun * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
14*4882a593Smuzhiyun * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net)
15*4882a593Smuzhiyun * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
16*4882a593Smuzhiyun * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
17*4882a593Smuzhiyun * Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
18*4882a593Smuzhiyun * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
19*4882a593Smuzhiyun * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch)
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/kernel.h>
23*4882a593Smuzhiyun #include <linux/errno.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun #include <linux/module.h>
26*4882a593Smuzhiyun #include <linux/usb/input.h>
27*4882a593Smuzhiyun #include <linux/hid.h>
28*4882a593Smuzhiyun #include <linux/mutex.h>
29*4882a593Smuzhiyun #include <linux/input/mt.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define USB_VENDOR_ID_APPLE 0x05ac
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /* MacbookAir, aka wellspring */
34*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
35*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
36*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
37*4882a593Smuzhiyun /* MacbookProPenryn, aka wellspring2 */
38*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
39*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
40*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
41*4882a593Smuzhiyun /* Macbook5,1 (unibody), aka wellspring3 */
42*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
43*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
44*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
45*4882a593Smuzhiyun /* MacbookAir3,2 (unibody), aka wellspring5 */
46*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
47*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
48*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
49*4882a593Smuzhiyun /* MacbookAir3,1 (unibody), aka wellspring4 */
50*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
51*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
52*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
53*4882a593Smuzhiyun /* Macbook8 (unibody, March 2011) */
54*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
55*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
56*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
57*4882a593Smuzhiyun /* MacbookAir4,1 (unibody, July 2011) */
58*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
59*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
60*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
61*4882a593Smuzhiyun /* MacbookAir4,2 (unibody, July 2011) */
62*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
63*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
64*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
65*4882a593Smuzhiyun /* Macbook8,2 (unibody) */
66*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252
67*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253
68*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254
69*4882a593Smuzhiyun /* MacbookPro10,1 (unibody, June 2012) */
70*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262
71*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263
72*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264
73*4882a593Smuzhiyun /* MacbookPro10,2 (unibody, October 2012) */
74*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259
75*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a
76*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b
77*4882a593Smuzhiyun /* MacbookAir6,2 (unibody, June 2013) */
78*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
79*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
80*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
81*4882a593Smuzhiyun /* MacbookPro12,1 (2015) */
82*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272
83*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
84*4882a593Smuzhiyun #define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #define BCM5974_DEVICE(prod) { \
87*4882a593Smuzhiyun .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
88*4882a593Smuzhiyun USB_DEVICE_ID_MATCH_INT_CLASS | \
89*4882a593Smuzhiyun USB_DEVICE_ID_MATCH_INT_PROTOCOL), \
90*4882a593Smuzhiyun .idVendor = USB_VENDOR_ID_APPLE, \
91*4882a593Smuzhiyun .idProduct = (prod), \
92*4882a593Smuzhiyun .bInterfaceClass = USB_INTERFACE_CLASS_HID, \
93*4882a593Smuzhiyun .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* table of devices that work with this driver */
97*4882a593Smuzhiyun static const struct usb_device_id bcm5974_table[] = {
98*4882a593Smuzhiyun /* MacbookAir1.1 */
99*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
100*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
101*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
102*4882a593Smuzhiyun /* MacbookProPenryn */
103*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
104*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
105*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
106*4882a593Smuzhiyun /* Macbook5,1 */
107*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI),
108*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO),
109*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
110*4882a593Smuzhiyun /* MacbookAir3,2 */
111*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
112*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
113*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
114*4882a593Smuzhiyun /* MacbookAir3,1 */
115*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
116*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
117*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
118*4882a593Smuzhiyun /* MacbookPro8 */
119*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
120*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
121*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
122*4882a593Smuzhiyun /* MacbookAir4,1 */
123*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
124*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
125*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
126*4882a593Smuzhiyun /* MacbookAir4,2 */
127*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
128*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
129*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
130*4882a593Smuzhiyun /* MacbookPro8,2 */
131*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
132*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
133*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
134*4882a593Smuzhiyun /* MacbookPro10,1 */
135*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
136*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
137*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
138*4882a593Smuzhiyun /* MacbookPro10,2 */
139*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
140*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
141*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
142*4882a593Smuzhiyun /* MacbookAir6,2 */
143*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
144*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
145*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
146*4882a593Smuzhiyun /* MacbookPro12,1 */
147*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
148*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
149*4882a593Smuzhiyun BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
150*4882a593Smuzhiyun /* Terminating entry */
151*4882a593Smuzhiyun {}
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, bcm5974_table);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun MODULE_AUTHOR("Henrik Rydberg");
156*4882a593Smuzhiyun MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver");
157*4882a593Smuzhiyun MODULE_LICENSE("GPL");
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun #define dprintk(level, format, a...)\
160*4882a593Smuzhiyun { if (debug >= level) printk(KERN_DEBUG format, ##a); }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun static int debug = 1;
163*4882a593Smuzhiyun module_param(debug, int, 0644);
164*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "Activate debugging output");
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* button data structure */
167*4882a593Smuzhiyun struct bt_data {
168*4882a593Smuzhiyun u8 unknown1; /* constant */
169*4882a593Smuzhiyun u8 button; /* left button */
170*4882a593Smuzhiyun u8 rel_x; /* relative x coordinate */
171*4882a593Smuzhiyun u8 rel_y; /* relative y coordinate */
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* trackpad header types */
175*4882a593Smuzhiyun enum tp_type {
176*4882a593Smuzhiyun TYPE1, /* plain trackpad */
177*4882a593Smuzhiyun TYPE2, /* button integrated in trackpad */
178*4882a593Smuzhiyun TYPE3, /* additional header fields since June 2013 */
179*4882a593Smuzhiyun TYPE4 /* additional header field for pressure data */
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* trackpad finger data offsets, le16-aligned */
183*4882a593Smuzhiyun #define HEADER_TYPE1 (13 * sizeof(__le16))
184*4882a593Smuzhiyun #define HEADER_TYPE2 (15 * sizeof(__le16))
185*4882a593Smuzhiyun #define HEADER_TYPE3 (19 * sizeof(__le16))
186*4882a593Smuzhiyun #define HEADER_TYPE4 (23 * sizeof(__le16))
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* trackpad button data offsets */
189*4882a593Smuzhiyun #define BUTTON_TYPE1 0
190*4882a593Smuzhiyun #define BUTTON_TYPE2 15
191*4882a593Smuzhiyun #define BUTTON_TYPE3 23
192*4882a593Smuzhiyun #define BUTTON_TYPE4 31
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* list of device capability bits */
195*4882a593Smuzhiyun #define HAS_INTEGRATED_BUTTON 1
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* trackpad finger data block size */
198*4882a593Smuzhiyun #define FSIZE_TYPE1 (14 * sizeof(__le16))
199*4882a593Smuzhiyun #define FSIZE_TYPE2 (14 * sizeof(__le16))
200*4882a593Smuzhiyun #define FSIZE_TYPE3 (14 * sizeof(__le16))
201*4882a593Smuzhiyun #define FSIZE_TYPE4 (15 * sizeof(__le16))
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* offset from header to finger struct */
204*4882a593Smuzhiyun #define DELTA_TYPE1 (0 * sizeof(__le16))
205*4882a593Smuzhiyun #define DELTA_TYPE2 (0 * sizeof(__le16))
206*4882a593Smuzhiyun #define DELTA_TYPE3 (0 * sizeof(__le16))
207*4882a593Smuzhiyun #define DELTA_TYPE4 (1 * sizeof(__le16))
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /* usb control message mode switch data */
210*4882a593Smuzhiyun #define USBMSG_TYPE1 8, 0x300, 0, 0, 0x1, 0x8
211*4882a593Smuzhiyun #define USBMSG_TYPE2 8, 0x300, 0, 0, 0x1, 0x8
212*4882a593Smuzhiyun #define USBMSG_TYPE3 8, 0x300, 0, 0, 0x1, 0x8
213*4882a593Smuzhiyun #define USBMSG_TYPE4 2, 0x302, 2, 1, 0x1, 0x0
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* Wellspring initialization constants */
216*4882a593Smuzhiyun #define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1
217*4882a593Smuzhiyun #define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* trackpad finger structure, le16-aligned */
220*4882a593Smuzhiyun struct tp_finger {
221*4882a593Smuzhiyun __le16 origin; /* zero when switching track finger */
222*4882a593Smuzhiyun __le16 abs_x; /* absolute x coodinate */
223*4882a593Smuzhiyun __le16 abs_y; /* absolute y coodinate */
224*4882a593Smuzhiyun __le16 rel_x; /* relative x coodinate */
225*4882a593Smuzhiyun __le16 rel_y; /* relative y coodinate */
226*4882a593Smuzhiyun __le16 tool_major; /* tool area, major axis */
227*4882a593Smuzhiyun __le16 tool_minor; /* tool area, minor axis */
228*4882a593Smuzhiyun __le16 orientation; /* 16384 when point, else 15 bit angle */
229*4882a593Smuzhiyun __le16 touch_major; /* touch area, major axis */
230*4882a593Smuzhiyun __le16 touch_minor; /* touch area, minor axis */
231*4882a593Smuzhiyun __le16 unused[2]; /* zeros */
232*4882a593Smuzhiyun __le16 pressure; /* pressure on forcetouch touchpad */
233*4882a593Smuzhiyun __le16 multi; /* one finger: varies, more fingers: constant */
234*4882a593Smuzhiyun } __attribute__((packed,aligned(2)));
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /* trackpad finger data size, empirically at least ten fingers */
237*4882a593Smuzhiyun #define MAX_FINGERS 16
238*4882a593Smuzhiyun #define MAX_FINGER_ORIENTATION 16384
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /* device-specific parameters */
241*4882a593Smuzhiyun struct bcm5974_param {
242*4882a593Smuzhiyun int snratio; /* signal-to-noise ratio */
243*4882a593Smuzhiyun int min; /* device minimum reading */
244*4882a593Smuzhiyun int max; /* device maximum reading */
245*4882a593Smuzhiyun };
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* device-specific configuration */
248*4882a593Smuzhiyun struct bcm5974_config {
249*4882a593Smuzhiyun int ansi, iso, jis; /* the product id of this device */
250*4882a593Smuzhiyun int caps; /* device capability bitmask */
251*4882a593Smuzhiyun int bt_ep; /* the endpoint of the button interface */
252*4882a593Smuzhiyun int bt_datalen; /* data length of the button interface */
253*4882a593Smuzhiyun int tp_ep; /* the endpoint of the trackpad interface */
254*4882a593Smuzhiyun enum tp_type tp_type; /* type of trackpad interface */
255*4882a593Smuzhiyun int tp_header; /* bytes in header block */
256*4882a593Smuzhiyun int tp_datalen; /* data length of the trackpad interface */
257*4882a593Smuzhiyun int tp_button; /* offset to button data */
258*4882a593Smuzhiyun int tp_fsize; /* bytes in single finger block */
259*4882a593Smuzhiyun int tp_delta; /* offset from header to finger struct */
260*4882a593Smuzhiyun int um_size; /* usb control message length */
261*4882a593Smuzhiyun int um_req_val; /* usb control message value */
262*4882a593Smuzhiyun int um_req_idx; /* usb control message index */
263*4882a593Smuzhiyun int um_switch_idx; /* usb control message mode switch index */
264*4882a593Smuzhiyun int um_switch_on; /* usb control message mode switch on */
265*4882a593Smuzhiyun int um_switch_off; /* usb control message mode switch off */
266*4882a593Smuzhiyun struct bcm5974_param p; /* finger pressure limits */
267*4882a593Smuzhiyun struct bcm5974_param w; /* finger width limits */
268*4882a593Smuzhiyun struct bcm5974_param x; /* horizontal limits */
269*4882a593Smuzhiyun struct bcm5974_param y; /* vertical limits */
270*4882a593Smuzhiyun struct bcm5974_param o; /* orientation limits */
271*4882a593Smuzhiyun };
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* logical device structure */
274*4882a593Smuzhiyun struct bcm5974 {
275*4882a593Smuzhiyun char phys[64];
276*4882a593Smuzhiyun struct usb_device *udev; /* usb device */
277*4882a593Smuzhiyun struct usb_interface *intf; /* our interface */
278*4882a593Smuzhiyun struct input_dev *input; /* input dev */
279*4882a593Smuzhiyun struct bcm5974_config cfg; /* device configuration */
280*4882a593Smuzhiyun struct mutex pm_mutex; /* serialize access to open/suspend */
281*4882a593Smuzhiyun int opened; /* 1: opened, 0: closed */
282*4882a593Smuzhiyun struct urb *bt_urb; /* button usb request block */
283*4882a593Smuzhiyun struct bt_data *bt_data; /* button transferred data */
284*4882a593Smuzhiyun struct urb *tp_urb; /* trackpad usb request block */
285*4882a593Smuzhiyun u8 *tp_data; /* trackpad transferred data */
286*4882a593Smuzhiyun const struct tp_finger *index[MAX_FINGERS]; /* finger index data */
287*4882a593Smuzhiyun struct input_mt_pos pos[MAX_FINGERS]; /* position array */
288*4882a593Smuzhiyun int slots[MAX_FINGERS]; /* slot assignments */
289*4882a593Smuzhiyun };
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* trackpad finger block data, le16-aligned */
get_tp_finger(const struct bcm5974 * dev,int i)292*4882a593Smuzhiyun static const struct tp_finger *get_tp_finger(const struct bcm5974 *dev, int i)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun const struct bcm5974_config *c = &dev->cfg;
295*4882a593Smuzhiyun u8 *f_base = dev->tp_data + c->tp_header + c->tp_delta;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun return (const struct tp_finger *)(f_base + i * c->tp_fsize);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun #define DATAFORMAT(type) \
301*4882a593Smuzhiyun type, \
302*4882a593Smuzhiyun HEADER_##type, \
303*4882a593Smuzhiyun HEADER_##type + (MAX_FINGERS) * (FSIZE_##type), \
304*4882a593Smuzhiyun BUTTON_##type, \
305*4882a593Smuzhiyun FSIZE_##type, \
306*4882a593Smuzhiyun DELTA_##type, \
307*4882a593Smuzhiyun USBMSG_##type
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* logical signal quality */
310*4882a593Smuzhiyun #define SN_PRESSURE 45 /* pressure signal-to-noise ratio */
311*4882a593Smuzhiyun #define SN_WIDTH 25 /* width signal-to-noise ratio */
312*4882a593Smuzhiyun #define SN_COORD 250 /* coordinate signal-to-noise ratio */
313*4882a593Smuzhiyun #define SN_ORIENT 10 /* orientation signal-to-noise ratio */
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /* device constants */
316*4882a593Smuzhiyun static const struct bcm5974_config bcm5974_config_table[] = {
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING_ANSI,
319*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING_ISO,
320*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
321*4882a593Smuzhiyun 0,
322*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
323*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE1),
324*4882a593Smuzhiyun { SN_PRESSURE, 0, 256 },
325*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
326*4882a593Smuzhiyun { SN_COORD, -4824, 5342 },
327*4882a593Smuzhiyun { SN_COORD, -172, 5820 },
328*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
329*4882a593Smuzhiyun },
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
332*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING2_ISO,
333*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
334*4882a593Smuzhiyun 0,
335*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
336*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE1),
337*4882a593Smuzhiyun { SN_PRESSURE, 0, 256 },
338*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
339*4882a593Smuzhiyun { SN_COORD, -4824, 4824 },
340*4882a593Smuzhiyun { SN_COORD, -172, 4290 },
341*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
342*4882a593Smuzhiyun },
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI,
345*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING3_ISO,
346*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING3_JIS,
347*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
348*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
349*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
350*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
351*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
352*4882a593Smuzhiyun { SN_COORD, -4460, 5166 },
353*4882a593Smuzhiyun { SN_COORD, -75, 6700 },
354*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
355*4882a593Smuzhiyun },
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI,
358*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING4_ISO,
359*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
360*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
361*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
362*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
363*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
364*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
365*4882a593Smuzhiyun { SN_COORD, -4620, 5140 },
366*4882a593Smuzhiyun { SN_COORD, -150, 6600 },
367*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
368*4882a593Smuzhiyun },
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI,
371*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO,
372*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
373*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
374*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
375*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
376*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
377*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
378*4882a593Smuzhiyun { SN_COORD, -4616, 5112 },
379*4882a593Smuzhiyun { SN_COORD, -142, 5234 },
380*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
381*4882a593Smuzhiyun },
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
384*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING5_ISO,
385*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
386*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
387*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
388*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
389*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
390*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
391*4882a593Smuzhiyun { SN_COORD, -4415, 5050 },
392*4882a593Smuzhiyun { SN_COORD, -55, 6680 },
393*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
394*4882a593Smuzhiyun },
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
397*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING6_ISO,
398*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
399*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
400*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
401*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
402*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
403*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
404*4882a593Smuzhiyun { SN_COORD, -4620, 5140 },
405*4882a593Smuzhiyun { SN_COORD, -150, 6600 },
406*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
407*4882a593Smuzhiyun },
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
410*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO,
411*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
412*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
413*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
414*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
415*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
416*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
417*4882a593Smuzhiyun { SN_COORD, -4750, 5280 },
418*4882a593Smuzhiyun { SN_COORD, -150, 6730 },
419*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
420*4882a593Smuzhiyun },
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI,
423*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO,
424*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
425*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
426*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
427*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
428*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
429*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
430*4882a593Smuzhiyun { SN_COORD, -4620, 5140 },
431*4882a593Smuzhiyun { SN_COORD, -150, 6600 },
432*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
433*4882a593Smuzhiyun },
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
436*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING7_ISO,
437*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
438*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
439*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
440*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
441*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
442*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
443*4882a593Smuzhiyun { SN_COORD, -4750, 5280 },
444*4882a593Smuzhiyun { SN_COORD, -150, 6730 },
445*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
446*4882a593Smuzhiyun },
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI,
449*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO,
450*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
451*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
452*4882a593Smuzhiyun 0x84, sizeof(struct bt_data),
453*4882a593Smuzhiyun 0x81, DATAFORMAT(TYPE2),
454*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
455*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
456*4882a593Smuzhiyun { SN_COORD, -4750, 5280 },
457*4882a593Smuzhiyun { SN_COORD, -150, 6730 },
458*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
459*4882a593Smuzhiyun },
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI,
462*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING8_ISO,
463*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
464*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
465*4882a593Smuzhiyun 0, sizeof(struct bt_data),
466*4882a593Smuzhiyun 0x83, DATAFORMAT(TYPE3),
467*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
468*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
469*4882a593Smuzhiyun { SN_COORD, -4620, 5140 },
470*4882a593Smuzhiyun { SN_COORD, -150, 6600 },
471*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
472*4882a593Smuzhiyun },
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI,
475*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING9_ISO,
476*4882a593Smuzhiyun USB_DEVICE_ID_APPLE_WELLSPRING9_JIS,
477*4882a593Smuzhiyun HAS_INTEGRATED_BUTTON,
478*4882a593Smuzhiyun 0, sizeof(struct bt_data),
479*4882a593Smuzhiyun 0x83, DATAFORMAT(TYPE4),
480*4882a593Smuzhiyun { SN_PRESSURE, 0, 300 },
481*4882a593Smuzhiyun { SN_WIDTH, 0, 2048 },
482*4882a593Smuzhiyun { SN_COORD, -4828, 5345 },
483*4882a593Smuzhiyun { SN_COORD, -203, 6803 },
484*4882a593Smuzhiyun { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
485*4882a593Smuzhiyun },
486*4882a593Smuzhiyun {}
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* return the device-specific configuration by device */
bcm5974_get_config(struct usb_device * udev)490*4882a593Smuzhiyun static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun u16 id = le16_to_cpu(udev->descriptor.idProduct);
493*4882a593Smuzhiyun const struct bcm5974_config *cfg;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun for (cfg = bcm5974_config_table; cfg->ansi; ++cfg)
496*4882a593Smuzhiyun if (cfg->ansi == id || cfg->iso == id || cfg->jis == id)
497*4882a593Smuzhiyun return cfg;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return bcm5974_config_table;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* convert 16-bit little endian to signed integer */
raw2int(__le16 x)503*4882a593Smuzhiyun static inline int raw2int(__le16 x)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun return (signed short)le16_to_cpu(x);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
set_abs(struct input_dev * input,unsigned int code,const struct bcm5974_param * p)508*4882a593Smuzhiyun static void set_abs(struct input_dev *input, unsigned int code,
509*4882a593Smuzhiyun const struct bcm5974_param *p)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun int fuzz = p->snratio ? (p->max - p->min) / p->snratio : 0;
512*4882a593Smuzhiyun input_set_abs_params(input, code, p->min, p->max, fuzz, 0);
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /* setup which logical events to report */
setup_events_to_report(struct input_dev * input_dev,const struct bcm5974_config * cfg)516*4882a593Smuzhiyun static void setup_events_to_report(struct input_dev *input_dev,
517*4882a593Smuzhiyun const struct bcm5974_config *cfg)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun __set_bit(EV_ABS, input_dev->evbit);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /* for synaptics only */
522*4882a593Smuzhiyun input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 5, 0);
523*4882a593Smuzhiyun input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 16, 0, 0);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun /* finger touch area */
526*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w);
527*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w);
528*4882a593Smuzhiyun /* finger approach area */
529*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
530*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
531*4882a593Smuzhiyun /* finger orientation */
532*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o);
533*4882a593Smuzhiyun /* finger position */
534*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_POSITION_X, &cfg->x);
535*4882a593Smuzhiyun set_abs(input_dev, ABS_MT_POSITION_Y, &cfg->y);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun __set_bit(EV_KEY, input_dev->evbit);
538*4882a593Smuzhiyun __set_bit(BTN_LEFT, input_dev->keybit);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (cfg->caps & HAS_INTEGRATED_BUTTON)
541*4882a593Smuzhiyun __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun input_mt_init_slots(input_dev, MAX_FINGERS,
544*4882a593Smuzhiyun INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun /* report button data as logical button state */
report_bt_state(struct bcm5974 * dev,int size)548*4882a593Smuzhiyun static int report_bt_state(struct bcm5974 *dev, int size)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun if (size != sizeof(struct bt_data))
551*4882a593Smuzhiyun return -EIO;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun dprintk(7,
554*4882a593Smuzhiyun "bcm5974: button data: %x %x %x %x\n",
555*4882a593Smuzhiyun dev->bt_data->unknown1, dev->bt_data->button,
556*4882a593Smuzhiyun dev->bt_data->rel_x, dev->bt_data->rel_y);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun input_report_key(dev->input, BTN_LEFT, dev->bt_data->button);
559*4882a593Smuzhiyun input_sync(dev->input);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun return 0;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
report_finger_data(struct input_dev * input,int slot,const struct input_mt_pos * pos,const struct tp_finger * f)564*4882a593Smuzhiyun static void report_finger_data(struct input_dev *input, int slot,
565*4882a593Smuzhiyun const struct input_mt_pos *pos,
566*4882a593Smuzhiyun const struct tp_finger *f)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun input_mt_slot(input, slot);
569*4882a593Smuzhiyun input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun input_report_abs(input, ABS_MT_TOUCH_MAJOR,
572*4882a593Smuzhiyun raw2int(f->touch_major) << 1);
573*4882a593Smuzhiyun input_report_abs(input, ABS_MT_TOUCH_MINOR,
574*4882a593Smuzhiyun raw2int(f->touch_minor) << 1);
575*4882a593Smuzhiyun input_report_abs(input, ABS_MT_WIDTH_MAJOR,
576*4882a593Smuzhiyun raw2int(f->tool_major) << 1);
577*4882a593Smuzhiyun input_report_abs(input, ABS_MT_WIDTH_MINOR,
578*4882a593Smuzhiyun raw2int(f->tool_minor) << 1);
579*4882a593Smuzhiyun input_report_abs(input, ABS_MT_ORIENTATION,
580*4882a593Smuzhiyun MAX_FINGER_ORIENTATION - raw2int(f->orientation));
581*4882a593Smuzhiyun input_report_abs(input, ABS_MT_POSITION_X, pos->x);
582*4882a593Smuzhiyun input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
report_synaptics_data(struct input_dev * input,const struct bcm5974_config * cfg,const struct tp_finger * f,int raw_n)585*4882a593Smuzhiyun static void report_synaptics_data(struct input_dev *input,
586*4882a593Smuzhiyun const struct bcm5974_config *cfg,
587*4882a593Smuzhiyun const struct tp_finger *f, int raw_n)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun int abs_p = 0, abs_w = 0;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun if (raw_n) {
592*4882a593Smuzhiyun int p = raw2int(f->touch_major);
593*4882a593Smuzhiyun int w = raw2int(f->tool_major);
594*4882a593Smuzhiyun if (p > 0 && raw2int(f->origin)) {
595*4882a593Smuzhiyun abs_p = clamp_val(256 * p / cfg->p.max, 0, 255);
596*4882a593Smuzhiyun abs_w = clamp_val(16 * w / cfg->w.max, 0, 15);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun input_report_abs(input, ABS_PRESSURE, abs_p);
601*4882a593Smuzhiyun input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /* report trackpad data as logical trackpad state */
report_tp_state(struct bcm5974 * dev,int size)605*4882a593Smuzhiyun static int report_tp_state(struct bcm5974 *dev, int size)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun const struct bcm5974_config *c = &dev->cfg;
608*4882a593Smuzhiyun const struct tp_finger *f;
609*4882a593Smuzhiyun struct input_dev *input = dev->input;
610*4882a593Smuzhiyun int raw_n, i, n = 0;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun if (size < c->tp_header || (size - c->tp_header) % c->tp_fsize != 0)
613*4882a593Smuzhiyun return -EIO;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun raw_n = (size - c->tp_header) / c->tp_fsize;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun for (i = 0; i < raw_n; i++) {
618*4882a593Smuzhiyun f = get_tp_finger(dev, i);
619*4882a593Smuzhiyun if (raw2int(f->touch_major) == 0)
620*4882a593Smuzhiyun continue;
621*4882a593Smuzhiyun dev->pos[n].x = raw2int(f->abs_x);
622*4882a593Smuzhiyun dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
623*4882a593Smuzhiyun dev->index[n++] = f;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun for (i = 0; i < n; i++)
629*4882a593Smuzhiyun report_finger_data(input, dev->slots[i],
630*4882a593Smuzhiyun &dev->pos[i], dev->index[i]);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun input_mt_sync_frame(input);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun /* later types report button events via integrated button only */
637*4882a593Smuzhiyun if (c->caps & HAS_INTEGRATED_BUTTON) {
638*4882a593Smuzhiyun int ibt = raw2int(dev->tp_data[c->tp_button]);
639*4882a593Smuzhiyun input_report_key(input, BTN_LEFT, ibt);
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun input_sync(input);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
bcm5974_wellspring_mode(struct bcm5974 * dev,bool on)647*4882a593Smuzhiyun static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun const struct bcm5974_config *c = &dev->cfg;
650*4882a593Smuzhiyun int retval = 0, size;
651*4882a593Smuzhiyun char *data;
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun /* Type 3 does not require a mode switch */
654*4882a593Smuzhiyun if (c->tp_type == TYPE3)
655*4882a593Smuzhiyun return 0;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun data = kmalloc(c->um_size, GFP_KERNEL);
658*4882a593Smuzhiyun if (!data) {
659*4882a593Smuzhiyun dev_err(&dev->intf->dev, "out of memory\n");
660*4882a593Smuzhiyun retval = -ENOMEM;
661*4882a593Smuzhiyun goto out;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun /* read configuration */
665*4882a593Smuzhiyun size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
666*4882a593Smuzhiyun BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
667*4882a593Smuzhiyun USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
668*4882a593Smuzhiyun c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (size != c->um_size) {
671*4882a593Smuzhiyun dev_err(&dev->intf->dev, "could not read from device\n");
672*4882a593Smuzhiyun retval = -EIO;
673*4882a593Smuzhiyun goto out;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun /* apply the mode switch */
677*4882a593Smuzhiyun data[c->um_switch_idx] = on ? c->um_switch_on : c->um_switch_off;
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun /* write configuration */
680*4882a593Smuzhiyun size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
681*4882a593Smuzhiyun BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
682*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
683*4882a593Smuzhiyun c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun if (size != c->um_size) {
686*4882a593Smuzhiyun dev_err(&dev->intf->dev, "could not write to device\n");
687*4882a593Smuzhiyun retval = -EIO;
688*4882a593Smuzhiyun goto out;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun dprintk(2, "bcm5974: switched to %s mode.\n",
692*4882a593Smuzhiyun on ? "wellspring" : "normal");
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun out:
695*4882a593Smuzhiyun kfree(data);
696*4882a593Smuzhiyun return retval;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
bcm5974_irq_button(struct urb * urb)699*4882a593Smuzhiyun static void bcm5974_irq_button(struct urb *urb)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun struct bcm5974 *dev = urb->context;
702*4882a593Smuzhiyun struct usb_interface *intf = dev->intf;
703*4882a593Smuzhiyun int error;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun switch (urb->status) {
706*4882a593Smuzhiyun case 0:
707*4882a593Smuzhiyun break;
708*4882a593Smuzhiyun case -EOVERFLOW:
709*4882a593Smuzhiyun case -ECONNRESET:
710*4882a593Smuzhiyun case -ENOENT:
711*4882a593Smuzhiyun case -ESHUTDOWN:
712*4882a593Smuzhiyun dev_dbg(&intf->dev, "button urb shutting down: %d\n",
713*4882a593Smuzhiyun urb->status);
714*4882a593Smuzhiyun return;
715*4882a593Smuzhiyun default:
716*4882a593Smuzhiyun dev_dbg(&intf->dev, "button urb status: %d\n", urb->status);
717*4882a593Smuzhiyun goto exit;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun if (report_bt_state(dev, dev->bt_urb->actual_length))
721*4882a593Smuzhiyun dprintk(1, "bcm5974: bad button package, length: %d\n",
722*4882a593Smuzhiyun dev->bt_urb->actual_length);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun exit:
725*4882a593Smuzhiyun error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
726*4882a593Smuzhiyun if (error)
727*4882a593Smuzhiyun dev_err(&intf->dev, "button urb failed: %d\n", error);
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
bcm5974_irq_trackpad(struct urb * urb)730*4882a593Smuzhiyun static void bcm5974_irq_trackpad(struct urb *urb)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun struct bcm5974 *dev = urb->context;
733*4882a593Smuzhiyun struct usb_interface *intf = dev->intf;
734*4882a593Smuzhiyun int error;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun switch (urb->status) {
737*4882a593Smuzhiyun case 0:
738*4882a593Smuzhiyun break;
739*4882a593Smuzhiyun case -EOVERFLOW:
740*4882a593Smuzhiyun case -ECONNRESET:
741*4882a593Smuzhiyun case -ENOENT:
742*4882a593Smuzhiyun case -ESHUTDOWN:
743*4882a593Smuzhiyun dev_dbg(&intf->dev, "trackpad urb shutting down: %d\n",
744*4882a593Smuzhiyun urb->status);
745*4882a593Smuzhiyun return;
746*4882a593Smuzhiyun default:
747*4882a593Smuzhiyun dev_dbg(&intf->dev, "trackpad urb status: %d\n", urb->status);
748*4882a593Smuzhiyun goto exit;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun /* control response ignored */
752*4882a593Smuzhiyun if (dev->tp_urb->actual_length == 2)
753*4882a593Smuzhiyun goto exit;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun if (report_tp_state(dev, dev->tp_urb->actual_length))
756*4882a593Smuzhiyun dprintk(1, "bcm5974: bad trackpad package, length: %d\n",
757*4882a593Smuzhiyun dev->tp_urb->actual_length);
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun exit:
760*4882a593Smuzhiyun error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
761*4882a593Smuzhiyun if (error)
762*4882a593Smuzhiyun dev_err(&intf->dev, "trackpad urb failed: %d\n", error);
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun /*
766*4882a593Smuzhiyun * The Wellspring trackpad, like many recent Apple trackpads, share
767*4882a593Smuzhiyun * the usb device with the keyboard. Since keyboards are usually
768*4882a593Smuzhiyun * handled by the HID system, the device ends up being handled by two
769*4882a593Smuzhiyun * modules. Setting up the device therefore becomes slightly
770*4882a593Smuzhiyun * complicated. To enable multitouch features, a mode switch is
771*4882a593Smuzhiyun * required, which is usually applied via the control interface of the
772*4882a593Smuzhiyun * device. It can be argued where this switch should take place. In
773*4882a593Smuzhiyun * some drivers, like appletouch, the switch is made during
774*4882a593Smuzhiyun * probe. However, the hid module may also alter the state of the
775*4882a593Smuzhiyun * device, resulting in trackpad malfunction under certain
776*4882a593Smuzhiyun * circumstances. To get around this problem, there is at least one
777*4882a593Smuzhiyun * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to
778*4882a593Smuzhiyun * receive a reset_resume request rather than the normal resume.
779*4882a593Smuzhiyun * Since the implementation of reset_resume is equal to mode switch
780*4882a593Smuzhiyun * plus start_traffic, it seems easier to always do the switch when
781*4882a593Smuzhiyun * starting traffic on the device.
782*4882a593Smuzhiyun */
bcm5974_start_traffic(struct bcm5974 * dev)783*4882a593Smuzhiyun static int bcm5974_start_traffic(struct bcm5974 *dev)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun int error;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun error = bcm5974_wellspring_mode(dev, true);
788*4882a593Smuzhiyun if (error) {
789*4882a593Smuzhiyun dprintk(1, "bcm5974: mode switch failed\n");
790*4882a593Smuzhiyun goto err_out;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun if (dev->bt_urb) {
794*4882a593Smuzhiyun error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
795*4882a593Smuzhiyun if (error)
796*4882a593Smuzhiyun goto err_reset_mode;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
800*4882a593Smuzhiyun if (error)
801*4882a593Smuzhiyun goto err_kill_bt;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun return 0;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun err_kill_bt:
806*4882a593Smuzhiyun usb_kill_urb(dev->bt_urb);
807*4882a593Smuzhiyun err_reset_mode:
808*4882a593Smuzhiyun bcm5974_wellspring_mode(dev, false);
809*4882a593Smuzhiyun err_out:
810*4882a593Smuzhiyun return error;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
bcm5974_pause_traffic(struct bcm5974 * dev)813*4882a593Smuzhiyun static void bcm5974_pause_traffic(struct bcm5974 *dev)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun usb_kill_urb(dev->tp_urb);
816*4882a593Smuzhiyun usb_kill_urb(dev->bt_urb);
817*4882a593Smuzhiyun bcm5974_wellspring_mode(dev, false);
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun /*
821*4882a593Smuzhiyun * The code below implements open/close and manual suspend/resume.
822*4882a593Smuzhiyun * All functions may be called in random order.
823*4882a593Smuzhiyun *
824*4882a593Smuzhiyun * Opening a suspended device fails with EACCES - permission denied.
825*4882a593Smuzhiyun *
826*4882a593Smuzhiyun * Failing a resume leaves the device resumed but closed.
827*4882a593Smuzhiyun */
bcm5974_open(struct input_dev * input)828*4882a593Smuzhiyun static int bcm5974_open(struct input_dev *input)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun struct bcm5974 *dev = input_get_drvdata(input);
831*4882a593Smuzhiyun int error;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun error = usb_autopm_get_interface(dev->intf);
834*4882a593Smuzhiyun if (error)
835*4882a593Smuzhiyun return error;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun mutex_lock(&dev->pm_mutex);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun error = bcm5974_start_traffic(dev);
840*4882a593Smuzhiyun if (!error)
841*4882a593Smuzhiyun dev->opened = 1;
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun mutex_unlock(&dev->pm_mutex);
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun if (error)
846*4882a593Smuzhiyun usb_autopm_put_interface(dev->intf);
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun return error;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
bcm5974_close(struct input_dev * input)851*4882a593Smuzhiyun static void bcm5974_close(struct input_dev *input)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun struct bcm5974 *dev = input_get_drvdata(input);
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun mutex_lock(&dev->pm_mutex);
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun bcm5974_pause_traffic(dev);
858*4882a593Smuzhiyun dev->opened = 0;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun mutex_unlock(&dev->pm_mutex);
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun usb_autopm_put_interface(dev->intf);
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun
bcm5974_suspend(struct usb_interface * iface,pm_message_t message)865*4882a593Smuzhiyun static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun struct bcm5974 *dev = usb_get_intfdata(iface);
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun mutex_lock(&dev->pm_mutex);
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun if (dev->opened)
872*4882a593Smuzhiyun bcm5974_pause_traffic(dev);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun mutex_unlock(&dev->pm_mutex);
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun return 0;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
bcm5974_resume(struct usb_interface * iface)879*4882a593Smuzhiyun static int bcm5974_resume(struct usb_interface *iface)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun struct bcm5974 *dev = usb_get_intfdata(iface);
882*4882a593Smuzhiyun int error = 0;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun mutex_lock(&dev->pm_mutex);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun if (dev->opened)
887*4882a593Smuzhiyun error = bcm5974_start_traffic(dev);
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun mutex_unlock(&dev->pm_mutex);
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun return error;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
bcm5974_probe(struct usb_interface * iface,const struct usb_device_id * id)894*4882a593Smuzhiyun static int bcm5974_probe(struct usb_interface *iface,
895*4882a593Smuzhiyun const struct usb_device_id *id)
896*4882a593Smuzhiyun {
897*4882a593Smuzhiyun struct usb_device *udev = interface_to_usbdev(iface);
898*4882a593Smuzhiyun const struct bcm5974_config *cfg;
899*4882a593Smuzhiyun struct bcm5974 *dev;
900*4882a593Smuzhiyun struct input_dev *input_dev;
901*4882a593Smuzhiyun int error = -ENOMEM;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /* find the product index */
904*4882a593Smuzhiyun cfg = bcm5974_get_config(udev);
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun /* allocate memory for our device state and initialize it */
907*4882a593Smuzhiyun dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
908*4882a593Smuzhiyun input_dev = input_allocate_device();
909*4882a593Smuzhiyun if (!dev || !input_dev) {
910*4882a593Smuzhiyun dev_err(&iface->dev, "out of memory\n");
911*4882a593Smuzhiyun goto err_free_devs;
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun dev->udev = udev;
915*4882a593Smuzhiyun dev->intf = iface;
916*4882a593Smuzhiyun dev->input = input_dev;
917*4882a593Smuzhiyun dev->cfg = *cfg;
918*4882a593Smuzhiyun mutex_init(&dev->pm_mutex);
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun /* setup urbs */
921*4882a593Smuzhiyun if (cfg->tp_type == TYPE1) {
922*4882a593Smuzhiyun dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
923*4882a593Smuzhiyun if (!dev->bt_urb)
924*4882a593Smuzhiyun goto err_free_devs;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
928*4882a593Smuzhiyun if (!dev->tp_urb)
929*4882a593Smuzhiyun goto err_free_bt_urb;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun if (dev->bt_urb) {
932*4882a593Smuzhiyun dev->bt_data = usb_alloc_coherent(dev->udev,
933*4882a593Smuzhiyun dev->cfg.bt_datalen, GFP_KERNEL,
934*4882a593Smuzhiyun &dev->bt_urb->transfer_dma);
935*4882a593Smuzhiyun if (!dev->bt_data)
936*4882a593Smuzhiyun goto err_free_urb;
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun dev->tp_data = usb_alloc_coherent(dev->udev,
940*4882a593Smuzhiyun dev->cfg.tp_datalen, GFP_KERNEL,
941*4882a593Smuzhiyun &dev->tp_urb->transfer_dma);
942*4882a593Smuzhiyun if (!dev->tp_data)
943*4882a593Smuzhiyun goto err_free_bt_buffer;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun if (dev->bt_urb) {
946*4882a593Smuzhiyun usb_fill_int_urb(dev->bt_urb, udev,
947*4882a593Smuzhiyun usb_rcvintpipe(udev, cfg->bt_ep),
948*4882a593Smuzhiyun dev->bt_data, dev->cfg.bt_datalen,
949*4882a593Smuzhiyun bcm5974_irq_button, dev, 1);
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun dev->bt_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun usb_fill_int_urb(dev->tp_urb, udev,
955*4882a593Smuzhiyun usb_rcvintpipe(udev, cfg->tp_ep),
956*4882a593Smuzhiyun dev->tp_data, dev->cfg.tp_datalen,
957*4882a593Smuzhiyun bcm5974_irq_trackpad, dev, 1);
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun dev->tp_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun /* create bcm5974 device */
962*4882a593Smuzhiyun usb_make_path(udev, dev->phys, sizeof(dev->phys));
963*4882a593Smuzhiyun strlcat(dev->phys, "/input0", sizeof(dev->phys));
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun input_dev->name = "bcm5974";
966*4882a593Smuzhiyun input_dev->phys = dev->phys;
967*4882a593Smuzhiyun usb_to_input_id(dev->udev, &input_dev->id);
968*4882a593Smuzhiyun /* report driver capabilities via the version field */
969*4882a593Smuzhiyun input_dev->id.version = cfg->caps;
970*4882a593Smuzhiyun input_dev->dev.parent = &iface->dev;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun input_set_drvdata(input_dev, dev);
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun input_dev->open = bcm5974_open;
975*4882a593Smuzhiyun input_dev->close = bcm5974_close;
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun setup_events_to_report(input_dev, cfg);
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun error = input_register_device(dev->input);
980*4882a593Smuzhiyun if (error)
981*4882a593Smuzhiyun goto err_free_buffer;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun /* save our data pointer in this interface device */
984*4882a593Smuzhiyun usb_set_intfdata(iface, dev);
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun return 0;
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun err_free_buffer:
989*4882a593Smuzhiyun usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
990*4882a593Smuzhiyun dev->tp_data, dev->tp_urb->transfer_dma);
991*4882a593Smuzhiyun err_free_bt_buffer:
992*4882a593Smuzhiyun if (dev->bt_urb)
993*4882a593Smuzhiyun usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
994*4882a593Smuzhiyun dev->bt_data, dev->bt_urb->transfer_dma);
995*4882a593Smuzhiyun err_free_urb:
996*4882a593Smuzhiyun usb_free_urb(dev->tp_urb);
997*4882a593Smuzhiyun err_free_bt_urb:
998*4882a593Smuzhiyun usb_free_urb(dev->bt_urb);
999*4882a593Smuzhiyun err_free_devs:
1000*4882a593Smuzhiyun usb_set_intfdata(iface, NULL);
1001*4882a593Smuzhiyun input_free_device(input_dev);
1002*4882a593Smuzhiyun kfree(dev);
1003*4882a593Smuzhiyun return error;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
bcm5974_disconnect(struct usb_interface * iface)1006*4882a593Smuzhiyun static void bcm5974_disconnect(struct usb_interface *iface)
1007*4882a593Smuzhiyun {
1008*4882a593Smuzhiyun struct bcm5974 *dev = usb_get_intfdata(iface);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun usb_set_intfdata(iface, NULL);
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun input_unregister_device(dev->input);
1013*4882a593Smuzhiyun usb_free_coherent(dev->udev, dev->cfg.tp_datalen,
1014*4882a593Smuzhiyun dev->tp_data, dev->tp_urb->transfer_dma);
1015*4882a593Smuzhiyun if (dev->bt_urb)
1016*4882a593Smuzhiyun usb_free_coherent(dev->udev, dev->cfg.bt_datalen,
1017*4882a593Smuzhiyun dev->bt_data, dev->bt_urb->transfer_dma);
1018*4882a593Smuzhiyun usb_free_urb(dev->tp_urb);
1019*4882a593Smuzhiyun usb_free_urb(dev->bt_urb);
1020*4882a593Smuzhiyun kfree(dev);
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun static struct usb_driver bcm5974_driver = {
1024*4882a593Smuzhiyun .name = "bcm5974",
1025*4882a593Smuzhiyun .probe = bcm5974_probe,
1026*4882a593Smuzhiyun .disconnect = bcm5974_disconnect,
1027*4882a593Smuzhiyun .suspend = bcm5974_suspend,
1028*4882a593Smuzhiyun .resume = bcm5974_resume,
1029*4882a593Smuzhiyun .id_table = bcm5974_table,
1030*4882a593Smuzhiyun .supports_autosuspend = 1,
1031*4882a593Smuzhiyun };
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun module_usb_driver(bcm5974_driver);
1034