xref: /OK3568_Linux_fs/kernel/drivers/input/mouse/bcm5974.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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