blob: ba7658b2287bdb160aad39e168d026a1494ad87e [file] [log] [blame]
Jack Phame32cf322011-09-26 10:20:17 -07001/*
Hemant Kumar7a067f12012-01-05 15:35:15 -08002 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Jack Phame32cf322011-09-26 10:20:17 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
Jack Pham76e61dd2012-06-14 18:48:53 -070014/* add additional information to our printk's */
15#define pr_fmt(fmt) "%s: " fmt "\n", __func__
16
Jack Phame32cf322011-09-26 10:20:17 -070017#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/module.h>
22#include <linux/kref.h>
23#include <linux/platform_device.h>
Jack Phamcca03322012-06-14 19:00:31 -070024#include <linux/ratelimit.h>
Jack Phame32cf322011-09-26 10:20:17 -070025#include <linux/uaccess.h>
26#include <linux/usb.h>
Jack Pham9a08de42012-02-06 15:43:23 -080027#include <linux/debugfs.h>
Jack Phame32cf322011-09-26 10:20:17 -070028#include <mach/diag_bridge.h>
29
30#define DRIVER_DESC "USB host diag bridge driver"
Jack Phamf6ed5582011-11-02 16:08:31 -070031#define DRIVER_VERSION "1.0"
Jack Phame32cf322011-09-26 10:20:17 -070032
33struct diag_bridge {
34 struct usb_device *udev;
35 struct usb_interface *ifc;
36 struct usb_anchor submitted;
37 __u8 in_epAddr;
38 __u8 out_epAddr;
Jack Pham3ae820f2011-12-14 16:21:04 -080039 int err;
Jack Phame32cf322011-09-26 10:20:17 -070040 struct kref kref;
41 struct diag_bridge_ops *ops;
42 struct platform_device *pdev;
Jack Pham9a08de42012-02-06 15:43:23 -080043
44 /* debugging counters */
45 unsigned long bytes_to_host;
46 unsigned long bytes_to_mdm;
47 unsigned pending_reads;
48 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070049};
50struct diag_bridge *__dev;
51
Jack Phamf6ed5582011-11-02 16:08:31 -070052int diag_bridge_open(struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070053{
54 struct diag_bridge *dev = __dev;
55
56 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -070057 pr_err("dev is null");
Jack Phame32cf322011-09-26 10:20:17 -070058 return -ENODEV;
59 }
60
61 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080062 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070063
Jack Pham76e61dd2012-06-14 18:48:53 -070064 kref_get(&dev->kref);
65
Jack Phame32cf322011-09-26 10:20:17 -070066 return 0;
67}
Jack Phamf6ed5582011-11-02 16:08:31 -070068EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070069
Jack Pham76e61dd2012-06-14 18:48:53 -070070static void diag_bridge_delete(struct kref *kref)
71{
72 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
73
74 usb_put_dev(dev->udev);
75 __dev = 0;
76 kfree(dev);
77}
78
Jack Phamf6ed5582011-11-02 16:08:31 -070079void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070080{
81 struct diag_bridge *dev = __dev;
82
Jack Phame8741502012-06-13 17:34:07 -070083 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -070084
85 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -070086 dev->ops = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -070087 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -070088}
Jack Phamf6ed5582011-11-02 16:08:31 -070089EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -070090
Jack Phamf6ed5582011-11-02 16:08:31 -070091static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -070092{
93 struct diag_bridge *dev = urb->context;
94 struct diag_bridge_ops *cbs = dev->ops;
95
Jack Phame8741502012-06-13 17:34:07 -070096 dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
Jack Phame32cf322011-09-26 10:20:17 -070097 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070098
Jack Pham3ec42b62012-08-31 15:36:27 -070099 /* save error so that subsequent read/write returns ENODEV */
100 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800101 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800102
Vamsi Krishna90125642012-05-12 16:06:13 -0700103 if (cbs && cbs->read_complete_cb)
104 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700105 urb->transfer_buffer,
106 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700107 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800108
109 dev->bytes_to_host += urb->actual_length;
110 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700111 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700112}
113
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800114int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700115{
116 struct urb *urb = NULL;
117 unsigned int pipe;
118 struct diag_bridge *dev = __dev;
119 int ret;
120
Jack Pham76e61dd2012-06-14 18:48:53 -0700121 pr_debug("reading %d bytes", size);
122
123 if (!dev || !dev->ifc) {
124 pr_err("device is disconnected");
125 return -ENODEV;
126 }
127
128 if (!dev->ops) {
129 pr_err("bridge is not open");
130 return -ENODEV;
131 }
Jack Phame32cf322011-09-26 10:20:17 -0700132
133 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700134 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phame32cf322011-09-26 10:20:17 -0700135 return -EINVAL;
136 }
137
Jack Pham3ae820f2011-12-14 16:21:04 -0800138 /* if there was a previous unrecoverable error, just quit */
139 if (dev->err)
Jack Phamcca03322012-06-14 19:00:31 -0700140 return -ENODEV;
Jack Pham3ae820f2011-12-14 16:21:04 -0800141
Jack Pham76e61dd2012-06-14 18:48:53 -0700142 kref_get(&dev->kref);
143
Jack Phamb60775a2012-02-14 17:57:41 -0800144 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700145 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700146 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700147 ret = -ENOMEM;
148 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700149 }
150
Jack Phamb60775a2012-02-14 17:57:41 -0800151 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700152 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
153 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700154 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800155 }
156
Jack Phame32cf322011-09-26 10:20:17 -0700157 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
158 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700159 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700160 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800161 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700162
Jack Phamb60775a2012-02-14 17:57:41 -0800163 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700164 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700165 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800166 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700167 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700168 }
Jack Phamb60775a2012-02-14 17:57:41 -0800169 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700170
Jack Pham76e61dd2012-06-14 18:48:53 -0700171free_error:
172 usb_free_urb(urb);
173error:
174 if (ret) /* otherwise this is done in the completion handler */
175 kref_put(&dev->kref, diag_bridge_delete);
176 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700177}
Jack Phamf6ed5582011-11-02 16:08:31 -0700178EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700179
Jack Phamf6ed5582011-11-02 16:08:31 -0700180static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700181{
182 struct diag_bridge *dev = urb->context;
183 struct diag_bridge_ops *cbs = dev->ops;
184
Jack Phame8741502012-06-13 17:34:07 -0700185 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700186
Jack Phamb60775a2012-02-14 17:57:41 -0800187 usb_autopm_put_interface_async(dev->ifc);
188
Jack Pham3ec42b62012-08-31 15:36:27 -0700189 /* save error so that subsequent read/write returns ENODEV */
190 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800191 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800192
Vamsi Krishna90125642012-05-12 16:06:13 -0700193 if (cbs && cbs->write_complete_cb)
194 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700195 urb->transfer_buffer,
196 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700197 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800198
199 dev->bytes_to_mdm += urb->actual_length;
200 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700201 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700202}
203
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800204int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700205{
206 struct urb *urb = NULL;
207 unsigned int pipe;
208 struct diag_bridge *dev = __dev;
209 int ret;
210
Jack Pham76e61dd2012-06-14 18:48:53 -0700211 pr_debug("writing %d bytes", size);
212
213 if (!dev || !dev->ifc) {
214 pr_err("device is disconnected");
215 return -ENODEV;
216 }
217
218 if (!dev->ops) {
219 pr_err("bridge is not open");
220 return -ENODEV;
221 }
Jack Phame32cf322011-09-26 10:20:17 -0700222
223 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700224 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phame32cf322011-09-26 10:20:17 -0700225 return -EINVAL;
226 }
227
Jack Pham3ae820f2011-12-14 16:21:04 -0800228 /* if there was a previous unrecoverable error, just quit */
229 if (dev->err)
Jack Phamcca03322012-06-14 19:00:31 -0700230 return -ENODEV;
Jack Pham3ae820f2011-12-14 16:21:04 -0800231
Jack Pham76e61dd2012-06-14 18:48:53 -0700232 kref_get(&dev->kref);
233
Jack Phamb60775a2012-02-14 17:57:41 -0800234 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700235 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700236 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700237 ret = -ENOMEM;
238 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700239 }
240
Jack Phamb60775a2012-02-14 17:57:41 -0800241 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700242 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
243 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700244 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800245 }
246
Jack Phame32cf322011-09-26 10:20:17 -0700247 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
248 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700249 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700250 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700251 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800252 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700253
Jack Phamb60775a2012-02-14 17:57:41 -0800254 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700255 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700256 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800257 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700258 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800259 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700260 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700261 }
262
Jack Pham76e61dd2012-06-14 18:48:53 -0700263free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700264 usb_free_urb(urb);
Jack Pham76e61dd2012-06-14 18:48:53 -0700265error:
266 if (ret) /* otherwise this is done in the completion handler */
267 kref_put(&dev->kref, diag_bridge_delete);
268 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700269}
Jack Phamf6ed5582011-11-02 16:08:31 -0700270EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700271
Jack Pham9a08de42012-02-06 15:43:23 -0800272#if defined(CONFIG_DEBUG_FS)
273#define DEBUG_BUF_SIZE 512
274static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
275 size_t count, loff_t *ppos)
276{
277 struct diag_bridge *dev = __dev;
278 char *buf;
279 int ret;
280
Jack Pham76e61dd2012-06-14 18:48:53 -0700281 if (!dev)
282 return -ENODEV;
283
Jack Pham9a08de42012-02-06 15:43:23 -0800284 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
285 if (!buf)
286 return -ENOMEM;
287
288 ret = scnprintf(buf, DEBUG_BUF_SIZE,
289 "epin:%d, epout:%d\n"
290 "bytes to host: %lu\n"
291 "bytes to mdm: %lu\n"
292 "pending reads: %u\n"
293 "pending writes: %u\n"
294 "last error: %d\n",
295 dev->in_epAddr, dev->out_epAddr,
296 dev->bytes_to_host, dev->bytes_to_mdm,
297 dev->pending_reads, dev->pending_writes,
298 dev->err);
299
300 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
301 kfree(buf);
302 return ret;
303}
304
305static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
306 size_t count, loff_t *ppos)
307{
308 struct diag_bridge *dev = __dev;
309
Jack Pham76e61dd2012-06-14 18:48:53 -0700310 if (dev) {
311 dev->bytes_to_host = dev->bytes_to_mdm = 0;
312 dev->pending_reads = dev->pending_writes = 0;
313 }
Jack Pham9a08de42012-02-06 15:43:23 -0800314
315 return count;
316}
317
318const struct file_operations diag_stats_ops = {
319 .read = diag_read_stats,
320 .write = diag_reset_stats,
321};
322
323static struct dentry *dent;
324
325static void diag_bridge_debugfs_init(void)
326{
327 struct dentry *dfile;
328
329 dent = debugfs_create_dir("diag_bridge", 0);
330 if (IS_ERR(dent))
331 return;
332
333 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
334 if (!dfile || IS_ERR(dfile))
335 debugfs_remove(dent);
336}
337
338static void diag_bridge_debugfs_cleanup(void)
339{
340 if (dent) {
341 debugfs_remove_recursive(dent);
342 dent = NULL;
343 }
344}
345#else
346static inline void diag_bridge_debugfs_init(void) { }
347static inline void diag_bridge_debugfs_cleanup(void) { }
348#endif
349
Jack Phame32cf322011-09-26 10:20:17 -0700350static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700351diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700352{
353 struct diag_bridge *dev;
354 struct usb_host_interface *ifc_desc;
355 struct usb_endpoint_descriptor *ep_desc;
356 int i;
357 int ret = -ENOMEM;
358 __u8 ifc_num;
359
Jack Pham76e61dd2012-06-14 18:48:53 -0700360 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700361
362 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
363
364 /* is this interface supported ? */
365 if (ifc_num != id->driver_info)
366 return -ENODEV;
367
368 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
369 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700370 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700371 return -ENOMEM;
372 }
373 dev->pdev = platform_device_alloc("diag_bridge", -1);
374 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700375 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700376 kfree(dev);
377 return -ENOMEM;
378 }
379 __dev = dev;
380
381 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
382 dev->ifc = ifc;
383 kref_init(&dev->kref);
384 init_usb_anchor(&dev->submitted);
385
386 ifc_desc = ifc->cur_altsetting;
387 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
388 ep_desc = &ifc_desc->endpoint[i].desc;
389
390 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
391 dev->in_epAddr = ep_desc->bEndpointAddress;
392
393 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
394 dev->out_epAddr = ep_desc->bEndpointAddress;
395 }
396
397 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700398 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700399 ret = -ENODEV;
400 goto error;
401 }
402
403 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800404 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700405 platform_device_add(dev->pdev);
406
Jack Phame8741502012-06-13 17:34:07 -0700407 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700408
409 return 0;
410
411error:
412 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700413 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700414
415 return ret;
416}
417
Jack Phamf6ed5582011-11-02 16:08:31 -0700418static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700419{
420 struct diag_bridge *dev = usb_get_intfdata(ifc);
421
Jack Phame8741502012-06-13 17:34:07 -0700422 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700423
Jack Pham1b1ba472012-06-13 16:40:15 -0700424 platform_device_unregister(dev->pdev);
Jack Pham76e61dd2012-06-14 18:48:53 -0700425 dev->ifc = NULL;
Jack Pham9a08de42012-02-06 15:43:23 -0800426 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700427 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700428 usb_set_intfdata(ifc, NULL);
429}
430
Jack Phamb60775a2012-02-14 17:57:41 -0800431static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
432{
433 struct diag_bridge *dev = usb_get_intfdata(ifc);
434 struct diag_bridge_ops *cbs = dev->ops;
435 int ret = 0;
436
437 if (cbs && cbs->suspend) {
438 ret = cbs->suspend(cbs->ctxt);
439 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700440 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800441 "%s: diag veto'd suspend\n", __func__);
442 return ret;
443 }
444
445 usb_kill_anchored_urbs(&dev->submitted);
446 }
447
448 return ret;
449}
450
451static int diag_bridge_resume(struct usb_interface *ifc)
452{
453 struct diag_bridge *dev = usb_get_intfdata(ifc);
454 struct diag_bridge_ops *cbs = dev->ops;
455
456
457 if (cbs && cbs->resume)
458 cbs->resume(cbs->ctxt);
459
460 return 0;
461}
Jack Phame32cf322011-09-26 10:20:17 -0700462
463#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700464static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800465 { USB_DEVICE(0x5c6, 0x9001),
466 .driver_info = VALID_INTERFACE_NUM, },
467 { USB_DEVICE(0x5c6, 0x9034),
468 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800469 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700470 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800471 { USB_DEVICE(0x5c6, 0x904C),
472 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700473
474 {} /* terminating entry */
475};
Jack Phamf6ed5582011-11-02 16:08:31 -0700476MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700477
Jack Phamf6ed5582011-11-02 16:08:31 -0700478static struct usb_driver diag_bridge_driver = {
479 .name = "diag_bridge",
480 .probe = diag_bridge_probe,
481 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800482 .suspend = diag_bridge_suspend,
483 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700484 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800485 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700486};
487
Jack Phamf6ed5582011-11-02 16:08:31 -0700488static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700489{
490 int ret;
491
Jack Phamf6ed5582011-11-02 16:08:31 -0700492 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700493 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700494 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700495 return ret;
496 }
497
498 return 0;
499}
500
Jack Phamf6ed5582011-11-02 16:08:31 -0700501static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700502{
Jack Phamf6ed5582011-11-02 16:08:31 -0700503 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700504}
505
Jack Phamf6ed5582011-11-02 16:08:31 -0700506module_init(diag_bridge_init);
507module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700508
509MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700510MODULE_VERSION(DRIVER_VERSION);
511MODULE_LICENSE("GPL v2");