blob: 8e80348191bbab4d9f1ffac9a7bd4fa5c9b44f55 [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
83 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
84
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
96 dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
97 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070098
Jack Pham3ae820f2011-12-14 16:21:04 -080099 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -0800100 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Phamcca03322012-06-14 19:00:31 -0700101 /* save error so that subsequent read/write returns ENODEV */
Jack Pham3ae820f2011-12-14 16:21:04 -0800102 dev->err = urb->status;
Jack Pham76e61dd2012-06-14 18:48:53 -0700103 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3ae820f2011-12-14 16:21:04 -0800104 return;
105 }
106
Vamsi Krishna90125642012-05-12 16:06:13 -0700107 if (cbs && cbs->read_complete_cb)
108 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700109 urb->transfer_buffer,
110 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700111 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800112
113 dev->bytes_to_host += urb->actual_length;
114 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700115 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700116}
117
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800118int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700119{
120 struct urb *urb = NULL;
121 unsigned int pipe;
122 struct diag_bridge *dev = __dev;
123 int ret;
124
Jack Pham76e61dd2012-06-14 18:48:53 -0700125 pr_debug("reading %d bytes", size);
126
127 if (!dev || !dev->ifc) {
128 pr_err("device is disconnected");
129 return -ENODEV;
130 }
131
132 if (!dev->ops) {
133 pr_err("bridge is not open");
134 return -ENODEV;
135 }
Jack Phame32cf322011-09-26 10:20:17 -0700136
137 if (!size) {
138 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
139 return -EINVAL;
140 }
141
Jack Pham3ae820f2011-12-14 16:21:04 -0800142 /* if there was a previous unrecoverable error, just quit */
143 if (dev->err)
Jack Phamcca03322012-06-14 19:00:31 -0700144 return -ENODEV;
Jack Pham3ae820f2011-12-14 16:21:04 -0800145
Jack Pham76e61dd2012-06-14 18:48:53 -0700146 kref_get(&dev->kref);
147
Jack Phamb60775a2012-02-14 17:57:41 -0800148 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700149 if (!urb) {
150 dev_err(&dev->udev->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700151 ret = -ENOMEM;
152 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700153 }
154
Jack Phamb60775a2012-02-14 17:57:41 -0800155 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700156 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
157 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700158 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800159 }
160
Jack Phame32cf322011-09-26 10:20:17 -0700161 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
162 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700163 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700164 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800165 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700166
Jack Phamb60775a2012-02-14 17:57:41 -0800167 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700168 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700169 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800170 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700171 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700172 }
Jack Phamb60775a2012-02-14 17:57:41 -0800173 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700174
Jack Pham76e61dd2012-06-14 18:48:53 -0700175free_error:
176 usb_free_urb(urb);
177error:
178 if (ret) /* otherwise this is done in the completion handler */
179 kref_put(&dev->kref, diag_bridge_delete);
180 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700181}
Jack Phamf6ed5582011-11-02 16:08:31 -0700182EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700183
Jack Phamf6ed5582011-11-02 16:08:31 -0700184static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700185{
186 struct diag_bridge *dev = urb->context;
187 struct diag_bridge_ops *cbs = dev->ops;
188
189 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
190
Jack Phamb60775a2012-02-14 17:57:41 -0800191 usb_autopm_put_interface_async(dev->ifc);
192
Jack Pham3ae820f2011-12-14 16:21:04 -0800193 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -0800194 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Phamcca03322012-06-14 19:00:31 -0700195 /* save error so that subsequent read/write returns ENODEV */
Jack Pham3ae820f2011-12-14 16:21:04 -0800196 dev->err = urb->status;
Jack Pham76e61dd2012-06-14 18:48:53 -0700197 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3ae820f2011-12-14 16:21:04 -0800198 return;
199 }
200
Vamsi Krishna90125642012-05-12 16:06:13 -0700201 if (cbs && cbs->write_complete_cb)
202 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700203 urb->transfer_buffer,
204 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700205 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800206
207 dev->bytes_to_mdm += urb->actual_length;
208 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700209 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700210}
211
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800212int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700213{
214 struct urb *urb = NULL;
215 unsigned int pipe;
216 struct diag_bridge *dev = __dev;
217 int ret;
218
Jack Pham76e61dd2012-06-14 18:48:53 -0700219 pr_debug("writing %d bytes", size);
220
221 if (!dev || !dev->ifc) {
222 pr_err("device is disconnected");
223 return -ENODEV;
224 }
225
226 if (!dev->ops) {
227 pr_err("bridge is not open");
228 return -ENODEV;
229 }
Jack Phame32cf322011-09-26 10:20:17 -0700230
231 if (!size) {
232 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
233 return -EINVAL;
234 }
235
Jack Pham3ae820f2011-12-14 16:21:04 -0800236 /* if there was a previous unrecoverable error, just quit */
237 if (dev->err)
Jack Phamcca03322012-06-14 19:00:31 -0700238 return -ENODEV;
Jack Pham3ae820f2011-12-14 16:21:04 -0800239
Jack Pham76e61dd2012-06-14 18:48:53 -0700240 kref_get(&dev->kref);
241
Jack Phamb60775a2012-02-14 17:57:41 -0800242 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700243 if (!urb) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700244 dev_err(&dev->udev->dev, "unable to allocate urb\n");
245 ret = -ENOMEM;
246 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700247 }
248
Jack Phamb60775a2012-02-14 17:57:41 -0800249 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700250 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
251 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700252 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800253 }
254
Jack Phame32cf322011-09-26 10:20:17 -0700255 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
256 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700257 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700258 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800259 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700260
Jack Phamb60775a2012-02-14 17:57:41 -0800261 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700262 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700263 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800264 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700265 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800266 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700267 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700268 }
269
Jack Pham76e61dd2012-06-14 18:48:53 -0700270free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700271 usb_free_urb(urb);
Jack Pham76e61dd2012-06-14 18:48:53 -0700272error:
273 if (ret) /* otherwise this is done in the completion handler */
274 kref_put(&dev->kref, diag_bridge_delete);
275 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700276}
Jack Phamf6ed5582011-11-02 16:08:31 -0700277EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700278
Jack Pham9a08de42012-02-06 15:43:23 -0800279#if defined(CONFIG_DEBUG_FS)
280#define DEBUG_BUF_SIZE 512
281static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
282 size_t count, loff_t *ppos)
283{
284 struct diag_bridge *dev = __dev;
285 char *buf;
286 int ret;
287
Jack Pham76e61dd2012-06-14 18:48:53 -0700288 if (!dev)
289 return -ENODEV;
290
Jack Pham9a08de42012-02-06 15:43:23 -0800291 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
292 if (!buf)
293 return -ENOMEM;
294
295 ret = scnprintf(buf, DEBUG_BUF_SIZE,
296 "epin:%d, epout:%d\n"
297 "bytes to host: %lu\n"
298 "bytes to mdm: %lu\n"
299 "pending reads: %u\n"
300 "pending writes: %u\n"
301 "last error: %d\n",
302 dev->in_epAddr, dev->out_epAddr,
303 dev->bytes_to_host, dev->bytes_to_mdm,
304 dev->pending_reads, dev->pending_writes,
305 dev->err);
306
307 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
308 kfree(buf);
309 return ret;
310}
311
312static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
313 size_t count, loff_t *ppos)
314{
315 struct diag_bridge *dev = __dev;
316
Jack Pham76e61dd2012-06-14 18:48:53 -0700317 if (dev) {
318 dev->bytes_to_host = dev->bytes_to_mdm = 0;
319 dev->pending_reads = dev->pending_writes = 0;
320 }
Jack Pham9a08de42012-02-06 15:43:23 -0800321
322 return count;
323}
324
325const struct file_operations diag_stats_ops = {
326 .read = diag_read_stats,
327 .write = diag_reset_stats,
328};
329
330static struct dentry *dent;
331
332static void diag_bridge_debugfs_init(void)
333{
334 struct dentry *dfile;
335
336 dent = debugfs_create_dir("diag_bridge", 0);
337 if (IS_ERR(dent))
338 return;
339
340 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
341 if (!dfile || IS_ERR(dfile))
342 debugfs_remove(dent);
343}
344
345static void diag_bridge_debugfs_cleanup(void)
346{
347 if (dent) {
348 debugfs_remove_recursive(dent);
349 dent = NULL;
350 }
351}
352#else
353static inline void diag_bridge_debugfs_init(void) { }
354static inline void diag_bridge_debugfs_cleanup(void) { }
355#endif
356
Jack Phame32cf322011-09-26 10:20:17 -0700357static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700358diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700359{
360 struct diag_bridge *dev;
361 struct usb_host_interface *ifc_desc;
362 struct usb_endpoint_descriptor *ep_desc;
363 int i;
364 int ret = -ENOMEM;
365 __u8 ifc_num;
366
Jack Pham76e61dd2012-06-14 18:48:53 -0700367 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700368
369 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
370
371 /* is this interface supported ? */
372 if (ifc_num != id->driver_info)
373 return -ENODEV;
374
375 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
376 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700377 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700378 return -ENOMEM;
379 }
380 dev->pdev = platform_device_alloc("diag_bridge", -1);
381 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700382 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700383 kfree(dev);
384 return -ENOMEM;
385 }
386 __dev = dev;
387
388 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
389 dev->ifc = ifc;
390 kref_init(&dev->kref);
391 init_usb_anchor(&dev->submitted);
392
393 ifc_desc = ifc->cur_altsetting;
394 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
395 ep_desc = &ifc_desc->endpoint[i].desc;
396
397 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
398 dev->in_epAddr = ep_desc->bEndpointAddress;
399
400 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
401 dev->out_epAddr = ep_desc->bEndpointAddress;
402 }
403
404 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700405 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700406 ret = -ENODEV;
407 goto error;
408 }
409
410 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800411 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700412 platform_device_add(dev->pdev);
413
414 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
415
416 return 0;
417
418error:
419 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700420 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700421
422 return ret;
423}
424
Jack Phamf6ed5582011-11-02 16:08:31 -0700425static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700426{
427 struct diag_bridge *dev = usb_get_intfdata(ifc);
428
429 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
430
431 platform_device_del(dev->pdev);
Jack Pham76e61dd2012-06-14 18:48:53 -0700432 dev->ifc = NULL;
Jack Pham9a08de42012-02-06 15:43:23 -0800433 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700434 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700435 usb_set_intfdata(ifc, NULL);
436}
437
Jack Phamb60775a2012-02-14 17:57:41 -0800438static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
439{
440 struct diag_bridge *dev = usb_get_intfdata(ifc);
441 struct diag_bridge_ops *cbs = dev->ops;
442 int ret = 0;
443
444 if (cbs && cbs->suspend) {
445 ret = cbs->suspend(cbs->ctxt);
446 if (ret) {
447 dev_dbg(&dev->udev->dev,
448 "%s: diag veto'd suspend\n", __func__);
449 return ret;
450 }
451
452 usb_kill_anchored_urbs(&dev->submitted);
453 }
454
455 return ret;
456}
457
458static int diag_bridge_resume(struct usb_interface *ifc)
459{
460 struct diag_bridge *dev = usb_get_intfdata(ifc);
461 struct diag_bridge_ops *cbs = dev->ops;
462
463
464 if (cbs && cbs->resume)
465 cbs->resume(cbs->ctxt);
466
467 return 0;
468}
Jack Phame32cf322011-09-26 10:20:17 -0700469
470#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700471static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800472 { USB_DEVICE(0x5c6, 0x9001),
473 .driver_info = VALID_INTERFACE_NUM, },
474 { USB_DEVICE(0x5c6, 0x9034),
475 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800476 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700477 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800478 { USB_DEVICE(0x5c6, 0x904C),
479 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700480
481 {} /* terminating entry */
482};
Jack Phamf6ed5582011-11-02 16:08:31 -0700483MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700484
Jack Phamf6ed5582011-11-02 16:08:31 -0700485static struct usb_driver diag_bridge_driver = {
486 .name = "diag_bridge",
487 .probe = diag_bridge_probe,
488 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800489 .suspend = diag_bridge_suspend,
490 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700491 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800492 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700493};
494
Jack Phamf6ed5582011-11-02 16:08:31 -0700495static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700496{
497 int ret;
498
Jack Phamf6ed5582011-11-02 16:08:31 -0700499 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700500 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700501 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700502 return ret;
503 }
504
505 return 0;
506}
507
Jack Phamf6ed5582011-11-02 16:08:31 -0700508static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700509{
Jack Phamf6ed5582011-11-02 16:08:31 -0700510 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700511}
512
Jack Phamf6ed5582011-11-02 16:08:31 -0700513module_init(diag_bridge_init);
514module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700515
516MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700517MODULE_VERSION(DRIVER_VERSION);
518MODULE_LICENSE("GPL v2");