blob: 38e778652c6cc5977948e3fc91ae8ec5e7b3e35c [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 Pham3d02d942012-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 Pham3d02d942012-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
Devin Kima8d28532012-09-07 14:17:16 -0700101 if (cbs && cbs->read_complete_cb)
102 cbs->read_complete_cb(cbs->ctxt,
103 urb->transfer_buffer,
104 urb->transfer_buffer_length,
105 urb->status < 0 ? urb->status : urb->actual_length);
106
Jack Pham3ae820f2011-12-14 16:21:04 -0800107 if (urb->status == -EPROTO) {
Jack Phame8741502012-06-13 17:34:07 -0700108 dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
Jack Phamcca03322012-06-14 19:00:31 -0700109 /* save error so that subsequent read/write returns ENODEV */
Jack Pham3ae820f2011-12-14 16:21:04 -0800110 dev->err = urb->status;
Jack Pham76e61dd2012-06-14 18:48:53 -0700111 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3ae820f2011-12-14 16:21:04 -0800112 return;
113 }
114
Jack Pham9a08de42012-02-06 15:43:23 -0800115 dev->bytes_to_host += urb->actual_length;
116 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700117 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700118}
119
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800120int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700121{
122 struct urb *urb = NULL;
123 unsigned int pipe;
124 struct diag_bridge *dev = __dev;
125 int ret;
126
Jack Pham76e61dd2012-06-14 18:48:53 -0700127 pr_debug("reading %d bytes", size);
128
Jack Pham3d02d942012-09-04 17:13:37 -0700129 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700130 pr_err("device is disconnected");
131 return -ENODEV;
132 }
133
Jack Pham3d02d942012-09-04 17:13:37 -0700134 mutex_lock(&dev->ifc_mutex);
135 if (!dev->ifc) {
136 ret = -ENODEV;
137 goto error;
138 }
139
Jack Pham76e61dd2012-06-14 18:48:53 -0700140 if (!dev->ops) {
141 pr_err("bridge is not open");
Jack Pham3d02d942012-09-04 17:13:37 -0700142 ret = -ENODEV;
143 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700144 }
Jack Phame32cf322011-09-26 10:20:17 -0700145
146 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700147 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Pham3d02d942012-09-04 17:13:37 -0700148 ret = -EINVAL;
149 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700150 }
151
Jack Pham3ae820f2011-12-14 16:21:04 -0800152 /* if there was a previous unrecoverable error, just quit */
Jack Pham3d02d942012-09-04 17:13:37 -0700153 if (dev->err) {
154 ret = -ENODEV;
155 goto error;
156 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800157
Jack Pham76e61dd2012-06-14 18:48:53 -0700158 kref_get(&dev->kref);
159
Jack Phamb60775a2012-02-14 17:57:41 -0800160 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700161 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700162 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700163 ret = -ENOMEM;
Jack Pham3d02d942012-09-04 17:13:37 -0700164 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700165 }
166
Jack Phamb60775a2012-02-14 17:57:41 -0800167 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700168 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
169 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700170 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800171 }
172
Jack Phame32cf322011-09-26 10:20:17 -0700173 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
174 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700175 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700176 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800177 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700178
Jack Phamb60775a2012-02-14 17:57:41 -0800179 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700180 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700181 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800182 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700183 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700184 }
Jack Phamb60775a2012-02-14 17:57:41 -0800185 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700186
Jack Pham76e61dd2012-06-14 18:48:53 -0700187free_error:
188 usb_free_urb(urb);
Jack Pham3d02d942012-09-04 17:13:37 -0700189put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700190 if (ret) /* otherwise this is done in the completion handler */
191 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3d02d942012-09-04 17:13:37 -0700192error:
193 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700194 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700195}
Jack Phamf6ed5582011-11-02 16:08:31 -0700196EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700197
Jack Phamf6ed5582011-11-02 16:08:31 -0700198static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700199{
200 struct diag_bridge *dev = urb->context;
201 struct diag_bridge_ops *cbs = dev->ops;
202
Jack Phame8741502012-06-13 17:34:07 -0700203 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700204
Jack Phamb60775a2012-02-14 17:57:41 -0800205 usb_autopm_put_interface_async(dev->ifc);
206
Jack Pham3ae820f2011-12-14 16:21:04 -0800207 if (urb->status == -EPROTO) {
Jack Phame8741502012-06-13 17:34:07 -0700208 dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
Jack Phamcca03322012-06-14 19:00:31 -0700209 /* save error so that subsequent read/write returns ENODEV */
Jack Pham3ae820f2011-12-14 16:21:04 -0800210 dev->err = urb->status;
Jack Pham76e61dd2012-06-14 18:48:53 -0700211 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3ae820f2011-12-14 16:21:04 -0800212 return;
213 }
214
Vamsi Krishna90125642012-05-12 16:06:13 -0700215 if (cbs && cbs->write_complete_cb)
216 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700217 urb->transfer_buffer,
218 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700219 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800220
221 dev->bytes_to_mdm += urb->actual_length;
222 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700223 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700224}
225
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800226int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700227{
228 struct urb *urb = NULL;
229 unsigned int pipe;
230 struct diag_bridge *dev = __dev;
231 int ret;
232
Jack Pham76e61dd2012-06-14 18:48:53 -0700233 pr_debug("writing %d bytes", size);
234
Jack Pham3d02d942012-09-04 17:13:37 -0700235 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700236 pr_err("device is disconnected");
237 return -ENODEV;
238 }
239
Jack Pham3d02d942012-09-04 17:13:37 -0700240 mutex_lock(&dev->ifc_mutex);
241 if (!dev->ifc) {
242 ret = -ENODEV;
243 goto error;
244 }
245
Jack Pham76e61dd2012-06-14 18:48:53 -0700246 if (!dev->ops) {
247 pr_err("bridge is not open");
Jack Pham3d02d942012-09-04 17:13:37 -0700248 ret = -ENODEV;
249 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700250 }
Jack Phame32cf322011-09-26 10:20:17 -0700251
252 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700253 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Pham3d02d942012-09-04 17:13:37 -0700254 ret = -EINVAL;
255 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700256 }
257
Jack Pham3ae820f2011-12-14 16:21:04 -0800258 /* if there was a previous unrecoverable error, just quit */
Jack Pham3d02d942012-09-04 17:13:37 -0700259 if (dev->err) {
260 ret = -ENODEV;
261 goto error;
262 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800263
Jack Pham76e61dd2012-06-14 18:48:53 -0700264 kref_get(&dev->kref);
265
Jack Phamb60775a2012-02-14 17:57:41 -0800266 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700267 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700268 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700269 ret = -ENOMEM;
Jack Pham3d02d942012-09-04 17:13:37 -0700270 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700271 }
272
Jack Phamb60775a2012-02-14 17:57:41 -0800273 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700274 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
275 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700276 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800277 }
278
Jack Phame32cf322011-09-26 10:20:17 -0700279 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
280 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700281 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700282 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700283 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800284 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700285
Jack Phamb60775a2012-02-14 17:57:41 -0800286 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700287 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700288 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800289 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700290 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800291 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700292 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700293 }
294
Jack Pham76e61dd2012-06-14 18:48:53 -0700295free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700296 usb_free_urb(urb);
Jack Pham3d02d942012-09-04 17:13:37 -0700297put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700298 if (ret) /* otherwise this is done in the completion handler */
299 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3d02d942012-09-04 17:13:37 -0700300error:
301 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700302 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700303}
Jack Phamf6ed5582011-11-02 16:08:31 -0700304EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700305
Jack Pham9a08de42012-02-06 15:43:23 -0800306#if defined(CONFIG_DEBUG_FS)
307#define DEBUG_BUF_SIZE 512
308static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
309 size_t count, loff_t *ppos)
310{
311 struct diag_bridge *dev = __dev;
312 char *buf;
313 int ret;
314
Jack Pham76e61dd2012-06-14 18:48:53 -0700315 if (!dev)
316 return -ENODEV;
317
Jack Pham9a08de42012-02-06 15:43:23 -0800318 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
319 if (!buf)
320 return -ENOMEM;
321
322 ret = scnprintf(buf, DEBUG_BUF_SIZE,
323 "epin:%d, epout:%d\n"
324 "bytes to host: %lu\n"
325 "bytes to mdm: %lu\n"
326 "pending reads: %u\n"
327 "pending writes: %u\n"
328 "last error: %d\n",
329 dev->in_epAddr, dev->out_epAddr,
330 dev->bytes_to_host, dev->bytes_to_mdm,
331 dev->pending_reads, dev->pending_writes,
332 dev->err);
333
334 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
335 kfree(buf);
336 return ret;
337}
338
339static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
340 size_t count, loff_t *ppos)
341{
342 struct diag_bridge *dev = __dev;
343
Jack Pham76e61dd2012-06-14 18:48:53 -0700344 if (dev) {
345 dev->bytes_to_host = dev->bytes_to_mdm = 0;
346 dev->pending_reads = dev->pending_writes = 0;
347 }
Jack Pham9a08de42012-02-06 15:43:23 -0800348
349 return count;
350}
351
352const struct file_operations diag_stats_ops = {
353 .read = diag_read_stats,
354 .write = diag_reset_stats,
355};
356
357static struct dentry *dent;
358
359static void diag_bridge_debugfs_init(void)
360{
361 struct dentry *dfile;
362
363 dent = debugfs_create_dir("diag_bridge", 0);
364 if (IS_ERR(dent))
365 return;
366
367 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
368 if (!dfile || IS_ERR(dfile))
369 debugfs_remove(dent);
370}
371
372static void diag_bridge_debugfs_cleanup(void)
373{
374 if (dent) {
375 debugfs_remove_recursive(dent);
376 dent = NULL;
377 }
378}
379#else
380static inline void diag_bridge_debugfs_init(void) { }
381static inline void diag_bridge_debugfs_cleanup(void) { }
382#endif
383
Jack Phame32cf322011-09-26 10:20:17 -0700384static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700385diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700386{
387 struct diag_bridge *dev;
388 struct usb_host_interface *ifc_desc;
389 struct usb_endpoint_descriptor *ep_desc;
390 int i;
391 int ret = -ENOMEM;
392 __u8 ifc_num;
393
Jack Pham76e61dd2012-06-14 18:48:53 -0700394 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700395
396 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
397
398 /* is this interface supported ? */
399 if (ifc_num != id->driver_info)
400 return -ENODEV;
401
402 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
403 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700404 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700405 return -ENOMEM;
406 }
407 dev->pdev = platform_device_alloc("diag_bridge", -1);
408 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700409 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700410 kfree(dev);
411 return -ENOMEM;
412 }
413 __dev = dev;
414
415 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
416 dev->ifc = ifc;
417 kref_init(&dev->kref);
Jack Pham3d02d942012-09-04 17:13:37 -0700418 mutex_init(&dev->ifc_mutex);
Jack Phame32cf322011-09-26 10:20:17 -0700419 init_usb_anchor(&dev->submitted);
420
421 ifc_desc = ifc->cur_altsetting;
422 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
423 ep_desc = &ifc_desc->endpoint[i].desc;
424
425 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
426 dev->in_epAddr = ep_desc->bEndpointAddress;
427
428 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
429 dev->out_epAddr = ep_desc->bEndpointAddress;
430 }
431
432 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700433 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700434 ret = -ENODEV;
435 goto error;
436 }
437
438 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800439 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700440 platform_device_add(dev->pdev);
441
Jack Phame8741502012-06-13 17:34:07 -0700442 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700443
444 return 0;
445
446error:
447 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700448 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700449
450 return ret;
451}
452
Jack Phamf6ed5582011-11-02 16:08:31 -0700453static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700454{
455 struct diag_bridge *dev = usb_get_intfdata(ifc);
456
Jack Phame8741502012-06-13 17:34:07 -0700457 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700458
Jack Pham1b1ba472012-06-13 16:40:15 -0700459 platform_device_unregister(dev->pdev);
Jack Pham3d02d942012-09-04 17:13:37 -0700460 mutex_lock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700461 dev->ifc = NULL;
Jack Pham3d02d942012-09-04 17:13:37 -0700462 mutex_unlock(&dev->ifc_mutex);
Jack Pham9a08de42012-02-06 15:43:23 -0800463 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700464 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700465 usb_set_intfdata(ifc, NULL);
466}
467
Jack Phamb60775a2012-02-14 17:57:41 -0800468static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
469{
470 struct diag_bridge *dev = usb_get_intfdata(ifc);
471 struct diag_bridge_ops *cbs = dev->ops;
472 int ret = 0;
473
474 if (cbs && cbs->suspend) {
475 ret = cbs->suspend(cbs->ctxt);
476 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700477 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800478 "%s: diag veto'd suspend\n", __func__);
479 return ret;
480 }
481
482 usb_kill_anchored_urbs(&dev->submitted);
483 }
484
485 return ret;
486}
487
488static int diag_bridge_resume(struct usb_interface *ifc)
489{
490 struct diag_bridge *dev = usb_get_intfdata(ifc);
491 struct diag_bridge_ops *cbs = dev->ops;
492
493
494 if (cbs && cbs->resume)
495 cbs->resume(cbs->ctxt);
496
497 return 0;
498}
Jack Phame32cf322011-09-26 10:20:17 -0700499
500#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700501static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800502 { USB_DEVICE(0x5c6, 0x9001),
503 .driver_info = VALID_INTERFACE_NUM, },
504 { USB_DEVICE(0x5c6, 0x9034),
505 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800506 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700507 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800508 { USB_DEVICE(0x5c6, 0x904C),
509 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700510
511 {} /* terminating entry */
512};
Jack Phamf6ed5582011-11-02 16:08:31 -0700513MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700514
Jack Phamf6ed5582011-11-02 16:08:31 -0700515static struct usb_driver diag_bridge_driver = {
516 .name = "diag_bridge",
517 .probe = diag_bridge_probe,
518 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800519 .suspend = diag_bridge_suspend,
520 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700521 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800522 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700523};
524
Jack Phamf6ed5582011-11-02 16:08:31 -0700525static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700526{
527 int ret;
528
Jack Phamf6ed5582011-11-02 16:08:31 -0700529 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700530 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700531 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700532 return ret;
533 }
534
535 return 0;
536}
537
Jack Phamf6ed5582011-11-02 16:08:31 -0700538static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700539{
Jack Phamf6ed5582011-11-02 16:08:31 -0700540 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700541}
542
Jack Phamf6ed5582011-11-02 16:08:31 -0700543module_init(diag_bridge_init);
544module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700545
546MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700547MODULE_VERSION(DRIVER_VERSION);
548MODULE_LICENSE("GPL v2");