blob: b1b77630c41f575be8d199956a7ca18511896733 [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>
Jack Phamb1795542012-09-04 17:13:37 -070023#include <linux/mutex.h>
Jack Phame32cf322011-09-26 10:20:17 -070024#include <linux/platform_device.h>
Jack Phamcca03322012-06-14 19:00:31 -070025#include <linux/ratelimit.h>
Jack Phame32cf322011-09-26 10:20:17 -070026#include <linux/uaccess.h>
27#include <linux/usb.h>
Jack Pham9a08de42012-02-06 15:43:23 -080028#include <linux/debugfs.h>
Jack Phame32cf322011-09-26 10:20:17 -070029#include <mach/diag_bridge.h>
30
31#define DRIVER_DESC "USB host diag bridge driver"
Jack Phamf6ed5582011-11-02 16:08:31 -070032#define DRIVER_VERSION "1.0"
Jack Phame32cf322011-09-26 10:20:17 -070033
34struct diag_bridge {
35 struct usb_device *udev;
36 struct usb_interface *ifc;
37 struct usb_anchor submitted;
38 __u8 in_epAddr;
39 __u8 out_epAddr;
Jack Pham3ae820f2011-12-14 16:21:04 -080040 int err;
Jack Phame32cf322011-09-26 10:20:17 -070041 struct kref kref;
Jack Phamb1795542012-09-04 17:13:37 -070042 struct mutex ifc_mutex;
Jack Phame32cf322011-09-26 10:20:17 -070043 struct diag_bridge_ops *ops;
44 struct platform_device *pdev;
Jack Pham9a08de42012-02-06 15:43:23 -080045
46 /* debugging counters */
47 unsigned long bytes_to_host;
48 unsigned long bytes_to_mdm;
49 unsigned pending_reads;
50 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070051};
52struct diag_bridge *__dev;
53
Jack Phamf6ed5582011-11-02 16:08:31 -070054int diag_bridge_open(struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070055{
56 struct diag_bridge *dev = __dev;
57
58 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -070059 pr_err("dev is null");
Jack Phame32cf322011-09-26 10:20:17 -070060 return -ENODEV;
61 }
62
Jack Phamfbd22552012-09-07 17:29:08 -070063 if (dev->ops) {
64 pr_err("bridge already opened");
65 return -EALREADY;
66 }
67
Jack Phame32cf322011-09-26 10:20:17 -070068 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080069 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070070
Jack Pham76e61dd2012-06-14 18:48:53 -070071 kref_get(&dev->kref);
72
Jack Phame32cf322011-09-26 10:20:17 -070073 return 0;
74}
Jack Phamf6ed5582011-11-02 16:08:31 -070075EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070076
Jack Pham76e61dd2012-06-14 18:48:53 -070077static void diag_bridge_delete(struct kref *kref)
78{
79 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
80
81 usb_put_dev(dev->udev);
82 __dev = 0;
83 kfree(dev);
84}
85
Jack Phamf6ed5582011-11-02 16:08:31 -070086void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070087{
88 struct diag_bridge *dev = __dev;
89
Jack Phamfbd22552012-09-07 17:29:08 -070090 if (!dev) {
91 pr_err("dev is null");
92 return;
93 }
94
95 if (!dev->ops) {
96 pr_err("can't close bridge that was not open");
97 return;
98 }
99
Jack Phame8741502012-06-13 17:34:07 -0700100 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700101
102 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -0700103 dev->ops = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700104 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700105}
Jack Phamf6ed5582011-11-02 16:08:31 -0700106EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -0700107
Jack Phamf6ed5582011-11-02 16:08:31 -0700108static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700109{
110 struct diag_bridge *dev = urb->context;
111 struct diag_bridge_ops *cbs = dev->ops;
112
Jack Phame8741502012-06-13 17:34:07 -0700113 dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
Jack Phame32cf322011-09-26 10:20:17 -0700114 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700115
Jack Pham3ec42b62012-08-31 15:36:27 -0700116 /* save error so that subsequent read/write returns ENODEV */
117 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800118 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800119
Vamsi Krishna90125642012-05-12 16:06:13 -0700120 if (cbs && cbs->read_complete_cb)
121 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700122 urb->transfer_buffer,
123 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700124 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800125
126 dev->bytes_to_host += urb->actual_length;
127 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700128 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700129}
130
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800131int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700132{
133 struct urb *urb = NULL;
134 unsigned int pipe;
135 struct diag_bridge *dev = __dev;
136 int ret;
137
Jack Pham76e61dd2012-06-14 18:48:53 -0700138 pr_debug("reading %d bytes", size);
139
Jack Phamb1795542012-09-04 17:13:37 -0700140 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700141 pr_err("device is disconnected");
142 return -ENODEV;
143 }
144
Jack Phamb1795542012-09-04 17:13:37 -0700145 mutex_lock(&dev->ifc_mutex);
146 if (!dev->ifc) {
147 ret = -ENODEV;
148 goto error;
149 }
150
Jack Pham76e61dd2012-06-14 18:48:53 -0700151 if (!dev->ops) {
152 pr_err("bridge is not open");
Jack Phamb1795542012-09-04 17:13:37 -0700153 ret = -ENODEV;
154 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700155 }
Jack Phame32cf322011-09-26 10:20:17 -0700156
157 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700158 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phamb1795542012-09-04 17:13:37 -0700159 ret = -EINVAL;
160 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700161 }
162
Jack Pham3ae820f2011-12-14 16:21:04 -0800163 /* if there was a previous unrecoverable error, just quit */
Jack Phamb1795542012-09-04 17:13:37 -0700164 if (dev->err) {
165 ret = -ENODEV;
166 goto error;
167 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800168
Jack Pham76e61dd2012-06-14 18:48:53 -0700169 kref_get(&dev->kref);
170
Jack Phamb60775a2012-02-14 17:57:41 -0800171 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700172 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700173 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700174 ret = -ENOMEM;
Jack Phamb1795542012-09-04 17:13:37 -0700175 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700176 }
177
Jack Phamb60775a2012-02-14 17:57:41 -0800178 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700179 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
180 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700181 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800182 }
183
Jack Phame32cf322011-09-26 10:20:17 -0700184 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
185 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700186 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700187 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800188 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700189
Jack Phamb60775a2012-02-14 17:57:41 -0800190 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700191 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700192 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800193 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700194 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700195 }
Jack Phamb60775a2012-02-14 17:57:41 -0800196 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700197
Jack Pham76e61dd2012-06-14 18:48:53 -0700198free_error:
199 usb_free_urb(urb);
Jack Phamb1795542012-09-04 17:13:37 -0700200put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700201 if (ret) /* otherwise this is done in the completion handler */
202 kref_put(&dev->kref, diag_bridge_delete);
Jack Phamb1795542012-09-04 17:13:37 -0700203error:
204 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700205 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700206}
Jack Phamf6ed5582011-11-02 16:08:31 -0700207EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700208
Jack Phamf6ed5582011-11-02 16:08:31 -0700209static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700210{
211 struct diag_bridge *dev = urb->context;
212 struct diag_bridge_ops *cbs = dev->ops;
213
Jack Phame8741502012-06-13 17:34:07 -0700214 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700215
Jack Phamb60775a2012-02-14 17:57:41 -0800216 usb_autopm_put_interface_async(dev->ifc);
217
Jack Pham3ec42b62012-08-31 15:36:27 -0700218 /* save error so that subsequent read/write returns ENODEV */
219 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800220 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800221
Vamsi Krishna90125642012-05-12 16:06:13 -0700222 if (cbs && cbs->write_complete_cb)
223 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700224 urb->transfer_buffer,
225 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700226 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800227
228 dev->bytes_to_mdm += urb->actual_length;
229 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700230 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700231}
232
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800233int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700234{
235 struct urb *urb = NULL;
236 unsigned int pipe;
237 struct diag_bridge *dev = __dev;
238 int ret;
239
Jack Pham76e61dd2012-06-14 18:48:53 -0700240 pr_debug("writing %d bytes", size);
241
Jack Phamb1795542012-09-04 17:13:37 -0700242 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700243 pr_err("device is disconnected");
244 return -ENODEV;
245 }
246
Jack Phamb1795542012-09-04 17:13:37 -0700247 mutex_lock(&dev->ifc_mutex);
248 if (!dev->ifc) {
249 ret = -ENODEV;
250 goto error;
251 }
252
Jack Pham76e61dd2012-06-14 18:48:53 -0700253 if (!dev->ops) {
254 pr_err("bridge is not open");
Jack Phamb1795542012-09-04 17:13:37 -0700255 ret = -ENODEV;
256 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700257 }
Jack Phame32cf322011-09-26 10:20:17 -0700258
259 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700260 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phamb1795542012-09-04 17:13:37 -0700261 ret = -EINVAL;
262 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700263 }
264
Jack Pham3ae820f2011-12-14 16:21:04 -0800265 /* if there was a previous unrecoverable error, just quit */
Jack Phamb1795542012-09-04 17:13:37 -0700266 if (dev->err) {
267 ret = -ENODEV;
268 goto error;
269 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800270
Jack Pham76e61dd2012-06-14 18:48:53 -0700271 kref_get(&dev->kref);
272
Jack Phamb60775a2012-02-14 17:57:41 -0800273 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700274 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700275 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700276 ret = -ENOMEM;
Jack Phamb1795542012-09-04 17:13:37 -0700277 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700278 }
279
Jack Phamb60775a2012-02-14 17:57:41 -0800280 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700281 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
282 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700283 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800284 }
285
Jack Phame32cf322011-09-26 10:20:17 -0700286 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
287 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700288 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700289 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700290 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800291 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700292
Jack Phamb60775a2012-02-14 17:57:41 -0800293 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700294 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700295 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800296 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700297 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800298 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700299 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700300 }
301
Jack Pham76e61dd2012-06-14 18:48:53 -0700302free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700303 usb_free_urb(urb);
Jack Phamb1795542012-09-04 17:13:37 -0700304put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700305 if (ret) /* otherwise this is done in the completion handler */
306 kref_put(&dev->kref, diag_bridge_delete);
Jack Phamb1795542012-09-04 17:13:37 -0700307error:
308 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700309 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700310}
Jack Phamf6ed5582011-11-02 16:08:31 -0700311EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700312
Jack Pham9a08de42012-02-06 15:43:23 -0800313#if defined(CONFIG_DEBUG_FS)
314#define DEBUG_BUF_SIZE 512
315static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
316 size_t count, loff_t *ppos)
317{
318 struct diag_bridge *dev = __dev;
319 char *buf;
320 int ret;
321
Jack Pham76e61dd2012-06-14 18:48:53 -0700322 if (!dev)
323 return -ENODEV;
324
Jack Pham9a08de42012-02-06 15:43:23 -0800325 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
326 if (!buf)
327 return -ENOMEM;
328
329 ret = scnprintf(buf, DEBUG_BUF_SIZE,
330 "epin:%d, epout:%d\n"
331 "bytes to host: %lu\n"
332 "bytes to mdm: %lu\n"
333 "pending reads: %u\n"
334 "pending writes: %u\n"
335 "last error: %d\n",
336 dev->in_epAddr, dev->out_epAddr,
337 dev->bytes_to_host, dev->bytes_to_mdm,
338 dev->pending_reads, dev->pending_writes,
339 dev->err);
340
341 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
342 kfree(buf);
343 return ret;
344}
345
346static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
347 size_t count, loff_t *ppos)
348{
349 struct diag_bridge *dev = __dev;
350
Jack Pham76e61dd2012-06-14 18:48:53 -0700351 if (dev) {
352 dev->bytes_to_host = dev->bytes_to_mdm = 0;
353 dev->pending_reads = dev->pending_writes = 0;
354 }
Jack Pham9a08de42012-02-06 15:43:23 -0800355
356 return count;
357}
358
359const struct file_operations diag_stats_ops = {
360 .read = diag_read_stats,
361 .write = diag_reset_stats,
362};
363
364static struct dentry *dent;
365
366static void diag_bridge_debugfs_init(void)
367{
368 struct dentry *dfile;
369
370 dent = debugfs_create_dir("diag_bridge", 0);
371 if (IS_ERR(dent))
372 return;
373
374 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
375 if (!dfile || IS_ERR(dfile))
376 debugfs_remove(dent);
377}
378
379static void diag_bridge_debugfs_cleanup(void)
380{
381 if (dent) {
382 debugfs_remove_recursive(dent);
383 dent = NULL;
384 }
385}
386#else
387static inline void diag_bridge_debugfs_init(void) { }
388static inline void diag_bridge_debugfs_cleanup(void) { }
389#endif
390
Jack Phame32cf322011-09-26 10:20:17 -0700391static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700392diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700393{
394 struct diag_bridge *dev;
395 struct usb_host_interface *ifc_desc;
396 struct usb_endpoint_descriptor *ep_desc;
397 int i;
398 int ret = -ENOMEM;
399 __u8 ifc_num;
400
Jack Pham76e61dd2012-06-14 18:48:53 -0700401 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700402
403 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
404
405 /* is this interface supported ? */
406 if (ifc_num != id->driver_info)
407 return -ENODEV;
408
409 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
410 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700411 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700412 return -ENOMEM;
413 }
414 dev->pdev = platform_device_alloc("diag_bridge", -1);
415 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700416 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700417 kfree(dev);
418 return -ENOMEM;
419 }
420 __dev = dev;
421
422 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
423 dev->ifc = ifc;
424 kref_init(&dev->kref);
Jack Phamb1795542012-09-04 17:13:37 -0700425 mutex_init(&dev->ifc_mutex);
Jack Phame32cf322011-09-26 10:20:17 -0700426 init_usb_anchor(&dev->submitted);
427
428 ifc_desc = ifc->cur_altsetting;
429 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
430 ep_desc = &ifc_desc->endpoint[i].desc;
431
432 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
433 dev->in_epAddr = ep_desc->bEndpointAddress;
434
435 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
436 dev->out_epAddr = ep_desc->bEndpointAddress;
437 }
438
439 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700440 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700441 ret = -ENODEV;
442 goto error;
443 }
444
445 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800446 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700447 platform_device_add(dev->pdev);
448
Jack Phame8741502012-06-13 17:34:07 -0700449 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700450
451 return 0;
452
453error:
454 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700455 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700456
457 return ret;
458}
459
Jack Phamf6ed5582011-11-02 16:08:31 -0700460static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700461{
462 struct diag_bridge *dev = usb_get_intfdata(ifc);
463
Jack Phame8741502012-06-13 17:34:07 -0700464 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700465
Jack Pham1b1ba472012-06-13 16:40:15 -0700466 platform_device_unregister(dev->pdev);
Jack Phamb1795542012-09-04 17:13:37 -0700467 mutex_lock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700468 dev->ifc = NULL;
Jack Phamb1795542012-09-04 17:13:37 -0700469 mutex_unlock(&dev->ifc_mutex);
Jack Pham9a08de42012-02-06 15:43:23 -0800470 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700471 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700472 usb_set_intfdata(ifc, NULL);
473}
474
Jack Phamb60775a2012-02-14 17:57:41 -0800475static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
476{
477 struct diag_bridge *dev = usb_get_intfdata(ifc);
478 struct diag_bridge_ops *cbs = dev->ops;
479 int ret = 0;
480
481 if (cbs && cbs->suspend) {
482 ret = cbs->suspend(cbs->ctxt);
483 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700484 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800485 "%s: diag veto'd suspend\n", __func__);
486 return ret;
487 }
488
489 usb_kill_anchored_urbs(&dev->submitted);
490 }
491
492 return ret;
493}
494
495static int diag_bridge_resume(struct usb_interface *ifc)
496{
497 struct diag_bridge *dev = usb_get_intfdata(ifc);
498 struct diag_bridge_ops *cbs = dev->ops;
499
500
501 if (cbs && cbs->resume)
502 cbs->resume(cbs->ctxt);
503
504 return 0;
505}
Jack Phame32cf322011-09-26 10:20:17 -0700506
507#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700508static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800509 { USB_DEVICE(0x5c6, 0x9001),
510 .driver_info = VALID_INTERFACE_NUM, },
511 { USB_DEVICE(0x5c6, 0x9034),
512 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800513 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700514 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800515 { USB_DEVICE(0x5c6, 0x904C),
516 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700517
518 {} /* terminating entry */
519};
Jack Phamf6ed5582011-11-02 16:08:31 -0700520MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700521
Jack Phamf6ed5582011-11-02 16:08:31 -0700522static struct usb_driver diag_bridge_driver = {
523 .name = "diag_bridge",
524 .probe = diag_bridge_probe,
525 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800526 .suspend = diag_bridge_suspend,
527 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700528 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800529 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700530};
531
Jack Phamf6ed5582011-11-02 16:08:31 -0700532static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700533{
534 int ret;
535
Jack Phamf6ed5582011-11-02 16:08:31 -0700536 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700537 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700538 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700539 return ret;
540 }
541
542 return 0;
543}
544
Jack Phamf6ed5582011-11-02 16:08:31 -0700545static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700546{
Jack Phamf6ed5582011-11-02 16:08:31 -0700547 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700548}
549
Jack Phamf6ed5582011-11-02 16:08:31 -0700550module_init(diag_bridge_init);
551module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700552
553MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700554MODULE_VERSION(DRIVER_VERSION);
555MODULE_LICENSE("GPL v2");