blob: b200903c4b6c931f91f80cd4cbe2a0057493e369 [file] [log] [blame]
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -08001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Jack Phame32cf322011-09-26 10:20:17 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Jack Pham76e61dd2012-06-14 18:48:53 -070013/* add additional information to our printk's */
14#define pr_fmt(fmt) "%s: " fmt "\n", __func__
15
Jack Phame32cf322011-09-26 10:20:17 -070016#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/kref.h>
Jack Pham3d02d942012-09-04 17:13:37 -070022#include <linux/mutex.h>
Jack Phame32cf322011-09-26 10:20:17 -070023#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
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080033#define MAX_DIAG_BRIDGE_DEVS 2
34#define AUTOSUSP_DELAY_WITH_USB 1000
35
Jack Phame32cf322011-09-26 10:20:17 -070036struct diag_bridge {
37 struct usb_device *udev;
38 struct usb_interface *ifc;
39 struct usb_anchor submitted;
40 __u8 in_epAddr;
41 __u8 out_epAddr;
Jack Pham3ae820f2011-12-14 16:21:04 -080042 int err;
Jack Phame32cf322011-09-26 10:20:17 -070043 struct kref kref;
Jack Pham3d02d942012-09-04 17:13:37 -070044 struct mutex ifc_mutex;
Jack Phame32cf322011-09-26 10:20:17 -070045 struct diag_bridge_ops *ops;
46 struct platform_device *pdev;
Pavankumar Kondeti0bdd2612013-04-02 14:46:24 +053047 int id;
Jack Pham9a08de42012-02-06 15:43:23 -080048
49 /* debugging counters */
50 unsigned long bytes_to_host;
51 unsigned long bytes_to_mdm;
52 unsigned pending_reads;
53 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070054};
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080055struct diag_bridge *__dev[MAX_DIAG_BRIDGE_DEVS];
Jack Phame32cf322011-09-26 10:20:17 -070056
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080057int diag_bridge_open(int id, struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070058{
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080059 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -070060
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080061 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
62 pr_err("Invalid device ID");
63 return -ENODEV;
64 }
65
66 dev = __dev[id];
Jack Phame32cf322011-09-26 10:20:17 -070067 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -070068 pr_err("dev is null");
Jack Phame32cf322011-09-26 10:20:17 -070069 return -ENODEV;
70 }
71
Jack Pham3621f4c2012-09-07 17:29:08 -070072 if (dev->ops) {
73 pr_err("bridge already opened");
74 return -EALREADY;
75 }
76
Jack Phame32cf322011-09-26 10:20:17 -070077 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080078 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070079
Jack Pham76e61dd2012-06-14 18:48:53 -070080 kref_get(&dev->kref);
81
Jack Phame32cf322011-09-26 10:20:17 -070082 return 0;
83}
Jack Phamf6ed5582011-11-02 16:08:31 -070084EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070085
Jack Pham76e61dd2012-06-14 18:48:53 -070086static void diag_bridge_delete(struct kref *kref)
87{
88 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
Pavankumar Kondeti0bdd2612013-04-02 14:46:24 +053089 int id = dev->id;
Jack Pham76e61dd2012-06-14 18:48:53 -070090
91 usb_put_dev(dev->udev);
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080092 __dev[id] = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -070093 kfree(dev);
94}
95
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080096void diag_bridge_close(int id)
Jack Phame32cf322011-09-26 10:20:17 -070097{
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080098 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -070099
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800100 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
101 pr_err("Invalid device ID");
102 return;
103 }
104
105 dev = __dev[id];
Jack Pham3621f4c2012-09-07 17:29:08 -0700106 if (!dev) {
107 pr_err("dev is null");
108 return;
109 }
110
111 if (!dev->ops) {
112 pr_err("can't close bridge that was not open");
113 return;
114 }
115
Jack Phame8741502012-06-13 17:34:07 -0700116 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700117
118 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -0700119 dev->ops = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700120 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700121}
Jack Phamf6ed5582011-11-02 16:08:31 -0700122EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -0700123
Jack Phamf6ed5582011-11-02 16:08:31 -0700124static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700125{
126 struct diag_bridge *dev = urb->context;
127 struct diag_bridge_ops *cbs = dev->ops;
128
Jack Phame8741502012-06-13 17:34:07 -0700129 dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
Jack Phame32cf322011-09-26 10:20:17 -0700130 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700131
Jack Pham3a3ab242012-08-31 15:36:27 -0700132 /* save error so that subsequent read/write returns ENODEV */
133 if (urb->status == -EPROTO)
134 dev->err = urb->status;
135
Devin Kima8d28532012-09-07 14:17:16 -0700136 if (cbs && cbs->read_complete_cb)
137 cbs->read_complete_cb(cbs->ctxt,
138 urb->transfer_buffer,
139 urb->transfer_buffer_length,
140 urb->status < 0 ? urb->status : urb->actual_length);
141
Jack Pham9a08de42012-02-06 15:43:23 -0800142 dev->bytes_to_host += urb->actual_length;
143 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700144 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700145}
146
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800147int diag_bridge_read(int id, char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700148{
149 struct urb *urb = NULL;
150 unsigned int pipe;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800151 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700152 int ret;
153
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800154 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
155 pr_err("Invalid device ID");
156 return -ENODEV;
157 }
158
Jack Pham76e61dd2012-06-14 18:48:53 -0700159 pr_debug("reading %d bytes", size);
160
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800161 dev = __dev[id];
Jack Pham3d02d942012-09-04 17:13:37 -0700162 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700163 pr_err("device is disconnected");
164 return -ENODEV;
165 }
166
Jack Pham3d02d942012-09-04 17:13:37 -0700167 mutex_lock(&dev->ifc_mutex);
168 if (!dev->ifc) {
169 ret = -ENODEV;
170 goto error;
171 }
172
Jack Pham76e61dd2012-06-14 18:48:53 -0700173 if (!dev->ops) {
174 pr_err("bridge is not open");
Jack Pham3d02d942012-09-04 17:13:37 -0700175 ret = -ENODEV;
176 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700177 }
Jack Phame32cf322011-09-26 10:20:17 -0700178
179 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700180 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Pham3d02d942012-09-04 17:13:37 -0700181 ret = -EINVAL;
182 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700183 }
184
Jack Pham3ae820f2011-12-14 16:21:04 -0800185 /* if there was a previous unrecoverable error, just quit */
Jack Pham3d02d942012-09-04 17:13:37 -0700186 if (dev->err) {
187 ret = -ENODEV;
188 goto error;
189 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800190
Jack Pham76e61dd2012-06-14 18:48:53 -0700191 kref_get(&dev->kref);
192
Jack Phamb60775a2012-02-14 17:57:41 -0800193 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700194 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700195 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700196 ret = -ENOMEM;
Jack Pham3d02d942012-09-04 17:13:37 -0700197 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700198 }
199
Jack Phamb60775a2012-02-14 17:57:41 -0800200 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700201 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
202 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700203 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800204 }
205
Jack Phame32cf322011-09-26 10:20:17 -0700206 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
207 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700208 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700209 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800210 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700211
Jack Phamb60775a2012-02-14 17:57:41 -0800212 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700213 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700214 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800215 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700216 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700217 }
Jack Phamb60775a2012-02-14 17:57:41 -0800218 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700219
Jack Pham76e61dd2012-06-14 18:48:53 -0700220free_error:
221 usb_free_urb(urb);
Jack Pham3d02d942012-09-04 17:13:37 -0700222put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700223 if (ret) /* otherwise this is done in the completion handler */
224 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3d02d942012-09-04 17:13:37 -0700225error:
226 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700227 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700228}
Jack Phamf6ed5582011-11-02 16:08:31 -0700229EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700230
Jack Phamf6ed5582011-11-02 16:08:31 -0700231static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700232{
233 struct diag_bridge *dev = urb->context;
234 struct diag_bridge_ops *cbs = dev->ops;
235
Jack Phame8741502012-06-13 17:34:07 -0700236 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700237
Jack Phamb60775a2012-02-14 17:57:41 -0800238 usb_autopm_put_interface_async(dev->ifc);
239
Jack Pham3a3ab242012-08-31 15:36:27 -0700240 /* save error so that subsequent read/write returns ENODEV */
241 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800242 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800243
Vamsi Krishna90125642012-05-12 16:06:13 -0700244 if (cbs && cbs->write_complete_cb)
245 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700246 urb->transfer_buffer,
247 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700248 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800249
250 dev->bytes_to_mdm += urb->actual_length;
251 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700252 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700253}
254
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800255int diag_bridge_write(int id, char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700256{
257 struct urb *urb = NULL;
258 unsigned int pipe;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800259 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700260 int ret;
261
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800262 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
263 pr_err("Invalid device ID");
264 return -ENODEV;
265 }
266
Jack Pham76e61dd2012-06-14 18:48:53 -0700267 pr_debug("writing %d bytes", size);
268
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800269 dev = __dev[id];
Jack Pham3d02d942012-09-04 17:13:37 -0700270 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700271 pr_err("device is disconnected");
272 return -ENODEV;
273 }
274
Jack Pham3d02d942012-09-04 17:13:37 -0700275 mutex_lock(&dev->ifc_mutex);
276 if (!dev->ifc) {
277 ret = -ENODEV;
278 goto error;
279 }
280
Jack Pham76e61dd2012-06-14 18:48:53 -0700281 if (!dev->ops) {
282 pr_err("bridge is not open");
Jack Pham3d02d942012-09-04 17:13:37 -0700283 ret = -ENODEV;
284 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700285 }
Jack Phame32cf322011-09-26 10:20:17 -0700286
287 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700288 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Pham3d02d942012-09-04 17:13:37 -0700289 ret = -EINVAL;
290 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700291 }
292
Jack Pham3ae820f2011-12-14 16:21:04 -0800293 /* if there was a previous unrecoverable error, just quit */
Jack Pham3d02d942012-09-04 17:13:37 -0700294 if (dev->err) {
295 ret = -ENODEV;
296 goto error;
297 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800298
Jack Pham76e61dd2012-06-14 18:48:53 -0700299 kref_get(&dev->kref);
300
Jack Phamb60775a2012-02-14 17:57:41 -0800301 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700302 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700303 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700304 ret = -ENOMEM;
Jack Pham3d02d942012-09-04 17:13:37 -0700305 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700306 }
307
Jack Phamb60775a2012-02-14 17:57:41 -0800308 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700309 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
310 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700311 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800312 }
313
Jack Phame32cf322011-09-26 10:20:17 -0700314 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
315 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700316 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700317 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700318 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800319 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700320
Jack Phamb60775a2012-02-14 17:57:41 -0800321 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700322 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700323 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800324 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700325 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800326 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700327 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700328 }
329
Jack Pham76e61dd2012-06-14 18:48:53 -0700330free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700331 usb_free_urb(urb);
Jack Pham3d02d942012-09-04 17:13:37 -0700332put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700333 if (ret) /* otherwise this is done in the completion handler */
334 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3d02d942012-09-04 17:13:37 -0700335error:
336 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700337 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700338}
Jack Phamf6ed5582011-11-02 16:08:31 -0700339EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700340
Jack Pham9a08de42012-02-06 15:43:23 -0800341#if defined(CONFIG_DEBUG_FS)
342#define DEBUG_BUF_SIZE 512
343static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
344 size_t count, loff_t *ppos)
345{
Jack Pham9a08de42012-02-06 15:43:23 -0800346 char *buf;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800347 int i, ret = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700348
Jack Pham9a08de42012-02-06 15:43:23 -0800349 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
350 if (!buf)
351 return -ENOMEM;
352
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800353 for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
354 struct diag_bridge *dev = __dev[i];
355 if (!dev)
356 continue;
357
358 ret += scnprintf(buf, DEBUG_BUF_SIZE,
359 "epin:%d, epout:%d\n"
360 "bytes to host: %lu\n"
361 "bytes to mdm: %lu\n"
362 "pending reads: %u\n"
363 "pending writes: %u\n"
364 "last error: %d\n",
365 dev->in_epAddr, dev->out_epAddr,
366 dev->bytes_to_host, dev->bytes_to_mdm,
367 dev->pending_reads, dev->pending_writes,
368 dev->err);
369 }
Jack Pham9a08de42012-02-06 15:43:23 -0800370
371 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
372 kfree(buf);
373 return ret;
374}
375
376static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
377 size_t count, loff_t *ppos)
378{
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800379 int i;
Jack Pham9a08de42012-02-06 15:43:23 -0800380
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800381 for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
382 struct diag_bridge *dev = __dev[i];
383 if (dev) {
384 dev->bytes_to_host = dev->bytes_to_mdm = 0;
385 dev->pending_reads = dev->pending_writes = 0;
386 }
Jack Pham76e61dd2012-06-14 18:48:53 -0700387 }
Jack Pham9a08de42012-02-06 15:43:23 -0800388
389 return count;
390}
391
392const struct file_operations diag_stats_ops = {
393 .read = diag_read_stats,
394 .write = diag_reset_stats,
395};
396
397static struct dentry *dent;
398
399static void diag_bridge_debugfs_init(void)
400{
401 struct dentry *dfile;
402
403 dent = debugfs_create_dir("diag_bridge", 0);
404 if (IS_ERR(dent))
405 return;
406
407 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
408 if (!dfile || IS_ERR(dfile))
409 debugfs_remove(dent);
410}
411
412static void diag_bridge_debugfs_cleanup(void)
413{
414 if (dent) {
415 debugfs_remove_recursive(dent);
416 dent = NULL;
417 }
418}
419#else
420static inline void diag_bridge_debugfs_init(void) { }
421static inline void diag_bridge_debugfs_cleanup(void) { }
422#endif
423
Jack Phame32cf322011-09-26 10:20:17 -0700424static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700425diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700426{
427 struct diag_bridge *dev;
428 struct usb_host_interface *ifc_desc;
429 struct usb_endpoint_descriptor *ep_desc;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800430 int i, devid, ret = -ENOMEM;
Jack Phame32cf322011-09-26 10:20:17 -0700431 __u8 ifc_num;
432
Jack Pham76e61dd2012-06-14 18:48:53 -0700433 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700434
435 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
436
437 /* is this interface supported ? */
Jack Phamd4d94102013-01-24 16:42:47 -0800438 if (ifc_num != (id->driver_info & 0xFF))
Jack Phame32cf322011-09-26 10:20:17 -0700439 return -ENODEV;
440
Jack Phamd4d94102013-01-24 16:42:47 -0800441 devid = (id->driver_info >> 8) & 0xFF;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800442 if (devid < 0 || devid >= MAX_DIAG_BRIDGE_DEVS)
443 return -ENODEV;
444
445 /* already probed? */
446 if (__dev[devid]) {
447 pr_err("Diag device already probed");
448 return -ENODEV;
449 }
450
Jack Phame32cf322011-09-26 10:20:17 -0700451 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
452 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700453 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700454 return -ENOMEM;
455 }
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800456 dev->pdev = platform_device_alloc("diag_bridge", devid);
Jack Phame32cf322011-09-26 10:20:17 -0700457 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700458 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700459 kfree(dev);
460 return -ENOMEM;
461 }
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800462 __dev[devid] = dev;
Pavankumar Kondeti0bdd2612013-04-02 14:46:24 +0530463 dev->id = devid;
Jack Phame32cf322011-09-26 10:20:17 -0700464
465 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
466 dev->ifc = ifc;
467 kref_init(&dev->kref);
Jack Pham3d02d942012-09-04 17:13:37 -0700468 mutex_init(&dev->ifc_mutex);
Jack Phame32cf322011-09-26 10:20:17 -0700469 init_usb_anchor(&dev->submitted);
470
471 ifc_desc = ifc->cur_altsetting;
472 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
473 ep_desc = &ifc_desc->endpoint[i].desc;
474
475 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
476 dev->in_epAddr = ep_desc->bEndpointAddress;
477
478 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
479 dev->out_epAddr = ep_desc->bEndpointAddress;
480 }
481
482 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700483 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700484 ret = -ENODEV;
485 goto error;
486 }
487
488 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800489 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700490 platform_device_add(dev->pdev);
491
Jack Phame8741502012-06-13 17:34:07 -0700492 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700493
494 return 0;
495
496error:
497 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700498 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700499
500 return ret;
501}
502
Jack Phamf6ed5582011-11-02 16:08:31 -0700503static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700504{
505 struct diag_bridge *dev = usb_get_intfdata(ifc);
506
Jack Phame8741502012-06-13 17:34:07 -0700507 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700508
Jack Pham1b1ba472012-06-13 16:40:15 -0700509 platform_device_unregister(dev->pdev);
Jack Pham3d02d942012-09-04 17:13:37 -0700510 mutex_lock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700511 dev->ifc = NULL;
Jack Pham3d02d942012-09-04 17:13:37 -0700512 mutex_unlock(&dev->ifc_mutex);
Jack Pham9a08de42012-02-06 15:43:23 -0800513 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700514 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700515 usb_set_intfdata(ifc, NULL);
516}
517
Jack Phamb60775a2012-02-14 17:57:41 -0800518static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
519{
520 struct diag_bridge *dev = usb_get_intfdata(ifc);
521 struct diag_bridge_ops *cbs = dev->ops;
522 int ret = 0;
523
524 if (cbs && cbs->suspend) {
525 ret = cbs->suspend(cbs->ctxt);
526 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700527 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800528 "%s: diag veto'd suspend\n", __func__);
529 return ret;
530 }
531
532 usb_kill_anchored_urbs(&dev->submitted);
533 }
534
535 return ret;
536}
537
538static int diag_bridge_resume(struct usb_interface *ifc)
539{
540 struct diag_bridge *dev = usb_get_intfdata(ifc);
541 struct diag_bridge_ops *cbs = dev->ops;
542
543
544 if (cbs && cbs->resume)
545 cbs->resume(cbs->ctxt);
546
547 return 0;
548}
Jack Phame32cf322011-09-26 10:20:17 -0700549
550#define VALID_INTERFACE_NUM 0
Jack Phamd4d94102013-01-24 16:42:47 -0800551#define DEV_ID(n) ((n)<<8)
552
Jack Phamf6ed5582011-11-02 16:08:31 -0700553static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800554 { USB_DEVICE(0x5c6, 0x9001),
Jack Phamd4d94102013-01-24 16:42:47 -0800555 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumar7a067f12012-01-05 15:35:15 -0800556 { USB_DEVICE(0x5c6, 0x9034),
Jack Phamd4d94102013-01-24 16:42:47 -0800557 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumar7f236832011-12-16 12:13:21 -0800558 { USB_DEVICE(0x5c6, 0x9048),
Jack Phamd4d94102013-01-24 16:42:47 -0800559 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800560 { USB_DEVICE(0x5c6, 0x904C),
Jack Phamd4d94102013-01-24 16:42:47 -0800561 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
562 { USB_DEVICE(0x5c6, 0x9079),
563 .driver_info = VALID_INTERFACE_NUM | DEV_ID(1), },
Jack Phame32cf322011-09-26 10:20:17 -0700564
565 {} /* terminating entry */
566};
Jack Phamf6ed5582011-11-02 16:08:31 -0700567MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700568
Jack Phamf6ed5582011-11-02 16:08:31 -0700569static struct usb_driver diag_bridge_driver = {
570 .name = "diag_bridge",
571 .probe = diag_bridge_probe,
572 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800573 .suspend = diag_bridge_suspend,
574 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700575 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800576 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700577};
578
Jack Phamf6ed5582011-11-02 16:08:31 -0700579static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700580{
581 int ret;
582
Jack Phamf6ed5582011-11-02 16:08:31 -0700583 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700584 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700585 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700586 return ret;
587 }
588
589 return 0;
590}
591
Jack Phamf6ed5582011-11-02 16:08:31 -0700592static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700593{
Jack Phamf6ed5582011-11-02 16:08:31 -0700594 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700595}
596
Jack Phamf6ed5582011-11-02 16:08:31 -0700597module_init(diag_bridge_init);
598module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700599
600MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700601MODULE_VERSION(DRIVER_VERSION);
602MODULE_LICENSE("GPL v2");