blob: 8e7bacfb9011e673b9ea6ded3a70bdeefb0484b2 [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>
24#include <linux/uaccess.h>
25#include <linux/usb.h>
Jack Pham9a08de42012-02-06 15:43:23 -080026#include <linux/debugfs.h>
Jack Phame32cf322011-09-26 10:20:17 -070027#include <mach/diag_bridge.h>
28
29#define DRIVER_DESC "USB host diag bridge driver"
Jack Phamf6ed5582011-11-02 16:08:31 -070030#define DRIVER_VERSION "1.0"
Jack Phame32cf322011-09-26 10:20:17 -070031
32struct diag_bridge {
33 struct usb_device *udev;
34 struct usb_interface *ifc;
35 struct usb_anchor submitted;
36 __u8 in_epAddr;
37 __u8 out_epAddr;
Jack Pham3ae820f2011-12-14 16:21:04 -080038 int err;
Jack Phame32cf322011-09-26 10:20:17 -070039 struct kref kref;
40 struct diag_bridge_ops *ops;
41 struct platform_device *pdev;
Jack Pham9a08de42012-02-06 15:43:23 -080042
43 /* debugging counters */
44 unsigned long bytes_to_host;
45 unsigned long bytes_to_mdm;
46 unsigned pending_reads;
47 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070048};
49struct diag_bridge *__dev;
50
Jack Phamf6ed5582011-11-02 16:08:31 -070051int diag_bridge_open(struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070052{
53 struct diag_bridge *dev = __dev;
54
55 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -070056 pr_err("dev is null");
Jack Phame32cf322011-09-26 10:20:17 -070057 return -ENODEV;
58 }
59
60 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080061 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070062
Jack Pham76e61dd2012-06-14 18:48:53 -070063 kref_get(&dev->kref);
64
Jack Phame32cf322011-09-26 10:20:17 -070065 return 0;
66}
Jack Phamf6ed5582011-11-02 16:08:31 -070067EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070068
Jack Pham76e61dd2012-06-14 18:48:53 -070069static void diag_bridge_delete(struct kref *kref)
70{
71 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
72
73 usb_put_dev(dev->udev);
74 __dev = 0;
75 kfree(dev);
76}
77
Jack Phamf6ed5582011-11-02 16:08:31 -070078void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070079{
80 struct diag_bridge *dev = __dev;
81
82 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
83
84 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -070085 dev->ops = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -070086 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -070087}
Jack Phamf6ed5582011-11-02 16:08:31 -070088EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -070089
Jack Phamf6ed5582011-11-02 16:08:31 -070090static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -070091{
92 struct diag_bridge *dev = urb->context;
93 struct diag_bridge_ops *cbs = dev->ops;
94
95 dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
96 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070097
Jack Pham3ae820f2011-12-14 16:21:04 -080098 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -080099 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Pham3ae820f2011-12-14 16:21:04 -0800100 /* save error so that subsequent read/write returns ESHUTDOWN */
101 dev->err = urb->status;
Jack Pham76e61dd2012-06-14 18:48:53 -0700102 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3ae820f2011-12-14 16:21:04 -0800103 return;
104 }
105
Vamsi Krishna90125642012-05-12 16:06:13 -0700106 if (cbs && cbs->read_complete_cb)
107 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700108 urb->transfer_buffer,
109 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700110 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800111
112 dev->bytes_to_host += urb->actual_length;
113 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700114 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700115}
116
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800117int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700118{
119 struct urb *urb = NULL;
120 unsigned int pipe;
121 struct diag_bridge *dev = __dev;
122 int ret;
123
Jack Pham76e61dd2012-06-14 18:48:53 -0700124 pr_debug("reading %d bytes", size);
125
126 if (!dev || !dev->ifc) {
127 pr_err("device is disconnected");
128 return -ENODEV;
129 }
130
131 if (!dev->ops) {
132 pr_err("bridge is not open");
133 return -ENODEV;
134 }
Jack Phame32cf322011-09-26 10:20:17 -0700135
136 if (!size) {
137 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
138 return -EINVAL;
139 }
140
Jack Pham3ae820f2011-12-14 16:21:04 -0800141 /* if there was a previous unrecoverable error, just quit */
142 if (dev->err)
143 return -ESHUTDOWN;
144
Jack Pham76e61dd2012-06-14 18:48:53 -0700145 kref_get(&dev->kref);
146
Jack Phamb60775a2012-02-14 17:57:41 -0800147 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700148 if (!urb) {
149 dev_err(&dev->udev->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700150 ret = -ENOMEM;
151 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700152 }
153
Jack Phamb60775a2012-02-14 17:57:41 -0800154 ret = usb_autopm_get_interface(dev->ifc);
155 if (ret < 0) {
156 dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700157 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800158 }
159
Jack Phame32cf322011-09-26 10:20:17 -0700160 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
161 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700162 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700163 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800164 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700165
Jack Phamb60775a2012-02-14 17:57:41 -0800166 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700167 if (ret) {
168 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800169 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700170 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700171 }
Jack Phamb60775a2012-02-14 17:57:41 -0800172 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700173
Jack Pham76e61dd2012-06-14 18:48:53 -0700174free_error:
175 usb_free_urb(urb);
176error:
177 if (ret) /* otherwise this is done in the completion handler */
178 kref_put(&dev->kref, diag_bridge_delete);
179 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700180}
Jack Phamf6ed5582011-11-02 16:08:31 -0700181EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700182
Jack Phamf6ed5582011-11-02 16:08:31 -0700183static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700184{
185 struct diag_bridge *dev = urb->context;
186 struct diag_bridge_ops *cbs = dev->ops;
187
188 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
189
Jack Phamb60775a2012-02-14 17:57:41 -0800190 usb_autopm_put_interface_async(dev->ifc);
191
Jack Pham3ae820f2011-12-14 16:21:04 -0800192 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -0800193 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Pham3ae820f2011-12-14 16:21:04 -0800194 /* save error so that subsequent read/write returns ESHUTDOWN */
195 dev->err = urb->status;
Jack Pham76e61dd2012-06-14 18:48:53 -0700196 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3ae820f2011-12-14 16:21:04 -0800197 return;
198 }
199
Vamsi Krishna90125642012-05-12 16:06:13 -0700200 if (cbs && cbs->write_complete_cb)
201 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700202 urb->transfer_buffer,
203 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700204 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800205
206 dev->bytes_to_mdm += urb->actual_length;
207 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700208 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700209}
210
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800211int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700212{
213 struct urb *urb = NULL;
214 unsigned int pipe;
215 struct diag_bridge *dev = __dev;
216 int ret;
217
Jack Pham76e61dd2012-06-14 18:48:53 -0700218 pr_debug("writing %d bytes", size);
219
220 if (!dev || !dev->ifc) {
221 pr_err("device is disconnected");
222 return -ENODEV;
223 }
224
225 if (!dev->ops) {
226 pr_err("bridge is not open");
227 return -ENODEV;
228 }
Jack Phame32cf322011-09-26 10:20:17 -0700229
230 if (!size) {
231 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
232 return -EINVAL;
233 }
234
Jack Pham3ae820f2011-12-14 16:21:04 -0800235 /* if there was a previous unrecoverable error, just quit */
236 if (dev->err)
237 return -ESHUTDOWN;
238
Jack Pham76e61dd2012-06-14 18:48:53 -0700239 kref_get(&dev->kref);
240
Jack Phamb60775a2012-02-14 17:57:41 -0800241 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700242 if (!urb) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700243 dev_err(&dev->udev->dev, "unable to allocate urb\n");
244 ret = -ENOMEM;
245 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700246 }
247
Jack Phamb60775a2012-02-14 17:57:41 -0800248 ret = usb_autopm_get_interface(dev->ifc);
249 if (ret < 0) {
250 dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700251 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800252 }
253
Jack Phame32cf322011-09-26 10:20:17 -0700254 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
255 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700256 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700257 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800258 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700259
Jack Phamb60775a2012-02-14 17:57:41 -0800260 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700261 if (ret) {
Jack Pham9a08de42012-02-06 15:43:23 -0800262 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
263 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700264 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800265 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700266 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700267 }
268
Jack Pham76e61dd2012-06-14 18:48:53 -0700269free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700270 usb_free_urb(urb);
Jack Pham76e61dd2012-06-14 18:48:53 -0700271error:
272 if (ret) /* otherwise this is done in the completion handler */
273 kref_put(&dev->kref, diag_bridge_delete);
274 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700275}
Jack Phamf6ed5582011-11-02 16:08:31 -0700276EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700277
Jack Pham9a08de42012-02-06 15:43:23 -0800278#if defined(CONFIG_DEBUG_FS)
279#define DEBUG_BUF_SIZE 512
280static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
281 size_t count, loff_t *ppos)
282{
283 struct diag_bridge *dev = __dev;
284 char *buf;
285 int ret;
286
Jack Pham76e61dd2012-06-14 18:48:53 -0700287 if (!dev)
288 return -ENODEV;
289
Jack Pham9a08de42012-02-06 15:43:23 -0800290 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
291 if (!buf)
292 return -ENOMEM;
293
294 ret = scnprintf(buf, DEBUG_BUF_SIZE,
295 "epin:%d, epout:%d\n"
296 "bytes to host: %lu\n"
297 "bytes to mdm: %lu\n"
298 "pending reads: %u\n"
299 "pending writes: %u\n"
300 "last error: %d\n",
301 dev->in_epAddr, dev->out_epAddr,
302 dev->bytes_to_host, dev->bytes_to_mdm,
303 dev->pending_reads, dev->pending_writes,
304 dev->err);
305
306 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
307 kfree(buf);
308 return ret;
309}
310
311static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
312 size_t count, loff_t *ppos)
313{
314 struct diag_bridge *dev = __dev;
315
Jack Pham76e61dd2012-06-14 18:48:53 -0700316 if (dev) {
317 dev->bytes_to_host = dev->bytes_to_mdm = 0;
318 dev->pending_reads = dev->pending_writes = 0;
319 }
Jack Pham9a08de42012-02-06 15:43:23 -0800320
321 return count;
322}
323
324const struct file_operations diag_stats_ops = {
325 .read = diag_read_stats,
326 .write = diag_reset_stats,
327};
328
329static struct dentry *dent;
330
331static void diag_bridge_debugfs_init(void)
332{
333 struct dentry *dfile;
334
335 dent = debugfs_create_dir("diag_bridge", 0);
336 if (IS_ERR(dent))
337 return;
338
339 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
340 if (!dfile || IS_ERR(dfile))
341 debugfs_remove(dent);
342}
343
344static void diag_bridge_debugfs_cleanup(void)
345{
346 if (dent) {
347 debugfs_remove_recursive(dent);
348 dent = NULL;
349 }
350}
351#else
352static inline void diag_bridge_debugfs_init(void) { }
353static inline void diag_bridge_debugfs_cleanup(void) { }
354#endif
355
Jack Phame32cf322011-09-26 10:20:17 -0700356static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700357diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700358{
359 struct diag_bridge *dev;
360 struct usb_host_interface *ifc_desc;
361 struct usb_endpoint_descriptor *ep_desc;
362 int i;
363 int ret = -ENOMEM;
364 __u8 ifc_num;
365
Jack Pham76e61dd2012-06-14 18:48:53 -0700366 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700367
368 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
369
370 /* is this interface supported ? */
371 if (ifc_num != id->driver_info)
372 return -ENODEV;
373
374 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
375 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700376 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700377 return -ENOMEM;
378 }
379 dev->pdev = platform_device_alloc("diag_bridge", -1);
380 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700381 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700382 kfree(dev);
383 return -ENOMEM;
384 }
385 __dev = dev;
386
387 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
388 dev->ifc = ifc;
389 kref_init(&dev->kref);
390 init_usb_anchor(&dev->submitted);
391
392 ifc_desc = ifc->cur_altsetting;
393 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
394 ep_desc = &ifc_desc->endpoint[i].desc;
395
396 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
397 dev->in_epAddr = ep_desc->bEndpointAddress;
398
399 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
400 dev->out_epAddr = ep_desc->bEndpointAddress;
401 }
402
403 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700404 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700405 ret = -ENODEV;
406 goto error;
407 }
408
409 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800410 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700411 platform_device_add(dev->pdev);
412
413 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
414
415 return 0;
416
417error:
418 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700419 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700420
421 return ret;
422}
423
Jack Phamf6ed5582011-11-02 16:08:31 -0700424static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700425{
426 struct diag_bridge *dev = usb_get_intfdata(ifc);
427
428 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
429
430 platform_device_del(dev->pdev);
Jack Pham76e61dd2012-06-14 18:48:53 -0700431 dev->ifc = NULL;
Jack Pham9a08de42012-02-06 15:43:23 -0800432 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700433 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700434 usb_set_intfdata(ifc, NULL);
435}
436
Jack Phamb60775a2012-02-14 17:57:41 -0800437static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
438{
439 struct diag_bridge *dev = usb_get_intfdata(ifc);
440 struct diag_bridge_ops *cbs = dev->ops;
441 int ret = 0;
442
443 if (cbs && cbs->suspend) {
444 ret = cbs->suspend(cbs->ctxt);
445 if (ret) {
446 dev_dbg(&dev->udev->dev,
447 "%s: diag veto'd suspend\n", __func__);
448 return ret;
449 }
450
451 usb_kill_anchored_urbs(&dev->submitted);
452 }
453
454 return ret;
455}
456
457static int diag_bridge_resume(struct usb_interface *ifc)
458{
459 struct diag_bridge *dev = usb_get_intfdata(ifc);
460 struct diag_bridge_ops *cbs = dev->ops;
461
462
463 if (cbs && cbs->resume)
464 cbs->resume(cbs->ctxt);
465
466 return 0;
467}
Jack Phame32cf322011-09-26 10:20:17 -0700468
469#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700470static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800471 { USB_DEVICE(0x5c6, 0x9001),
472 .driver_info = VALID_INTERFACE_NUM, },
473 { USB_DEVICE(0x5c6, 0x9034),
474 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800475 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700476 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800477 { USB_DEVICE(0x5c6, 0x904C),
478 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700479
480 {} /* terminating entry */
481};
Jack Phamf6ed5582011-11-02 16:08:31 -0700482MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700483
Jack Phamf6ed5582011-11-02 16:08:31 -0700484static struct usb_driver diag_bridge_driver = {
485 .name = "diag_bridge",
486 .probe = diag_bridge_probe,
487 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800488 .suspend = diag_bridge_suspend,
489 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700490 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800491 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700492};
493
Jack Phamf6ed5582011-11-02 16:08:31 -0700494static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700495{
496 int ret;
497
Jack Phamf6ed5582011-11-02 16:08:31 -0700498 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700499 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700500 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700501 return ret;
502 }
503
504 return 0;
505}
506
Jack Phamf6ed5582011-11-02 16:08:31 -0700507static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700508{
Jack Phamf6ed5582011-11-02 16:08:31 -0700509 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700510}
511
Jack Phamf6ed5582011-11-02 16:08:31 -0700512module_init(diag_bridge_init);
513module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700514
515MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700516MODULE_VERSION(DRIVER_VERSION);
517MODULE_LICENSE("GPL v2");