summaryrefslogtreecommitdiff
path: root/bcm5974.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2008-10-08 23:13:06 +0200
committerHenrik Rydberg <rydberg@euromail.se>2008-10-08 23:13:06 +0200
commit563dae29cd97e8ab1428a4827bdef557ee6fd235 (patch)
tree7e5972ca3bbc0452fb47ff628f93aeef3a950e92 /bcm5974.c
Initial import of bcm5974-0.42. Changelog from the absolute beginning:
bcm5974 (0.42) unstable; urgency=low * First button click registered. * Hooks pre/post-reset added. -- Henrik Rydberg <rydberg@euromail.se> Tue, 01 Jul 2008 20:59:39 +0200 bcm5974 (0.41) unstable; urgency=low * The reset_resume kernel function added. -- Henrik Rydberg <rydberg@euromail.se> Sun, 29 Jun 2008 20:59:39 +0200 bcm5974 (0.4) unstable; urgency=low * Both finger pressure and width reported. -- Henrik Rydberg <rydberg@euromail.se> Sun, 29 Jun 2008 18:59:39 +0200 bcm5974 (0.31) unstable; urgency=low * Administrative changes for kernel.org. -- Henrik Rydberg <rydberg@euromail.se> Fri, 27 Jun 2008 20:59:39 +0200 bcm5974 (0.3) unstable; urgency=low * Explicit device structure, use all packages. -- Henrik Rydberg <rydberg@euromail.se> Fri, 27 Jun 2008 18:59:39 +0200 bcm5974 (0.23) unstable; urgency=low * Finger release not reported properly. -- Henrik Rydberg <rydberg@euromail.se> Fri, 27 Jun 2008 17:59:39 +0200 bcm5974 (0.22) unstable; urgency=low * ABS coordinates more stable with synaptics. -- Henrik Rydberg <rydberg@euromail.se> Thu, 26 Jun 2008 20:59:39 +0200 bcm5974 (0.21) unstable; urgency=low * Fixed the relative coordinate scaling. -- Henrik Rydberg <rydberg@euromail.se> Wed, 25 Jun 2008 20:59:39 +0200 bcm5974 (0.2) unstable; urgency=low * Misinterpreted pressure input, noise reduction. -- Henrik Rydberg <rydberg@euromail.se> Wed, 25 Jun 2008 20:59:39 +0200 bcm5974 (0.1) unstable; urgency=low * First version. -- Henrik Rydberg <rydberg@euromail.se> Tue, 24 Jun 2008 20:59:39 +0200
Diffstat (limited to 'bcm5974.c')
-rw-r--r--bcm5974.c689
1 files changed, 689 insertions, 0 deletions
diff --git a/bcm5974.c b/bcm5974.c
new file mode 100644
index 0000000..68f92c5
--- /dev/null
+++ b/bcm5974.c
@@ -0,0 +1,689 @@
1/*
2 * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
3 *
4 * Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se)
5 *
6 * The USB initialization and package decoding was made by
7 * Scott Shawcroft as part of the touchd user-space driver project:
8 * Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com)
9 *
10 * The BCM5974 driver is based on the appletouch driver:
11 * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
12 * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net)
13 * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
14 * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
15 * Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
16 * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
17 * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch)
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 *
33 */
34
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/init.h>
38#include <linux/slab.h>
39#include <linux/module.h>
40#include <linux/usb/input.h>
41#include <linux/hid.h>
42
43#define APPLE_VENDOR_ID 0x05AC
44
45/* MacbookAir BCM5974, aka wellspring */
46
47#define ATP_WELLSPRING_ANSI 0x0223
48#define ATP_WELLSPRING_ISO 0x0224
49#define ATP_WELLSPRING_JIS 0x0225
50#define ATP_WELLSPRING2_ANSI 0x0230
51#define ATP_WELLSPRING2_ISO 0x0231
52#define ATP_WELLSPRING2_JIS 0x0232
53
54#define ATP_DEVICE(prod) { \
55 .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
56 USB_DEVICE_ID_MATCH_INT_CLASS | \
57 USB_DEVICE_ID_MATCH_INT_PROTOCOL), \
58 .idVendor = APPLE_VENDOR_ID, \
59 .idProduct = (prod), \
60 .bInterfaceClass = USB_INTERFACE_CLASS_HID, \
61 .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \
62 }
63
64/* table of devices that work with this driver */
65static const struct usb_device_id atp_table [] = {
66 /* MacbookAir1.1 */
67 ATP_DEVICE(ATP_WELLSPRING_ANSI),
68 ATP_DEVICE(ATP_WELLSPRING_ISO),
69 ATP_DEVICE(ATP_WELLSPRING_JIS),
70
71 /* MacbookProPenryn */
72 ATP_DEVICE(ATP_WELLSPRING2_ANSI),
73 ATP_DEVICE(ATP_WELLSPRING2_ISO),
74 ATP_DEVICE(ATP_WELLSPRING2_JIS),
75
76 /* Terminating entry */
77 {}
78};
79MODULE_DEVICE_TABLE(usb, atp_table);
80
81struct atp_params_t {
82 int devmin; /* device minimum reading */
83 int devmax; /* device maximum reading */
84 int min; /* logical minimum reading */
85 int max; /* logical maximum reading */
86 int fuzz; /* reading noise value */
87 int flat; /* zero */
88};
89
90struct atp_config_t {
91 int ansi, iso, jis; /* the product id of this device */
92 int bt_ep; /* the endpoint of the button interface */
93 int bt_datalen; /* data length of the button interface */
94 int tp_ep; /* the endpoint of the trackpad interface */
95 int tp_datalen; /* data length of the trackpad interface */
96 struct atp_params_t x; /* horizontal limits */
97 struct atp_params_t y; /* vertical limits */
98 struct atp_params_t p; /* finger pressure limits */
99 struct atp_params_t w; /* finger width limits */
100};
101
102/* trackpad header structure */
103struct tp_header_t {
104 u8 unknown1[16]; /* constants, timers, etc */
105 u8 nfinger; /* number of fingers on trackpad */
106 u8 unknown2[9]; /* constants, timers, etc */
107};
108
109/* trackpad finger structure */
110struct tp_finger_t {
111 __le16 origin; /* left/right origin? */
112 __le16 abs_x; /* absolute x coodinate */
113 __le16 abs_y; /* absolute y coodinate */
114 __le16 rel_x; /* relative x coodinate */
115 __le16 rel_y; /* relative y coodinate */
116 __le16 size_major; /* finger size, major axis? */
117 __le16 size_minor; /* finger size, minor axis? */
118 __le16 orientation; /* 16384 when point, else 15 bit angle */
119 __le16 force_major; /* trackpad force, major axis? */
120 __le16 force_minor; /* trackpad force, minor axis? */
121 __le16 unused[3]; /* zeros */
122 __le16 multi; /* one finger: varies, more fingers: constant */
123};
124
125/* trackpad data structure */
126struct tp_data_t {
127 struct tp_header_t header;
128 struct tp_finger_t finger[16];
129};
130
131/* device constants */
132static const struct atp_config_t atp_config_table[] = {
133 {
134 ATP_WELLSPRING_ANSI,
135 ATP_WELLSPRING_ISO,
136 ATP_WELLSPRING_JIS,
137 0x84, 4,
138 0x81, sizeof(struct tp_data_t),
139 {-4824, 5342, 0, 1280, 16, 0},
140 {-172, 5820, 0, 800, 16, 0},
141 {0, 256, 0, 256, 16, 0},
142 {0, 2048, 0, 256, 16, 0}
143 },
144 {
145 ATP_WELLSPRING2_ANSI,
146 ATP_WELLSPRING2_ISO,
147 ATP_WELLSPRING2_JIS,
148 0x84, 4,
149 0x81, sizeof(struct tp_data_t),
150 {-4824, 5342, 0, 1280, 16, 0},
151 {-172, 5820, 0, 800, 16, 0},
152 {0, 256, 0, 256, 16, 0},
153 {0, 2048, 0, 256, 16, 0}
154 },
155 {}
156};
157
158static inline
159const struct atp_config_t *atp_product_config(struct usb_device *udev)
160{
161 u16 id = le16_to_cpu(udev->descriptor.idProduct);
162 const struct atp_config_t *config;
163 for (config = atp_config_table; config->ansi; ++config)
164 if (config->ansi == id || config->iso == id || config->jis == id)
165 return config;
166 return atp_config_table;
167}
168
169/* Wellspring initialization constants */
170#define ATP_WELLSPRING_MODE_READ_REQUEST_ID 1
171#define ATP_WELLSPRING_MODE_WRITE_REQUEST_ID 9
172#define ATP_WELLSPRING_MODE_REQUEST_VALUE 0x300
173#define ATP_WELLSPRING_MODE_REQUEST_INDEX 0
174#define ATP_WELLSPRING_MODE_VENDOR_VALUE_1 0x01
175#define ATP_WELLSPRING_MODE_VENDOR_VALUE_2 0x05
176
177#define dprintk(format, a...) \
178 { if (debug) printk(KERN_DEBUG format, ##a); }
179
180MODULE_AUTHOR("Henrik Rydberg");
181MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver");
182MODULE_LICENSE("GPL");
183
184static int debug = 1;
185module_param(debug, int, 0644);
186MODULE_PARM_DESC(debug, "Activate debugging output");
187
188static int atp_wellspring_init(struct usb_device *udev)
189{
190 const struct atp_config_t *cfg = atp_product_config(udev);
191 char *data = kmalloc(8, GFP_KERNEL);
192 int size;
193
194 /* reset button endpoint */
195 if (usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
196 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
197 0, cfg->bt_ep, NULL, 0, 5000)) {
198 err("Could not reset button endpoint");
199 goto error;
200 }
201
202 /* reset trackpad endpoint */
203 if (usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
204 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
205 0, cfg->tp_ep, NULL, 0, 5000)) {
206 err("Could not reset trackpad endpoint");
207 goto error;
208 }
209
210 /* read configuration */
211 size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
212 ATP_WELLSPRING_MODE_READ_REQUEST_ID,
213 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
214 ATP_WELLSPRING_MODE_REQUEST_VALUE,
215 ATP_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
216
217 if (size != 8) {
218 err("Could not do mode read request from device (Wellspring Raw mode)");
219 goto error;
220 }
221
222 /* apply the mode switch */
223 data[0] = ATP_WELLSPRING_MODE_VENDOR_VALUE_1;
224 data[1] = ATP_WELLSPRING_MODE_VENDOR_VALUE_2;
225
226 /* write configuration */
227 size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
228 ATP_WELLSPRING_MODE_WRITE_REQUEST_ID,
229 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
230 ATP_WELLSPRING_MODE_REQUEST_VALUE,
231 ATP_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
232
233 if (size != 8) {
234 err("Could not do mode write request to device (Wellspring Raw mode)");
235 goto error;
236 }
237
238 printk(KERN_INFO "bcm5974: Wellspring mode initialized.\n");
239
240 kfree(data);
241 return 0;
242
243 error:
244 kfree(data);
245 return -EIO;
246}
247
248/* Structure to hold all of our device specific stuff */
249struct atp {
250 char phys[64];
251 struct usb_device *udev; /* usb device */
252 struct input_dev *input; /* input dev */
253 struct atp_config_t cfg; /* device configuration */
254 int open; /* >0: open, else closed */
255 int suspended; /* >0: suspended, else open */
256 struct urb *bt_urb; /* button usb request block */
257 signed char *bt_data; /* button transferred data */
258 unsigned bt_state; /* current button state */
259 struct urb *tp_urb; /* trackpad usb request block */
260 signed char *tp_data; /* trackpad transferred data */
261 unsigned tp_valid; /* are the trackpad sensors valid ? */
262};
263
264static inline int raw2int(__le16 x)
265{
266 return (short)le16_to_cpu(x);
267}
268
269static inline int int2scale(const struct atp_params_t *p, int x)
270{
271 return ((p->max-p->min)*x)/(p->devmax-p->devmin);
272}
273
274/**
275 * all value ranges, both device and logical, are assumed to be [a,b).
276 */
277static inline int int2bound(const struct atp_params_t *p, int x)
278{
279 int s = p->min+int2scale(p, x);
280 return s < p->min?p->min:s >= p->max?p->max-1:s;
281}
282
283/**
284 * check quality of reading.
285 * -1: bad data
286 * 0: ignore this reading
287 * 1: good reading
288 */
289static int compute_quality(const unsigned char *data, int size)
290{
291 if (size < 26 || (size-26)%28 != 0)
292 return -1;
293
294 return 1;
295}
296
297/**
298 * convert raw data to synaptics sensor output.
299 * returns the number of fingers on the trackpad,
300 * or a negative number in vase of bad data.
301 */
302static int compute_movement(int *abs_x, int *abs_y,
303 int *rel_x, int *rel_y,
304 int *pressure, int *width,
305 struct atp_config_t *cfg,
306 const unsigned char *data, int size)
307{
308 const int nfinger = (size-26)/28;
309 const struct tp_data_t *tp = (struct tp_data_t *) data;
310
311 if (nfinger) {
312 *abs_x = int2bound(&cfg->x, raw2int(tp->finger->abs_x) - cfg->x.devmin);
313 *abs_y = int2bound(&cfg->y, cfg->y.devmax - raw2int(tp->finger->abs_y));
314 *rel_x = int2scale(&cfg->x, raw2int(tp->finger->rel_x));
315 *rel_y = int2scale(&cfg->y, -raw2int(tp->finger->rel_y));
316 *pressure = int2bound(&cfg->p, raw2int(tp->finger->force_major));
317 *width = int2bound(&cfg->w, raw2int(tp->finger->size_major));
318 } else {
319 *abs_x = 0;
320 *abs_y = 0;
321 *rel_x = 0;
322 *rel_y = 0;
323 *pressure = 0;
324 *width = 0;
325 }
326
327 /* report zero fingers for zero pressure */
328 return *pressure > 0?nfinger:0;
329}
330
331static void atp_button(struct urb *urb)
332{
333 struct atp *dev = urb->context;
334 int button, retval;
335
336 switch (urb->status) {
337 case 0:
338 break;
339 case -EOVERFLOW:
340 case -ECONNRESET:
341 case -ENOENT:
342 case -ESHUTDOWN:
343 dbg("bcm5974: button urb shutting down: %d", urb->status);
344 return;
345 default:
346 dbg("bcm5974: button urb status: %d", urb->status);
347 goto exit;
348 }
349
350 /* drop incomplete datasets */
351 if (dev->bt_urb->actual_length != 4) {
352 dprintk("bcm5974: incomplete button package (first byte: %d, length: %d)\n",
353 (int)dev->bt_data[0], dev->bt_urb->actual_length);
354 goto exit;
355 }
356
357 button = dev->bt_data[1];
358
359 /* only report button state changes */
360 if (button != dev->bt_state) {
361 input_report_key(dev->input, BTN_LEFT, button);
362 input_sync(dev->input);
363 }
364
365 dev->bt_state = button;
366
367 exit:
368 retval = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
369 if (retval)
370 err("bcm5974: button urb failed: %d", retval);
371}
372
373static void atp_trackpad(struct urb *urb)
374{
375 struct atp *dev = urb->context;
376 int abs_x, abs_y, rel_x, rel_y, pressure, width;
377 int quality, nfinger, retval;
378
379 switch (urb->status) {
380 case 0:
381 break;
382 case -EOVERFLOW:
383 case -ECONNRESET:
384 case -ENOENT:
385 case -ESHUTDOWN:
386 dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
387 return;
388 default:
389 dbg("bcm5974: trackpad urb status: %d", urb->status);
390 goto exit;
391 }
392
393 /* first sample data ignored */
394 if (!dev->tp_valid) {
395 dev->tp_valid = 1;
396 goto exit;
397 }
398
399 /* determine quality of reading */
400 quality = compute_quality(dev->tp_data, dev->tp_urb->actual_length);
401
402 /* drop incomplete datasets */
403 if (quality < 0) {
404 dprintk("bcm5974: incomplete trackpad package "
405 "(first byte: %d, length: %d)\n",
406 (int)dev->tp_data[0], dev->tp_urb->actual_length);
407 goto exit;
408 }
409
410 /* drop poor quality readings */
411 if (quality == 0)
412 goto exit;
413
414 nfinger = compute_movement(&abs_x, &abs_y,
415 &rel_x, &rel_y,
416 &pressure, &width,
417 &dev->cfg,
418 dev->tp_data, dev->tp_urb->actual_length);
419
420 if (debug > 1) {
421 printk(KERN_DEBUG "bcm5974: x: %04d y: %04d "
422 "dx: %3d dy: %3d p: %3d w: %3d\n",
423 abs_x, abs_y, rel_x, rel_y, pressure, width);
424 }
425
426 input_report_abs(dev->input, ABS_X, abs_x);
427 input_report_abs(dev->input, ABS_Y, abs_y);
428 input_report_abs(dev->input, ABS_PRESSURE, pressure);
429 input_report_abs(dev->input, ABS_TOOL_WIDTH, width);
430 input_report_key(dev->input, BTN_TOOL_FINGER, nfinger == 1);
431 input_report_key(dev->input, BTN_TOOL_DOUBLETAP, nfinger == 2);
432 input_report_key(dev->input, BTN_TOOL_TRIPLETAP, nfinger > 2);
433 input_sync(dev->input);
434
435 exit:
436 retval = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
437 if (retval)
438 err("bcm5974: trackpad urb failed: %d", retval);
439}
440
441static int atp_open(struct input_dev *input)
442{
443 struct atp *dev = input_get_drvdata(input);
444
445 if (!dev->open) {
446 if (usb_submit_urb(dev->bt_urb, GFP_ATOMIC))
447 goto error;
448 if (usb_submit_urb(dev->tp_urb, GFP_ATOMIC))
449 goto err_free_bt_urb;
450 }
451
452 dev->open = 1;
453 dev->suspended = 0;
454 dev->tp_valid = 0;
455
456 return 0;
457
458 err_free_bt_urb:
459 usb_free_urb(dev->bt_urb);
460 error:
461 return -EIO;
462}
463
464static void atp_close(struct input_dev *input)
465{
466 struct atp *dev = input_get_drvdata(input);
467
468 if (dev->open && !dev->suspended) {
469 usb_kill_urb(dev->tp_urb);
470 usb_kill_urb(dev->bt_urb);
471 }
472
473 dev->open = 0;
474 dev->suspended = 0;
475}
476
477static int atp_probe(struct usb_interface *iface,
478 const struct usb_device_id *id)
479{
480 int error = -ENOMEM;
481 struct usb_device *udev = interface_to_usbdev(iface);
482 const struct atp_config_t *cfg;
483 struct atp *dev;
484 struct input_dev *input_dev;
485
486 printk(KERN_INFO "bcm5974: Probing device...\n");
487
488 /* find the product index */
489 cfg = atp_product_config(udev);
490
491 /* allocate memory for our device state and initialize it */
492 dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
493 input_dev = input_allocate_device();
494 if (!dev || !input_dev) {
495 err("Out of memory");
496 goto err_free_devs;
497 }
498
499 dev->udev = udev;
500 dev->input = input_dev;
501 dev->cfg = *cfg;
502
503 /* switch to raw sensor mode */
504 if (atp_wellspring_init(udev))
505 goto err_free_devs;
506
507 dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
508 if (!dev->bt_urb)
509 goto err_free_devs;
510
511 dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
512 if (!dev->tp_urb)
513 goto err_free_bt_urb;
514
515 dev->bt_data = usb_buffer_alloc(dev->udev,
516 dev->cfg.bt_datalen,
517 GFP_KERNEL,
518 &dev->bt_urb->transfer_dma);
519 if (!dev->bt_data)
520 goto err_free_urb;
521
522 dev->tp_data = usb_buffer_alloc(dev->udev,
523 dev->cfg.tp_datalen,
524 GFP_KERNEL,
525 &dev->tp_urb->transfer_dma);
526 if (!dev->tp_data)
527 goto err_free_bt_buffer;
528
529 usb_fill_int_urb(dev->bt_urb, udev,
530 usb_rcvintpipe(udev, cfg->bt_ep),
531 dev->bt_data, dev->cfg.bt_datalen,
532 atp_button, dev, 1);
533
534 usb_fill_int_urb(dev->tp_urb, udev,
535 usb_rcvintpipe(udev, cfg->tp_ep),
536 dev->tp_data, dev->cfg.tp_datalen,
537 atp_trackpad, dev, 1);
538
539 usb_make_path(udev, dev->phys, sizeof(dev->phys));
540 strlcat(dev->phys, "/input0", sizeof(dev->phys));
541
542 input_dev->name = "bcm5974";
543 input_dev->phys = dev->phys;
544 usb_to_input_id(dev->udev, &input_dev->id);
545 input_dev->dev.parent = &iface->dev;
546
547 input_set_drvdata(input_dev, dev);
548
549 input_dev->open = atp_open;
550 input_dev->close = atp_close;
551
552 set_bit(EV_ABS, input_dev->evbit);
553 input_set_abs_params(input_dev, ABS_X,
554 cfg->x.min, cfg->x.max, cfg->x.fuzz, cfg->x.flat);
555 input_set_abs_params(input_dev, ABS_Y,
556 cfg->y.min, cfg->y.max, cfg->y.fuzz, cfg->y.flat);
557 input_set_abs_params(input_dev, ABS_PRESSURE,
558 cfg->p.min, cfg->p.max, cfg->p.fuzz, cfg->p.flat);
559 input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
560 cfg->w.min, cfg->w.max, cfg->w.fuzz, cfg->w.flat);
561
562 set_bit(EV_KEY, input_dev->evbit);
563 set_bit(BTN_TOOL_FINGER, input_dev->keybit);
564 set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
565 set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
566 set_bit(BTN_LEFT, input_dev->keybit);
567
568 error = input_register_device(dev->input);
569 if (error)
570 goto err_free_buffer;
571
572 /* save our data pointer in this interface device */
573 usb_set_intfdata(iface, dev);
574
575 return 0;
576
577 err_free_buffer:
578 usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
579 dev->tp_data, dev->tp_urb->transfer_dma);
580 err_free_bt_buffer:
581 usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
582 dev->bt_data, dev->bt_urb->transfer_dma);
583 err_free_urb:
584 usb_free_urb(dev->tp_urb);
585 err_free_bt_urb:
586 usb_free_urb(dev->bt_urb);
587 err_free_devs:
588 usb_set_intfdata(iface, NULL);
589 kfree(dev);
590 input_free_device(input_dev);
591 return error;
592}
593
594static void atp_disconnect(struct usb_interface *iface)
595{
596 struct atp *dev = usb_get_intfdata(iface);
597
598 usb_set_intfdata(iface, NULL);
599 if (dev) {
600 input_unregister_device(dev->input);
601 usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
602 dev->tp_data, dev->tp_urb->transfer_dma);
603 usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
604 dev->bt_data, dev->bt_urb->transfer_dma);
605 usb_free_urb(dev->tp_urb);
606 usb_free_urb(dev->bt_urb);
607 kfree(dev);
608 }
609 printk(KERN_INFO "bcm5974: disconnected\n");
610}
611
612static int atp_suspend(struct usb_interface *iface, pm_message_t message)
613{
614 struct atp *dev = usb_get_intfdata(iface);
615
616 if (dev->open && !dev->suspended++) {
617 usb_kill_urb(dev->tp_urb);
618 usb_kill_urb(dev->bt_urb);
619 }
620
621 return 0;
622}
623
624static int atp_resume(struct usb_interface *iface)
625{
626 struct atp *dev = usb_get_intfdata(iface);
627
628 if (dev->open && !--dev->suspended) {
629 if (usb_submit_urb(dev->bt_urb, GFP_ATOMIC))
630 goto error;
631 if (usb_submit_urb(dev->tp_urb, GFP_ATOMIC))
632 goto err_free_bt_urb;
633 }
634
635 dev->tp_valid = 0;
636 return 0;
637
638 err_free_bt_urb:
639 usb_free_urb(dev->bt_urb);
640 error:
641 return -EIO;
642}
643
644static int atp_reset_resume(struct usb_interface *iface)
645{
646 struct atp *dev = usb_get_intfdata(iface);
647
648 if (dev->suspended == 1) {
649 if (atp_wellspring_init(dev->udev))
650 printk(KERN_INFO "bcm5974: warning: reset failed\n");
651 }
652
653 return atp_resume(iface);
654}
655
656static int atp_pre_reset(struct usb_interface *iface)
657{
658 return atp_suspend(iface, PMSG_ON);
659}
660
661static int atp_post_reset(struct usb_interface *iface)
662{
663 return atp_reset_resume(iface);
664}
665
666static struct usb_driver atp_driver = {
667 .name = "bcm5974",
668 .probe = atp_probe,
669 .disconnect = atp_disconnect,
670 .suspend = atp_suspend,
671 .resume = atp_resume,
672 .reset_resume = atp_reset_resume,
673 .pre_reset = atp_pre_reset,
674 .post_reset = atp_post_reset,
675 .id_table = atp_table,
676};
677
678static int __init atp_init(void)
679{
680 return usb_register(&atp_driver);
681}
682
683static void __exit atp_exit(void)
684{
685 usb_deregister(&atp_driver);
686}
687
688module_init(atp_init);
689module_exit(atp_exit);