xref: /linux/drivers/input/mouse/bcm5974.c (revision f89bd95c5c946776f116ffeb997653d4193d6a35)
1*f89bd95cSHenrik Rydberg /*
2*f89bd95cSHenrik Rydberg  * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
3*f89bd95cSHenrik Rydberg  *
4*f89bd95cSHenrik Rydberg  * Copyright (C) 2008	   Henrik Rydberg (rydberg@euromail.se)
5*f89bd95cSHenrik Rydberg  *
6*f89bd95cSHenrik Rydberg  * The USB initialization and package decoding was made by
7*f89bd95cSHenrik Rydberg  * Scott Shawcroft as part of the touchd user-space driver project:
8*f89bd95cSHenrik Rydberg  * Copyright (C) 2008	   Scott Shawcroft (scott.shawcroft@gmail.com)
9*f89bd95cSHenrik Rydberg  *
10*f89bd95cSHenrik Rydberg  * The BCM5974 driver is based on the appletouch driver:
11*f89bd95cSHenrik Rydberg  * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
12*f89bd95cSHenrik Rydberg  * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
13*f89bd95cSHenrik Rydberg  * Copyright (C) 2005	   Stelian Pop (stelian@popies.net)
14*f89bd95cSHenrik Rydberg  * Copyright (C) 2005	   Frank Arnold (frank@scirocco-5v-turbo.de)
15*f89bd95cSHenrik Rydberg  * Copyright (C) 2005	   Peter Osterlund (petero2@telia.com)
16*f89bd95cSHenrik Rydberg  * Copyright (C) 2005	   Michael Hanselmann (linux-kernel@hansmi.ch)
17*f89bd95cSHenrik Rydberg  * Copyright (C) 2006	   Nicolas Boichat (nicolas@boichat.ch)
18*f89bd95cSHenrik Rydberg  *
19*f89bd95cSHenrik Rydberg  * This program is free software; you can redistribute it and/or modify
20*f89bd95cSHenrik Rydberg  * it under the terms of the GNU General Public License as published by
21*f89bd95cSHenrik Rydberg  * the Free Software Foundation; either version 2 of the License, or
22*f89bd95cSHenrik Rydberg  * (at your option) any later version.
23*f89bd95cSHenrik Rydberg  *
24*f89bd95cSHenrik Rydberg  * This program is distributed in the hope that it will be useful,
25*f89bd95cSHenrik Rydberg  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26*f89bd95cSHenrik Rydberg  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
27*f89bd95cSHenrik Rydberg  * GNU General Public License for more details.
28*f89bd95cSHenrik Rydberg  *
29*f89bd95cSHenrik Rydberg  * You should have received a copy of the GNU General Public License
30*f89bd95cSHenrik Rydberg  * along with this program; if not, write to the Free Software
31*f89bd95cSHenrik Rydberg  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32*f89bd95cSHenrik Rydberg  *
33*f89bd95cSHenrik Rydberg  */
34*f89bd95cSHenrik Rydberg 
35*f89bd95cSHenrik Rydberg #include <linux/kernel.h>
36*f89bd95cSHenrik Rydberg #include <linux/errno.h>
37*f89bd95cSHenrik Rydberg #include <linux/init.h>
38*f89bd95cSHenrik Rydberg #include <linux/slab.h>
39*f89bd95cSHenrik Rydberg #include <linux/module.h>
40*f89bd95cSHenrik Rydberg #include <linux/usb/input.h>
41*f89bd95cSHenrik Rydberg #include <linux/hid.h>
42*f89bd95cSHenrik Rydberg #include <linux/mutex.h>
43*f89bd95cSHenrik Rydberg 
44*f89bd95cSHenrik Rydberg #define USB_VENDOR_ID_APPLE		0x05ac
45*f89bd95cSHenrik Rydberg 
46*f89bd95cSHenrik Rydberg /* MacbookAir, aka wellspring */
47*f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI	0x0223
48*f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO	0x0224
49*f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS	0x0225
50*f89bd95cSHenrik Rydberg /* MacbookProPenryn, aka wellspring2 */
51*f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI	0x0230
52*f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO	0x0231
53*f89bd95cSHenrik Rydberg #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS	0x0232
54*f89bd95cSHenrik Rydberg 
55*f89bd95cSHenrik Rydberg #define BCM5974_DEVICE(prod) {					\
56*f89bd95cSHenrik Rydberg 	.match_flags = (USB_DEVICE_ID_MATCH_DEVICE |		\
57*f89bd95cSHenrik Rydberg 			USB_DEVICE_ID_MATCH_INT_CLASS |		\
58*f89bd95cSHenrik Rydberg 			USB_DEVICE_ID_MATCH_INT_PROTOCOL),	\
59*f89bd95cSHenrik Rydberg 	.idVendor = USB_VENDOR_ID_APPLE,			\
60*f89bd95cSHenrik Rydberg 	.idProduct = (prod),					\
61*f89bd95cSHenrik Rydberg 	.bInterfaceClass = USB_INTERFACE_CLASS_HID,		\
62*f89bd95cSHenrik Rydberg 	.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE	\
63*f89bd95cSHenrik Rydberg }
64*f89bd95cSHenrik Rydberg 
65*f89bd95cSHenrik Rydberg /* table of devices that work with this driver */
66*f89bd95cSHenrik Rydberg static const struct usb_device_id bcm5974_table [] = {
67*f89bd95cSHenrik Rydberg 	/* MacbookAir1.1 */
68*f89bd95cSHenrik Rydberg 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
69*f89bd95cSHenrik Rydberg 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
70*f89bd95cSHenrik Rydberg 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
71*f89bd95cSHenrik Rydberg 	/* MacbookProPenryn */
72*f89bd95cSHenrik Rydberg 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
73*f89bd95cSHenrik Rydberg 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
74*f89bd95cSHenrik Rydberg 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
75*f89bd95cSHenrik Rydberg 	/* Terminating entry */
76*f89bd95cSHenrik Rydberg 	{}
77*f89bd95cSHenrik Rydberg };
78*f89bd95cSHenrik Rydberg MODULE_DEVICE_TABLE(usb, bcm5974_table);
79*f89bd95cSHenrik Rydberg 
80*f89bd95cSHenrik Rydberg MODULE_AUTHOR("Henrik Rydberg");
81*f89bd95cSHenrik Rydberg MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver");
82*f89bd95cSHenrik Rydberg MODULE_LICENSE("GPL");
83*f89bd95cSHenrik Rydberg 
84*f89bd95cSHenrik Rydberg #define dprintk(level, format, a...)\
85*f89bd95cSHenrik Rydberg 	{ if (debug >= level) printk(KERN_DEBUG format, ##a); }
86*f89bd95cSHenrik Rydberg 
87*f89bd95cSHenrik Rydberg static int debug = 1;
88*f89bd95cSHenrik Rydberg module_param(debug, int, 0644);
89*f89bd95cSHenrik Rydberg MODULE_PARM_DESC(debug, "Activate debugging output");
90*f89bd95cSHenrik Rydberg 
91*f89bd95cSHenrik Rydberg /* button data structure */
92*f89bd95cSHenrik Rydberg struct bt_data {
93*f89bd95cSHenrik Rydberg 	u8 unknown1;		/* constant */
94*f89bd95cSHenrik Rydberg 	u8 button;		/* left button */
95*f89bd95cSHenrik Rydberg 	u8 rel_x;		/* relative x coordinate */
96*f89bd95cSHenrik Rydberg 	u8 rel_y;		/* relative y coordinate */
97*f89bd95cSHenrik Rydberg };
98*f89bd95cSHenrik Rydberg 
99*f89bd95cSHenrik Rydberg /* trackpad header structure */
100*f89bd95cSHenrik Rydberg struct tp_header {
101*f89bd95cSHenrik Rydberg 	u8 unknown1[16];	/* constants, timers, etc */
102*f89bd95cSHenrik Rydberg 	u8 fingers;		/* number of fingers on trackpad */
103*f89bd95cSHenrik Rydberg 	u8 unknown2[9];		/* constants, timers, etc */
104*f89bd95cSHenrik Rydberg };
105*f89bd95cSHenrik Rydberg 
106*f89bd95cSHenrik Rydberg /* trackpad finger structure */
107*f89bd95cSHenrik Rydberg struct tp_finger {
108*f89bd95cSHenrik Rydberg 	__le16 origin;		/* left/right origin? */
109*f89bd95cSHenrik Rydberg 	__le16 abs_x;		/* absolute x coodinate */
110*f89bd95cSHenrik Rydberg 	__le16 abs_y;		/* absolute y coodinate */
111*f89bd95cSHenrik Rydberg 	__le16 rel_x;		/* relative x coodinate */
112*f89bd95cSHenrik Rydberg 	__le16 rel_y;		/* relative y coodinate */
113*f89bd95cSHenrik Rydberg 	__le16 size_major;	/* finger size, major axis? */
114*f89bd95cSHenrik Rydberg 	__le16 size_minor;	/* finger size, minor axis? */
115*f89bd95cSHenrik Rydberg 	__le16 orientation;	/* 16384 when point, else 15 bit angle */
116*f89bd95cSHenrik Rydberg 	__le16 force_major;	/* trackpad force, major axis? */
117*f89bd95cSHenrik Rydberg 	__le16 force_minor;	/* trackpad force, minor axis? */
118*f89bd95cSHenrik Rydberg 	__le16 unused[3];	/* zeros */
119*f89bd95cSHenrik Rydberg 	__le16 multi;		/* one finger: varies, more fingers: constant */
120*f89bd95cSHenrik Rydberg };
121*f89bd95cSHenrik Rydberg 
122*f89bd95cSHenrik Rydberg /* trackpad data structure, empirically at least ten fingers */
123*f89bd95cSHenrik Rydberg struct tp_data {
124*f89bd95cSHenrik Rydberg 	struct tp_header header;
125*f89bd95cSHenrik Rydberg 	struct tp_finger finger[16];
126*f89bd95cSHenrik Rydberg };
127*f89bd95cSHenrik Rydberg 
128*f89bd95cSHenrik Rydberg /* device-specific parameters */
129*f89bd95cSHenrik Rydberg struct bcm5974_param {
130*f89bd95cSHenrik Rydberg 	int dim;		/* logical dimension */
131*f89bd95cSHenrik Rydberg 	int fuzz;		/* logical noise value */
132*f89bd95cSHenrik Rydberg 	int devmin;		/* device minimum reading */
133*f89bd95cSHenrik Rydberg 	int devmax;		/* device maximum reading */
134*f89bd95cSHenrik Rydberg };
135*f89bd95cSHenrik Rydberg 
136*f89bd95cSHenrik Rydberg /* device-specific configuration */
137*f89bd95cSHenrik Rydberg struct bcm5974_config {
138*f89bd95cSHenrik Rydberg 	int ansi, iso, jis;	/* the product id of this device */
139*f89bd95cSHenrik Rydberg 	int bt_ep;		/* the endpoint of the button interface */
140*f89bd95cSHenrik Rydberg 	int bt_datalen;		/* data length of the button interface */
141*f89bd95cSHenrik Rydberg 	int tp_ep;		/* the endpoint of the trackpad interface */
142*f89bd95cSHenrik Rydberg 	int tp_datalen;		/* data length of the trackpad interface */
143*f89bd95cSHenrik Rydberg 	struct bcm5974_param p;	/* finger pressure limits */
144*f89bd95cSHenrik Rydberg 	struct bcm5974_param w;	/* finger width limits */
145*f89bd95cSHenrik Rydberg 	struct bcm5974_param x;	/* horizontal limits */
146*f89bd95cSHenrik Rydberg 	struct bcm5974_param y;	/* vertical limits */
147*f89bd95cSHenrik Rydberg };
148*f89bd95cSHenrik Rydberg 
149*f89bd95cSHenrik Rydberg /* logical device structure */
150*f89bd95cSHenrik Rydberg struct bcm5974 {
151*f89bd95cSHenrik Rydberg 	char phys[64];
152*f89bd95cSHenrik Rydberg 	struct usb_device *udev;	/* usb device */
153*f89bd95cSHenrik Rydberg 	struct input_dev *input;	/* input dev */
154*f89bd95cSHenrik Rydberg 	struct bcm5974_config cfg;	/* device configuration */
155*f89bd95cSHenrik Rydberg 	struct mutex pm_mutex;		/* serialize access to open/suspend */
156*f89bd95cSHenrik Rydberg 	int opened;			/* 1: opened, 0: closed */
157*f89bd95cSHenrik Rydberg 	struct urb *bt_urb;		/* button usb request block */
158*f89bd95cSHenrik Rydberg 	struct bt_data *bt_data;	/* button transferred data */
159*f89bd95cSHenrik Rydberg 	struct urb *tp_urb;		/* trackpad usb request block */
160*f89bd95cSHenrik Rydberg 	struct tp_data *tp_data;	/* trackpad transferred data */
161*f89bd95cSHenrik Rydberg };
162*f89bd95cSHenrik Rydberg 
163*f89bd95cSHenrik Rydberg /* logical dimensions */
164*f89bd95cSHenrik Rydberg #define DIM_PRESSURE	256		/* maximum finger pressure */
165*f89bd95cSHenrik Rydberg #define DIM_WIDTH	16		/* maximum finger width */
166*f89bd95cSHenrik Rydberg #define DIM_X		1280		/* maximum trackpad x value */
167*f89bd95cSHenrik Rydberg #define DIM_Y		800		/* maximum trackpad y value */
168*f89bd95cSHenrik Rydberg 
169*f89bd95cSHenrik Rydberg /* logical signal quality */
170*f89bd95cSHenrik Rydberg #define SN_PRESSURE	45		/* pressure signal-to-noise ratio */
171*f89bd95cSHenrik Rydberg #define SN_WIDTH	100		/* width signal-to-noise ratio */
172*f89bd95cSHenrik Rydberg #define SN_COORD	250		/* coordinate signal-to-noise ratio */
173*f89bd95cSHenrik Rydberg 
174*f89bd95cSHenrik Rydberg /* device constants */
175*f89bd95cSHenrik Rydberg static const struct bcm5974_config bcm5974_config_table[] = {
176*f89bd95cSHenrik Rydberg 	{
177*f89bd95cSHenrik Rydberg 		USB_DEVICE_ID_APPLE_WELLSPRING_ANSI,
178*f89bd95cSHenrik Rydberg 		USB_DEVICE_ID_APPLE_WELLSPRING_ISO,
179*f89bd95cSHenrik Rydberg 		USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
180*f89bd95cSHenrik Rydberg 		0x84, sizeof(struct bt_data),
181*f89bd95cSHenrik Rydberg 		0x81, sizeof(struct tp_data),
182*f89bd95cSHenrik Rydberg 		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
183*f89bd95cSHenrik Rydberg 		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
184*f89bd95cSHenrik Rydberg 		{ DIM_X, DIM_X / SN_COORD, -4824, 5342 },
185*f89bd95cSHenrik Rydberg 		{ DIM_Y, DIM_Y / SN_COORD, -172, 5820 }
186*f89bd95cSHenrik Rydberg 	},
187*f89bd95cSHenrik Rydberg 	{
188*f89bd95cSHenrik Rydberg 		USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
189*f89bd95cSHenrik Rydberg 		USB_DEVICE_ID_APPLE_WELLSPRING2_ISO,
190*f89bd95cSHenrik Rydberg 		USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
191*f89bd95cSHenrik Rydberg 		0x84, sizeof(struct bt_data),
192*f89bd95cSHenrik Rydberg 		0x81, sizeof(struct tp_data),
193*f89bd95cSHenrik Rydberg 		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
194*f89bd95cSHenrik Rydberg 		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
195*f89bd95cSHenrik Rydberg 		{ DIM_X, DIM_X / SN_COORD, -4824, 4824 },
196*f89bd95cSHenrik Rydberg 		{ DIM_Y, DIM_Y / SN_COORD, -172, 4290 }
197*f89bd95cSHenrik Rydberg 	},
198*f89bd95cSHenrik Rydberg 	{}
199*f89bd95cSHenrik Rydberg };
200*f89bd95cSHenrik Rydberg 
201*f89bd95cSHenrik Rydberg /* return the device-specific configuration by device */
202*f89bd95cSHenrik Rydberg static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev)
203*f89bd95cSHenrik Rydberg {
204*f89bd95cSHenrik Rydberg 	u16 id = le16_to_cpu(udev->descriptor.idProduct);
205*f89bd95cSHenrik Rydberg 	const struct bcm5974_config *cfg;
206*f89bd95cSHenrik Rydberg 
207*f89bd95cSHenrik Rydberg 	for (cfg = bcm5974_config_table; cfg->ansi; ++cfg)
208*f89bd95cSHenrik Rydberg 		if (cfg->ansi == id || cfg->iso == id || cfg->jis == id)
209*f89bd95cSHenrik Rydberg 			return cfg;
210*f89bd95cSHenrik Rydberg 
211*f89bd95cSHenrik Rydberg 	return bcm5974_config_table;
212*f89bd95cSHenrik Rydberg }
213*f89bd95cSHenrik Rydberg 
214*f89bd95cSHenrik Rydberg /* convert 16-bit little endian to signed integer */
215*f89bd95cSHenrik Rydberg static inline int raw2int(__le16 x)
216*f89bd95cSHenrik Rydberg {
217*f89bd95cSHenrik Rydberg 	return (signed short)le16_to_cpu(x);
218*f89bd95cSHenrik Rydberg }
219*f89bd95cSHenrik Rydberg 
220*f89bd95cSHenrik Rydberg /* scale device data to logical dimensions (asserts devmin < devmax) */
221*f89bd95cSHenrik Rydberg static inline int int2scale(const struct bcm5974_param *p, int x)
222*f89bd95cSHenrik Rydberg {
223*f89bd95cSHenrik Rydberg 	return x * p->dim / (p->devmax - p->devmin);
224*f89bd95cSHenrik Rydberg }
225*f89bd95cSHenrik Rydberg 
226*f89bd95cSHenrik Rydberg /* all logical value ranges are [0,dim). */
227*f89bd95cSHenrik Rydberg static inline int int2bound(const struct bcm5974_param *p, int x)
228*f89bd95cSHenrik Rydberg {
229*f89bd95cSHenrik Rydberg 	int s = int2scale(p, x);
230*f89bd95cSHenrik Rydberg 
231*f89bd95cSHenrik Rydberg 	return clamp_val(s, 0, p->dim - 1);
232*f89bd95cSHenrik Rydberg }
233*f89bd95cSHenrik Rydberg 
234*f89bd95cSHenrik Rydberg /* setup which logical events to report */
235*f89bd95cSHenrik Rydberg static void setup_events_to_report(struct input_dev *input_dev,
236*f89bd95cSHenrik Rydberg 				   const struct bcm5974_config *cfg)
237*f89bd95cSHenrik Rydberg {
238*f89bd95cSHenrik Rydberg 	__set_bit(EV_ABS, input_dev->evbit);
239*f89bd95cSHenrik Rydberg 
240*f89bd95cSHenrik Rydberg 	input_set_abs_params(input_dev, ABS_PRESSURE,
241*f89bd95cSHenrik Rydberg 				0, cfg->p.dim, cfg->p.fuzz, 0);
242*f89bd95cSHenrik Rydberg 	input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
243*f89bd95cSHenrik Rydberg 				0, cfg->w.dim, cfg->w.fuzz, 0);
244*f89bd95cSHenrik Rydberg 	input_set_abs_params(input_dev, ABS_X,
245*f89bd95cSHenrik Rydberg 				0, cfg->x.dim, cfg->x.fuzz, 0);
246*f89bd95cSHenrik Rydberg 	input_set_abs_params(input_dev, ABS_Y,
247*f89bd95cSHenrik Rydberg 				0, cfg->y.dim, cfg->y.fuzz, 0);
248*f89bd95cSHenrik Rydberg 
249*f89bd95cSHenrik Rydberg 	__set_bit(EV_KEY, input_dev->evbit);
250*f89bd95cSHenrik Rydberg 	__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
251*f89bd95cSHenrik Rydberg 	__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
252*f89bd95cSHenrik Rydberg 	__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
253*f89bd95cSHenrik Rydberg 	__set_bit(BTN_LEFT, input_dev->keybit);
254*f89bd95cSHenrik Rydberg }
255*f89bd95cSHenrik Rydberg 
256*f89bd95cSHenrik Rydberg /* report button data as logical button state */
257*f89bd95cSHenrik Rydberg static int report_bt_state(struct bcm5974 *dev, int size)
258*f89bd95cSHenrik Rydberg {
259*f89bd95cSHenrik Rydberg 	if (size != sizeof(struct bt_data))
260*f89bd95cSHenrik Rydberg 		return -EIO;
261*f89bd95cSHenrik Rydberg 
262*f89bd95cSHenrik Rydberg 	input_report_key(dev->input, BTN_LEFT, dev->bt_data->button);
263*f89bd95cSHenrik Rydberg 	input_sync(dev->input);
264*f89bd95cSHenrik Rydberg 
265*f89bd95cSHenrik Rydberg 	return 0;
266*f89bd95cSHenrik Rydberg }
267*f89bd95cSHenrik Rydberg 
268*f89bd95cSHenrik Rydberg /* report trackpad data as logical trackpad state */
269*f89bd95cSHenrik Rydberg static int report_tp_state(struct bcm5974 *dev, int size)
270*f89bd95cSHenrik Rydberg {
271*f89bd95cSHenrik Rydberg 	const struct bcm5974_config *c = &dev->cfg;
272*f89bd95cSHenrik Rydberg 	const struct tp_finger *f = dev->tp_data->finger;
273*f89bd95cSHenrik Rydberg 	struct input_dev *input = dev->input;
274*f89bd95cSHenrik Rydberg 	const int fingers = (size - 26) / 28;
275*f89bd95cSHenrik Rydberg 	int p = 0, w, x, y, n = 0;
276*f89bd95cSHenrik Rydberg 
277*f89bd95cSHenrik Rydberg 	if (size < 26 || (size - 26) % 28 != 0)
278*f89bd95cSHenrik Rydberg 		return -EIO;
279*f89bd95cSHenrik Rydberg 
280*f89bd95cSHenrik Rydberg 	if (fingers) {
281*f89bd95cSHenrik Rydberg 		p = raw2int(f->force_major);
282*f89bd95cSHenrik Rydberg 		w = raw2int(f->size_major);
283*f89bd95cSHenrik Rydberg 		x = raw2int(f->abs_x);
284*f89bd95cSHenrik Rydberg 		y = raw2int(f->abs_y);
285*f89bd95cSHenrik Rydberg 		n = p > 0 ? fingers : 0;
286*f89bd95cSHenrik Rydberg 
287*f89bd95cSHenrik Rydberg 		dprintk(9,
288*f89bd95cSHenrik Rydberg 			"bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
289*f89bd95cSHenrik Rydberg 			p, w, x, y, n);
290*f89bd95cSHenrik Rydberg 
291*f89bd95cSHenrik Rydberg 		input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
292*f89bd95cSHenrik Rydberg 		input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
293*f89bd95cSHenrik Rydberg 		input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
294*f89bd95cSHenrik Rydberg 	}
295*f89bd95cSHenrik Rydberg 
296*f89bd95cSHenrik Rydberg 	input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
297*f89bd95cSHenrik Rydberg 
298*f89bd95cSHenrik Rydberg 	input_report_key(input, BTN_TOOL_FINGER, n == 1);
299*f89bd95cSHenrik Rydberg 	input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
300*f89bd95cSHenrik Rydberg 	input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
301*f89bd95cSHenrik Rydberg 
302*f89bd95cSHenrik Rydberg 	input_sync(input);
303*f89bd95cSHenrik Rydberg 
304*f89bd95cSHenrik Rydberg 	return 0;
305*f89bd95cSHenrik Rydberg }
306*f89bd95cSHenrik Rydberg 
307*f89bd95cSHenrik Rydberg /* Wellspring initialization constants */
308*f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID		1
309*f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID	9
310*f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_REQUEST_VALUE		0x300
311*f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_REQUEST_INDEX		0
312*f89bd95cSHenrik Rydberg #define BCM5974_WELLSPRING_MODE_VENDOR_VALUE		0x01
313*f89bd95cSHenrik Rydberg 
314*f89bd95cSHenrik Rydberg static int bcm5974_wellspring_mode(struct bcm5974 *dev)
315*f89bd95cSHenrik Rydberg {
316*f89bd95cSHenrik Rydberg 	char *data = kmalloc(8, GFP_KERNEL);
317*f89bd95cSHenrik Rydberg 	int retval = 0, size;
318*f89bd95cSHenrik Rydberg 
319*f89bd95cSHenrik Rydberg 	if (!data) {
320*f89bd95cSHenrik Rydberg 		err("bcm5974: out of memory");
321*f89bd95cSHenrik Rydberg 		retval = -ENOMEM;
322*f89bd95cSHenrik Rydberg 		goto out;
323*f89bd95cSHenrik Rydberg 	}
324*f89bd95cSHenrik Rydberg 
325*f89bd95cSHenrik Rydberg 	/* read configuration */
326*f89bd95cSHenrik Rydberg 	size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
327*f89bd95cSHenrik Rydberg 			BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
328*f89bd95cSHenrik Rydberg 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
329*f89bd95cSHenrik Rydberg 			BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
330*f89bd95cSHenrik Rydberg 			BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
331*f89bd95cSHenrik Rydberg 
332*f89bd95cSHenrik Rydberg 	if (size != 8) {
333*f89bd95cSHenrik Rydberg 		err("bcm5974: could not read from device");
334*f89bd95cSHenrik Rydberg 		retval = -EIO;
335*f89bd95cSHenrik Rydberg 		goto out;
336*f89bd95cSHenrik Rydberg 	}
337*f89bd95cSHenrik Rydberg 
338*f89bd95cSHenrik Rydberg 	/* apply the mode switch */
339*f89bd95cSHenrik Rydberg 	data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE;
340*f89bd95cSHenrik Rydberg 
341*f89bd95cSHenrik Rydberg 	/* write configuration */
342*f89bd95cSHenrik Rydberg 	size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
343*f89bd95cSHenrik Rydberg 			BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
344*f89bd95cSHenrik Rydberg 			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
345*f89bd95cSHenrik Rydberg 			BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
346*f89bd95cSHenrik Rydberg 			BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
347*f89bd95cSHenrik Rydberg 
348*f89bd95cSHenrik Rydberg 	if (size != 8) {
349*f89bd95cSHenrik Rydberg 		err("bcm5974: could not write to device");
350*f89bd95cSHenrik Rydberg 		retval = -EIO;
351*f89bd95cSHenrik Rydberg 		goto out;
352*f89bd95cSHenrik Rydberg 	}
353*f89bd95cSHenrik Rydberg 
354*f89bd95cSHenrik Rydberg 	dprintk(2, "bcm5974: switched to wellspring mode.\n");
355*f89bd95cSHenrik Rydberg 
356*f89bd95cSHenrik Rydberg  out:
357*f89bd95cSHenrik Rydberg 	kfree(data);
358*f89bd95cSHenrik Rydberg 	return retval;
359*f89bd95cSHenrik Rydberg }
360*f89bd95cSHenrik Rydberg 
361*f89bd95cSHenrik Rydberg static void bcm5974_irq_button(struct urb *urb)
362*f89bd95cSHenrik Rydberg {
363*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = urb->context;
364*f89bd95cSHenrik Rydberg 	int error;
365*f89bd95cSHenrik Rydberg 
366*f89bd95cSHenrik Rydberg 	switch (urb->status) {
367*f89bd95cSHenrik Rydberg 	case 0:
368*f89bd95cSHenrik Rydberg 		break;
369*f89bd95cSHenrik Rydberg 	case -EOVERFLOW:
370*f89bd95cSHenrik Rydberg 	case -ECONNRESET:
371*f89bd95cSHenrik Rydberg 	case -ENOENT:
372*f89bd95cSHenrik Rydberg 	case -ESHUTDOWN:
373*f89bd95cSHenrik Rydberg 		dbg("bcm5974: button urb shutting down: %d", urb->status);
374*f89bd95cSHenrik Rydberg 		return;
375*f89bd95cSHenrik Rydberg 	default:
376*f89bd95cSHenrik Rydberg 		dbg("bcm5974: button urb status: %d", urb->status);
377*f89bd95cSHenrik Rydberg 		goto exit;
378*f89bd95cSHenrik Rydberg 	}
379*f89bd95cSHenrik Rydberg 
380*f89bd95cSHenrik Rydberg 	if (report_bt_state(dev, dev->bt_urb->actual_length))
381*f89bd95cSHenrik Rydberg 		dprintk(1, "bcm5974: bad button package, length: %d\n",
382*f89bd95cSHenrik Rydberg 			dev->bt_urb->actual_length);
383*f89bd95cSHenrik Rydberg 
384*f89bd95cSHenrik Rydberg exit:
385*f89bd95cSHenrik Rydberg 	error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
386*f89bd95cSHenrik Rydberg 	if (error)
387*f89bd95cSHenrik Rydberg 		err("bcm5974: button urb failed: %d", error);
388*f89bd95cSHenrik Rydberg }
389*f89bd95cSHenrik Rydberg 
390*f89bd95cSHenrik Rydberg static void bcm5974_irq_trackpad(struct urb *urb)
391*f89bd95cSHenrik Rydberg {
392*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = urb->context;
393*f89bd95cSHenrik Rydberg 	int error;
394*f89bd95cSHenrik Rydberg 
395*f89bd95cSHenrik Rydberg 	switch (urb->status) {
396*f89bd95cSHenrik Rydberg 	case 0:
397*f89bd95cSHenrik Rydberg 		break;
398*f89bd95cSHenrik Rydberg 	case -EOVERFLOW:
399*f89bd95cSHenrik Rydberg 	case -ECONNRESET:
400*f89bd95cSHenrik Rydberg 	case -ENOENT:
401*f89bd95cSHenrik Rydberg 	case -ESHUTDOWN:
402*f89bd95cSHenrik Rydberg 		dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
403*f89bd95cSHenrik Rydberg 		return;
404*f89bd95cSHenrik Rydberg 	default:
405*f89bd95cSHenrik Rydberg 		dbg("bcm5974: trackpad urb status: %d", urb->status);
406*f89bd95cSHenrik Rydberg 		goto exit;
407*f89bd95cSHenrik Rydberg 	}
408*f89bd95cSHenrik Rydberg 
409*f89bd95cSHenrik Rydberg 	/* control response ignored */
410*f89bd95cSHenrik Rydberg 	if (dev->tp_urb->actual_length == 2)
411*f89bd95cSHenrik Rydberg 		goto exit;
412*f89bd95cSHenrik Rydberg 
413*f89bd95cSHenrik Rydberg 	if (report_tp_state(dev, dev->tp_urb->actual_length))
414*f89bd95cSHenrik Rydberg 		dprintk(1, "bcm5974: bad trackpad package, length: %d\n",
415*f89bd95cSHenrik Rydberg 			dev->tp_urb->actual_length);
416*f89bd95cSHenrik Rydberg 
417*f89bd95cSHenrik Rydberg exit:
418*f89bd95cSHenrik Rydberg 	error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
419*f89bd95cSHenrik Rydberg 	if (error)
420*f89bd95cSHenrik Rydberg 		err("bcm5974: trackpad urb failed: %d", error);
421*f89bd95cSHenrik Rydberg }
422*f89bd95cSHenrik Rydberg 
423*f89bd95cSHenrik Rydberg /*
424*f89bd95cSHenrik Rydberg  * The Wellspring trackpad, like many recent Apple trackpads, share
425*f89bd95cSHenrik Rydberg  * the usb device with the keyboard. Since keyboards are usually
426*f89bd95cSHenrik Rydberg  * handled by the HID system, the device ends up being handled by two
427*f89bd95cSHenrik Rydberg  * modules. Setting up the device therefore becomes slightly
428*f89bd95cSHenrik Rydberg  * complicated. To enable multitouch features, a mode switch is
429*f89bd95cSHenrik Rydberg  * required, which is usually applied via the control interface of the
430*f89bd95cSHenrik Rydberg  * device.  It can be argued where this switch should take place. In
431*f89bd95cSHenrik Rydberg  * some drivers, like appletouch, the switch is made during
432*f89bd95cSHenrik Rydberg  * probe. However, the hid module may also alter the state of the
433*f89bd95cSHenrik Rydberg  * device, resulting in trackpad malfunction under certain
434*f89bd95cSHenrik Rydberg  * circumstances. To get around this problem, there is at least one
435*f89bd95cSHenrik Rydberg  * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to
436*f89bd95cSHenrik Rydberg  * recieve a reset_resume request rather than the normal resume.
437*f89bd95cSHenrik Rydberg  * Since the implementation of reset_resume is equal to mode switch
438*f89bd95cSHenrik Rydberg  * plus start_traffic, it seems easier to always do the switch when
439*f89bd95cSHenrik Rydberg  * starting traffic on the device.
440*f89bd95cSHenrik Rydberg  */
441*f89bd95cSHenrik Rydberg static int bcm5974_start_traffic(struct bcm5974 *dev)
442*f89bd95cSHenrik Rydberg {
443*f89bd95cSHenrik Rydberg 	if (bcm5974_wellspring_mode(dev)) {
444*f89bd95cSHenrik Rydberg 		dprintk(1, "bcm5974: mode switch failed\n");
445*f89bd95cSHenrik Rydberg 		goto error;
446*f89bd95cSHenrik Rydberg 	}
447*f89bd95cSHenrik Rydberg 
448*f89bd95cSHenrik Rydberg 	if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
449*f89bd95cSHenrik Rydberg 		goto error;
450*f89bd95cSHenrik Rydberg 
451*f89bd95cSHenrik Rydberg 	if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
452*f89bd95cSHenrik Rydberg 		goto err_kill_bt;
453*f89bd95cSHenrik Rydberg 
454*f89bd95cSHenrik Rydberg 	return 0;
455*f89bd95cSHenrik Rydberg 
456*f89bd95cSHenrik Rydberg err_kill_bt:
457*f89bd95cSHenrik Rydberg 	usb_kill_urb(dev->bt_urb);
458*f89bd95cSHenrik Rydberg error:
459*f89bd95cSHenrik Rydberg 	return -EIO;
460*f89bd95cSHenrik Rydberg }
461*f89bd95cSHenrik Rydberg 
462*f89bd95cSHenrik Rydberg static void bcm5974_pause_traffic(struct bcm5974 *dev)
463*f89bd95cSHenrik Rydberg {
464*f89bd95cSHenrik Rydberg 	usb_kill_urb(dev->tp_urb);
465*f89bd95cSHenrik Rydberg 	usb_kill_urb(dev->bt_urb);
466*f89bd95cSHenrik Rydberg }
467*f89bd95cSHenrik Rydberg 
468*f89bd95cSHenrik Rydberg /*
469*f89bd95cSHenrik Rydberg  * The code below implements open/close and manual suspend/resume.
470*f89bd95cSHenrik Rydberg  * All functions may be called in random order.
471*f89bd95cSHenrik Rydberg  *
472*f89bd95cSHenrik Rydberg  * Opening a suspended device fails with EACCES - permission denied.
473*f89bd95cSHenrik Rydberg  *
474*f89bd95cSHenrik Rydberg  * Failing a resume leaves the device resumed but closed.
475*f89bd95cSHenrik Rydberg  */
476*f89bd95cSHenrik Rydberg static int bcm5974_open(struct input_dev *input)
477*f89bd95cSHenrik Rydberg {
478*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = input_get_drvdata(input);
479*f89bd95cSHenrik Rydberg 	int error;
480*f89bd95cSHenrik Rydberg 
481*f89bd95cSHenrik Rydberg 	mutex_lock(&dev->pm_mutex);
482*f89bd95cSHenrik Rydberg 
483*f89bd95cSHenrik Rydberg 	error = bcm5974_start_traffic(dev);
484*f89bd95cSHenrik Rydberg 	if (!error)
485*f89bd95cSHenrik Rydberg 		dev->opened = 1;
486*f89bd95cSHenrik Rydberg 
487*f89bd95cSHenrik Rydberg 	mutex_unlock(&dev->pm_mutex);
488*f89bd95cSHenrik Rydberg 
489*f89bd95cSHenrik Rydberg 	return error;
490*f89bd95cSHenrik Rydberg }
491*f89bd95cSHenrik Rydberg 
492*f89bd95cSHenrik Rydberg static void bcm5974_close(struct input_dev *input)
493*f89bd95cSHenrik Rydberg {
494*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = input_get_drvdata(input);
495*f89bd95cSHenrik Rydberg 
496*f89bd95cSHenrik Rydberg 	mutex_lock(&dev->pm_mutex);
497*f89bd95cSHenrik Rydberg 
498*f89bd95cSHenrik Rydberg 	bcm5974_pause_traffic(dev);
499*f89bd95cSHenrik Rydberg 	dev->opened = 0;
500*f89bd95cSHenrik Rydberg 
501*f89bd95cSHenrik Rydberg 	mutex_unlock(&dev->pm_mutex);
502*f89bd95cSHenrik Rydberg }
503*f89bd95cSHenrik Rydberg 
504*f89bd95cSHenrik Rydberg static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message)
505*f89bd95cSHenrik Rydberg {
506*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = usb_get_intfdata(iface);
507*f89bd95cSHenrik Rydberg 
508*f89bd95cSHenrik Rydberg 	mutex_lock(&dev->pm_mutex);
509*f89bd95cSHenrik Rydberg 
510*f89bd95cSHenrik Rydberg 	if (dev->opened)
511*f89bd95cSHenrik Rydberg 		bcm5974_pause_traffic(dev);
512*f89bd95cSHenrik Rydberg 
513*f89bd95cSHenrik Rydberg 	mutex_unlock(&dev->pm_mutex);
514*f89bd95cSHenrik Rydberg 
515*f89bd95cSHenrik Rydberg 	return 0;
516*f89bd95cSHenrik Rydberg }
517*f89bd95cSHenrik Rydberg 
518*f89bd95cSHenrik Rydberg static int bcm5974_resume(struct usb_interface *iface)
519*f89bd95cSHenrik Rydberg {
520*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = usb_get_intfdata(iface);
521*f89bd95cSHenrik Rydberg 	int error = 0;
522*f89bd95cSHenrik Rydberg 
523*f89bd95cSHenrik Rydberg 	mutex_lock(&dev->pm_mutex);
524*f89bd95cSHenrik Rydberg 
525*f89bd95cSHenrik Rydberg 	if (dev->opened)
526*f89bd95cSHenrik Rydberg 		error = bcm5974_start_traffic(dev);
527*f89bd95cSHenrik Rydberg 
528*f89bd95cSHenrik Rydberg 	mutex_unlock(&dev->pm_mutex);
529*f89bd95cSHenrik Rydberg 
530*f89bd95cSHenrik Rydberg 	return error;
531*f89bd95cSHenrik Rydberg }
532*f89bd95cSHenrik Rydberg 
533*f89bd95cSHenrik Rydberg static int bcm5974_probe(struct usb_interface *iface,
534*f89bd95cSHenrik Rydberg 			 const struct usb_device_id *id)
535*f89bd95cSHenrik Rydberg {
536*f89bd95cSHenrik Rydberg 	struct usb_device *udev = interface_to_usbdev(iface);
537*f89bd95cSHenrik Rydberg 	const struct bcm5974_config *cfg;
538*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev;
539*f89bd95cSHenrik Rydberg 	struct input_dev *input_dev;
540*f89bd95cSHenrik Rydberg 	int error = -ENOMEM;
541*f89bd95cSHenrik Rydberg 
542*f89bd95cSHenrik Rydberg 	/* find the product index */
543*f89bd95cSHenrik Rydberg 	cfg = bcm5974_get_config(udev);
544*f89bd95cSHenrik Rydberg 
545*f89bd95cSHenrik Rydberg 	/* allocate memory for our device state and initialize it */
546*f89bd95cSHenrik Rydberg 	dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
547*f89bd95cSHenrik Rydberg 	input_dev = input_allocate_device();
548*f89bd95cSHenrik Rydberg 	if (!dev || !input_dev) {
549*f89bd95cSHenrik Rydberg 		err("bcm5974: out of memory");
550*f89bd95cSHenrik Rydberg 		goto err_free_devs;
551*f89bd95cSHenrik Rydberg 	}
552*f89bd95cSHenrik Rydberg 
553*f89bd95cSHenrik Rydberg 	dev->udev = udev;
554*f89bd95cSHenrik Rydberg 	dev->input = input_dev;
555*f89bd95cSHenrik Rydberg 	dev->cfg = *cfg;
556*f89bd95cSHenrik Rydberg 	mutex_init(&dev->pm_mutex);
557*f89bd95cSHenrik Rydberg 
558*f89bd95cSHenrik Rydberg 	/* setup urbs */
559*f89bd95cSHenrik Rydberg 	dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
560*f89bd95cSHenrik Rydberg 	if (!dev->bt_urb)
561*f89bd95cSHenrik Rydberg 		goto err_free_devs;
562*f89bd95cSHenrik Rydberg 
563*f89bd95cSHenrik Rydberg 	dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
564*f89bd95cSHenrik Rydberg 	if (!dev->tp_urb)
565*f89bd95cSHenrik Rydberg 		goto err_free_bt_urb;
566*f89bd95cSHenrik Rydberg 
567*f89bd95cSHenrik Rydberg 	dev->bt_data = usb_buffer_alloc(dev->udev,
568*f89bd95cSHenrik Rydberg 					dev->cfg.bt_datalen, GFP_KERNEL,
569*f89bd95cSHenrik Rydberg 					&dev->bt_urb->transfer_dma);
570*f89bd95cSHenrik Rydberg 	if (!dev->bt_data)
571*f89bd95cSHenrik Rydberg 		goto err_free_urb;
572*f89bd95cSHenrik Rydberg 
573*f89bd95cSHenrik Rydberg 	dev->tp_data = usb_buffer_alloc(dev->udev,
574*f89bd95cSHenrik Rydberg 					dev->cfg.tp_datalen, GFP_KERNEL,
575*f89bd95cSHenrik Rydberg 					&dev->tp_urb->transfer_dma);
576*f89bd95cSHenrik Rydberg 	if (!dev->tp_data)
577*f89bd95cSHenrik Rydberg 		goto err_free_bt_buffer;
578*f89bd95cSHenrik Rydberg 
579*f89bd95cSHenrik Rydberg 	usb_fill_int_urb(dev->bt_urb, udev,
580*f89bd95cSHenrik Rydberg 			 usb_rcvintpipe(udev, cfg->bt_ep),
581*f89bd95cSHenrik Rydberg 			 dev->bt_data, dev->cfg.bt_datalen,
582*f89bd95cSHenrik Rydberg 			 bcm5974_irq_button, dev, 1);
583*f89bd95cSHenrik Rydberg 
584*f89bd95cSHenrik Rydberg 	usb_fill_int_urb(dev->tp_urb, udev,
585*f89bd95cSHenrik Rydberg 			 usb_rcvintpipe(udev, cfg->tp_ep),
586*f89bd95cSHenrik Rydberg 			 dev->tp_data, dev->cfg.tp_datalen,
587*f89bd95cSHenrik Rydberg 			 bcm5974_irq_trackpad, dev, 1);
588*f89bd95cSHenrik Rydberg 
589*f89bd95cSHenrik Rydberg 	/* create bcm5974 device */
590*f89bd95cSHenrik Rydberg 	usb_make_path(udev, dev->phys, sizeof(dev->phys));
591*f89bd95cSHenrik Rydberg 	strlcat(dev->phys, "/input0", sizeof(dev->phys));
592*f89bd95cSHenrik Rydberg 
593*f89bd95cSHenrik Rydberg 	input_dev->name = "bcm5974";
594*f89bd95cSHenrik Rydberg 	input_dev->phys = dev->phys;
595*f89bd95cSHenrik Rydberg 	usb_to_input_id(dev->udev, &input_dev->id);
596*f89bd95cSHenrik Rydberg 	input_dev->dev.parent = &iface->dev;
597*f89bd95cSHenrik Rydberg 
598*f89bd95cSHenrik Rydberg 	input_set_drvdata(input_dev, dev);
599*f89bd95cSHenrik Rydberg 
600*f89bd95cSHenrik Rydberg 	input_dev->open = bcm5974_open;
601*f89bd95cSHenrik Rydberg 	input_dev->close = bcm5974_close;
602*f89bd95cSHenrik Rydberg 
603*f89bd95cSHenrik Rydberg 	setup_events_to_report(input_dev, cfg);
604*f89bd95cSHenrik Rydberg 
605*f89bd95cSHenrik Rydberg 	error = input_register_device(dev->input);
606*f89bd95cSHenrik Rydberg 	if (error)
607*f89bd95cSHenrik Rydberg 		goto err_free_buffer;
608*f89bd95cSHenrik Rydberg 
609*f89bd95cSHenrik Rydberg 	/* save our data pointer in this interface device */
610*f89bd95cSHenrik Rydberg 	usb_set_intfdata(iface, dev);
611*f89bd95cSHenrik Rydberg 
612*f89bd95cSHenrik Rydberg 	return 0;
613*f89bd95cSHenrik Rydberg 
614*f89bd95cSHenrik Rydberg err_free_buffer:
615*f89bd95cSHenrik Rydberg 	usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
616*f89bd95cSHenrik Rydberg 		dev->tp_data, dev->tp_urb->transfer_dma);
617*f89bd95cSHenrik Rydberg err_free_bt_buffer:
618*f89bd95cSHenrik Rydberg 	usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
619*f89bd95cSHenrik Rydberg 		dev->bt_data, dev->bt_urb->transfer_dma);
620*f89bd95cSHenrik Rydberg err_free_urb:
621*f89bd95cSHenrik Rydberg 	usb_free_urb(dev->tp_urb);
622*f89bd95cSHenrik Rydberg err_free_bt_urb:
623*f89bd95cSHenrik Rydberg 	usb_free_urb(dev->bt_urb);
624*f89bd95cSHenrik Rydberg err_free_devs:
625*f89bd95cSHenrik Rydberg 	usb_set_intfdata(iface, NULL);
626*f89bd95cSHenrik Rydberg 	input_free_device(input_dev);
627*f89bd95cSHenrik Rydberg 	kfree(dev);
628*f89bd95cSHenrik Rydberg 	return error;
629*f89bd95cSHenrik Rydberg }
630*f89bd95cSHenrik Rydberg 
631*f89bd95cSHenrik Rydberg static void bcm5974_disconnect(struct usb_interface *iface)
632*f89bd95cSHenrik Rydberg {
633*f89bd95cSHenrik Rydberg 	struct bcm5974 *dev = usb_get_intfdata(iface);
634*f89bd95cSHenrik Rydberg 
635*f89bd95cSHenrik Rydberg 	usb_set_intfdata(iface, NULL);
636*f89bd95cSHenrik Rydberg 
637*f89bd95cSHenrik Rydberg 	input_unregister_device(dev->input);
638*f89bd95cSHenrik Rydberg 	usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
639*f89bd95cSHenrik Rydberg 			dev->tp_data, dev->tp_urb->transfer_dma);
640*f89bd95cSHenrik Rydberg 	usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
641*f89bd95cSHenrik Rydberg 			dev->bt_data, dev->bt_urb->transfer_dma);
642*f89bd95cSHenrik Rydberg 	usb_free_urb(dev->tp_urb);
643*f89bd95cSHenrik Rydberg 	usb_free_urb(dev->bt_urb);
644*f89bd95cSHenrik Rydberg 	kfree(dev);
645*f89bd95cSHenrik Rydberg }
646*f89bd95cSHenrik Rydberg 
647*f89bd95cSHenrik Rydberg static struct usb_driver bcm5974_driver = {
648*f89bd95cSHenrik Rydberg 	.name			= "bcm5974",
649*f89bd95cSHenrik Rydberg 	.probe			= bcm5974_probe,
650*f89bd95cSHenrik Rydberg 	.disconnect		= bcm5974_disconnect,
651*f89bd95cSHenrik Rydberg 	.suspend		= bcm5974_suspend,
652*f89bd95cSHenrik Rydberg 	.resume			= bcm5974_resume,
653*f89bd95cSHenrik Rydberg 	.reset_resume		= bcm5974_resume,
654*f89bd95cSHenrik Rydberg 	.id_table		= bcm5974_table,
655*f89bd95cSHenrik Rydberg };
656*f89bd95cSHenrik Rydberg 
657*f89bd95cSHenrik Rydberg static int __init bcm5974_init(void)
658*f89bd95cSHenrik Rydberg {
659*f89bd95cSHenrik Rydberg 	return usb_register(&bcm5974_driver);
660*f89bd95cSHenrik Rydberg }
661*f89bd95cSHenrik Rydberg 
662*f89bd95cSHenrik Rydberg static void __exit bcm5974_exit(void)
663*f89bd95cSHenrik Rydberg {
664*f89bd95cSHenrik Rydberg 	usb_deregister(&bcm5974_driver);
665*f89bd95cSHenrik Rydberg }
666*f89bd95cSHenrik Rydberg 
667*f89bd95cSHenrik Rydberg module_init(bcm5974_init);
668*f89bd95cSHenrik Rydberg module_exit(bcm5974_exit);
669*f89bd95cSHenrik Rydberg 
670