blob: cad411dbb1fd348aaef6b773b6e50061731c1588 [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
63 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080064 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070065
Jack Pham76e61dd2012-06-14 18:48:53 -070066 kref_get(&dev->kref);
67
Jack Phame32cf322011-09-26 10:20:17 -070068 return 0;
69}
Jack Phamf6ed5582011-11-02 16:08:31 -070070EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070071
Jack Pham76e61dd2012-06-14 18:48:53 -070072static void diag_bridge_delete(struct kref *kref)
73{
74 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
75
76 usb_put_dev(dev->udev);
77 __dev = 0;
78 kfree(dev);
79}
80
Jack Phamf6ed5582011-11-02 16:08:31 -070081void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070082{
83 struct diag_bridge *dev = __dev;
84
Jack Phame8741502012-06-13 17:34:07 -070085 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -070086
87 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -070088 dev->ops = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -070089 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -070090}
Jack Phamf6ed5582011-11-02 16:08:31 -070091EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -070092
Jack Phamf6ed5582011-11-02 16:08:31 -070093static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -070094{
95 struct diag_bridge *dev = urb->context;
96 struct diag_bridge_ops *cbs = dev->ops;
97
Jack Phame8741502012-06-13 17:34:07 -070098 dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
Jack Phame32cf322011-09-26 10:20:17 -070099 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700100
Jack Pham3ec42b62012-08-31 15:36:27 -0700101 /* save error so that subsequent read/write returns ENODEV */
102 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800103 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800104
Vamsi Krishna90125642012-05-12 16:06:13 -0700105 if (cbs && cbs->read_complete_cb)
106 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700107 urb->transfer_buffer,
108 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700109 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800110
111 dev->bytes_to_host += urb->actual_length;
112 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700113 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700114}
115
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800116int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700117{
118 struct urb *urb = NULL;
119 unsigned int pipe;
120 struct diag_bridge *dev = __dev;
121 int ret;
122
Jack Pham76e61dd2012-06-14 18:48:53 -0700123 pr_debug("reading %d bytes", size);
124
Jack Phamb1795542012-09-04 17:13:37 -0700125 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700126 pr_err("device is disconnected");
127 return -ENODEV;
128 }
129
Jack Phamb1795542012-09-04 17:13:37 -0700130 mutex_lock(&dev->ifc_mutex);
131 if (!dev->ifc) {
132 ret = -ENODEV;
133 goto error;
134 }
135
Jack Pham76e61dd2012-06-14 18:48:53 -0700136 if (!dev->ops) {
137 pr_err("bridge is not open");
Jack Phamb1795542012-09-04 17:13:37 -0700138 ret = -ENODEV;
139 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700140 }
Jack Phame32cf322011-09-26 10:20:17 -0700141
142 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700143 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phamb1795542012-09-04 17:13:37 -0700144 ret = -EINVAL;
145 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700146 }
147
Jack Pham3ae820f2011-12-14 16:21:04 -0800148 /* if there was a previous unrecoverable error, just quit */
Jack Phamb1795542012-09-04 17:13:37 -0700149 if (dev->err) {
150 ret = -ENODEV;
151 goto error;
152 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800153
Jack Pham76e61dd2012-06-14 18:48:53 -0700154 kref_get(&dev->kref);
155
Jack Phamb60775a2012-02-14 17:57:41 -0800156 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700157 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700158 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700159 ret = -ENOMEM;
Jack Phamb1795542012-09-04 17:13:37 -0700160 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700161 }
162
Jack Phamb60775a2012-02-14 17:57:41 -0800163 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700164 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
165 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700166 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800167 }
168
Jack Phame32cf322011-09-26 10:20:17 -0700169 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
170 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700171 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700172 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800173 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700174
Jack Phamb60775a2012-02-14 17:57:41 -0800175 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700176 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700177 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800178 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700179 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700180 }
Jack Phamb60775a2012-02-14 17:57:41 -0800181 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700182
Jack Pham76e61dd2012-06-14 18:48:53 -0700183free_error:
184 usb_free_urb(urb);
Jack Phamb1795542012-09-04 17:13:37 -0700185put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700186 if (ret) /* otherwise this is done in the completion handler */
187 kref_put(&dev->kref, diag_bridge_delete);
Jack Phamb1795542012-09-04 17:13:37 -0700188error:
189 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700190 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700191}
Jack Phamf6ed5582011-11-02 16:08:31 -0700192EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700193
Jack Phamf6ed5582011-11-02 16:08:31 -0700194static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700195{
196 struct diag_bridge *dev = urb->context;
197 struct diag_bridge_ops *cbs = dev->ops;
198
Jack Phame8741502012-06-13 17:34:07 -0700199 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700200
Jack Phamb60775a2012-02-14 17:57:41 -0800201 usb_autopm_put_interface_async(dev->ifc);
202
Jack Pham3ec42b62012-08-31 15:36:27 -0700203 /* save error so that subsequent read/write returns ENODEV */
204 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800205 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800206
Vamsi Krishna90125642012-05-12 16:06:13 -0700207 if (cbs && cbs->write_complete_cb)
208 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700209 urb->transfer_buffer,
210 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700211 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800212
213 dev->bytes_to_mdm += urb->actual_length;
214 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700215 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700216}
217
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800218int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700219{
220 struct urb *urb = NULL;
221 unsigned int pipe;
222 struct diag_bridge *dev = __dev;
223 int ret;
224
Jack Pham76e61dd2012-06-14 18:48:53 -0700225 pr_debug("writing %d bytes", size);
226
Jack Phamb1795542012-09-04 17:13:37 -0700227 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700228 pr_err("device is disconnected");
229 return -ENODEV;
230 }
231
Jack Phamb1795542012-09-04 17:13:37 -0700232 mutex_lock(&dev->ifc_mutex);
233 if (!dev->ifc) {
234 ret = -ENODEV;
235 goto error;
236 }
237
Jack Pham76e61dd2012-06-14 18:48:53 -0700238 if (!dev->ops) {
239 pr_err("bridge is not open");
Jack Phamb1795542012-09-04 17:13:37 -0700240 ret = -ENODEV;
241 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700242 }
Jack Phame32cf322011-09-26 10:20:17 -0700243
244 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700245 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phamb1795542012-09-04 17:13:37 -0700246 ret = -EINVAL;
247 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700248 }
249
Jack Pham3ae820f2011-12-14 16:21:04 -0800250 /* if there was a previous unrecoverable error, just quit */
Jack Phamb1795542012-09-04 17:13:37 -0700251 if (dev->err) {
252 ret = -ENODEV;
253 goto error;
254 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800255
Jack Pham76e61dd2012-06-14 18:48:53 -0700256 kref_get(&dev->kref);
257
Jack Phamb60775a2012-02-14 17:57:41 -0800258 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700259 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700260 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700261 ret = -ENOMEM;
Jack Phamb1795542012-09-04 17:13:37 -0700262 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700263 }
264
Jack Phamb60775a2012-02-14 17:57:41 -0800265 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700266 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
267 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700268 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800269 }
270
Jack Phame32cf322011-09-26 10:20:17 -0700271 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
272 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700273 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700274 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700275 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800276 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700277
Jack Phamb60775a2012-02-14 17:57:41 -0800278 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700279 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700280 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800281 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700282 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800283 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700284 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700285 }
286
Jack Pham76e61dd2012-06-14 18:48:53 -0700287free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700288 usb_free_urb(urb);
Jack Phamb1795542012-09-04 17:13:37 -0700289put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700290 if (ret) /* otherwise this is done in the completion handler */
291 kref_put(&dev->kref, diag_bridge_delete);
Jack Phamb1795542012-09-04 17:13:37 -0700292error:
293 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700294 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700295}
Jack Phamf6ed5582011-11-02 16:08:31 -0700296EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700297
Jack Pham9a08de42012-02-06 15:43:23 -0800298#if defined(CONFIG_DEBUG_FS)
299#define DEBUG_BUF_SIZE 512
300static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
301 size_t count, loff_t *ppos)
302{
303 struct diag_bridge *dev = __dev;
304 char *buf;
305 int ret;
306
Jack Pham76e61dd2012-06-14 18:48:53 -0700307 if (!dev)
308 return -ENODEV;
309
Jack Pham9a08de42012-02-06 15:43:23 -0800310 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
311 if (!buf)
312 return -ENOMEM;
313
314 ret = scnprintf(buf, DEBUG_BUF_SIZE,
315 "epin:%d, epout:%d\n"
316 "bytes to host: %lu\n"
317 "bytes to mdm: %lu\n"
318 "pending reads: %u\n"
319 "pending writes: %u\n"
320 "last error: %d\n",
321 dev->in_epAddr, dev->out_epAddr,
322 dev->bytes_to_host, dev->bytes_to_mdm,
323 dev->pending_reads, dev->pending_writes,
324 dev->err);
325
326 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
327 kfree(buf);
328 return ret;
329}
330
331static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
332 size_t count, loff_t *ppos)
333{
334 struct diag_bridge *dev = __dev;
335
Jack Pham76e61dd2012-06-14 18:48:53 -0700336 if (dev) {
337 dev->bytes_to_host = dev->bytes_to_mdm = 0;
338 dev->pending_reads = dev->pending_writes = 0;
339 }
Jack Pham9a08de42012-02-06 15:43:23 -0800340
341 return count;
342}
343
344const struct file_operations diag_stats_ops = {
345 .read = diag_read_stats,
346 .write = diag_reset_stats,
347};
348
349static struct dentry *dent;
350
351static void diag_bridge_debugfs_init(void)
352{
353 struct dentry *dfile;
354
355 dent = debugfs_create_dir("diag_bridge", 0);
356 if (IS_ERR(dent))
357 return;
358
359 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
360 if (!dfile || IS_ERR(dfile))
361 debugfs_remove(dent);
362}
363
364static void diag_bridge_debugfs_cleanup(void)
365{
366 if (dent) {
367 debugfs_remove_recursive(dent);
368 dent = NULL;
369 }
370}
371#else
372static inline void diag_bridge_debugfs_init(void) { }
373static inline void diag_bridge_debugfs_cleanup(void) { }
374#endif
375
Jack Phame32cf322011-09-26 10:20:17 -0700376static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700377diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700378{
379 struct diag_bridge *dev;
380 struct usb_host_interface *ifc_desc;
381 struct usb_endpoint_descriptor *ep_desc;
382 int i;
383 int ret = -ENOMEM;
384 __u8 ifc_num;
385
Jack Pham76e61dd2012-06-14 18:48:53 -0700386 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700387
388 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
389
390 /* is this interface supported ? */
391 if (ifc_num != id->driver_info)
392 return -ENODEV;
393
394 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
395 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700396 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700397 return -ENOMEM;
398 }
399 dev->pdev = platform_device_alloc("diag_bridge", -1);
400 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700401 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700402 kfree(dev);
403 return -ENOMEM;
404 }
405 __dev = dev;
406
407 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
408 dev->ifc = ifc;
409 kref_init(&dev->kref);
Jack Phamb1795542012-09-04 17:13:37 -0700410 mutex_init(&dev->ifc_mutex);
Jack Phame32cf322011-09-26 10:20:17 -0700411 init_usb_anchor(&dev->submitted);
412
413 ifc_desc = ifc->cur_altsetting;
414 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
415 ep_desc = &ifc_desc->endpoint[i].desc;
416
417 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
418 dev->in_epAddr = ep_desc->bEndpointAddress;
419
420 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
421 dev->out_epAddr = ep_desc->bEndpointAddress;
422 }
423
424 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700425 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700426 ret = -ENODEV;
427 goto error;
428 }
429
430 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800431 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700432 platform_device_add(dev->pdev);
433
Jack Phame8741502012-06-13 17:34:07 -0700434 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700435
436 return 0;
437
438error:
439 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700440 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700441
442 return ret;
443}
444
Jack Phamf6ed5582011-11-02 16:08:31 -0700445static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700446{
447 struct diag_bridge *dev = usb_get_intfdata(ifc);
448
Jack Phame8741502012-06-13 17:34:07 -0700449 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700450
Jack Pham1b1ba472012-06-13 16:40:15 -0700451 platform_device_unregister(dev->pdev);
Jack Phamb1795542012-09-04 17:13:37 -0700452 mutex_lock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700453 dev->ifc = NULL;
Jack Phamb1795542012-09-04 17:13:37 -0700454 mutex_unlock(&dev->ifc_mutex);
Jack Pham9a08de42012-02-06 15:43:23 -0800455 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700456 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700457 usb_set_intfdata(ifc, NULL);
458}
459
Jack Phamb60775a2012-02-14 17:57:41 -0800460static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
461{
462 struct diag_bridge *dev = usb_get_intfdata(ifc);
463 struct diag_bridge_ops *cbs = dev->ops;
464 int ret = 0;
465
466 if (cbs && cbs->suspend) {
467 ret = cbs->suspend(cbs->ctxt);
468 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700469 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800470 "%s: diag veto'd suspend\n", __func__);
471 return ret;
472 }
473
474 usb_kill_anchored_urbs(&dev->submitted);
475 }
476
477 return ret;
478}
479
480static int diag_bridge_resume(struct usb_interface *ifc)
481{
482 struct diag_bridge *dev = usb_get_intfdata(ifc);
483 struct diag_bridge_ops *cbs = dev->ops;
484
485
486 if (cbs && cbs->resume)
487 cbs->resume(cbs->ctxt);
488
489 return 0;
490}
Jack Phame32cf322011-09-26 10:20:17 -0700491
492#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700493static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800494 { USB_DEVICE(0x5c6, 0x9001),
495 .driver_info = VALID_INTERFACE_NUM, },
496 { USB_DEVICE(0x5c6, 0x9034),
497 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800498 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700499 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800500 { USB_DEVICE(0x5c6, 0x904C),
501 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700502
503 {} /* terminating entry */
504};
Jack Phamf6ed5582011-11-02 16:08:31 -0700505MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700506
Jack Phamf6ed5582011-11-02 16:08:31 -0700507static struct usb_driver diag_bridge_driver = {
508 .name = "diag_bridge",
509 .probe = diag_bridge_probe,
510 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800511 .suspend = diag_bridge_suspend,
512 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700513 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800514 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700515};
516
Jack Phamf6ed5582011-11-02 16:08:31 -0700517static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700518{
519 int ret;
520
Jack Phamf6ed5582011-11-02 16:08:31 -0700521 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700522 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700523 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700524 return ret;
525 }
526
527 return 0;
528}
529
Jack Phamf6ed5582011-11-02 16:08:31 -0700530static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700531{
Jack Phamf6ed5582011-11-02 16:08:31 -0700532 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700533}
534
Jack Phamf6ed5582011-11-02 16:08:31 -0700535module_init(diag_bridge_init);
536module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700537
538MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700539MODULE_VERSION(DRIVER_VERSION);
540MODULE_LICENSE("GPL v2");