blob: b65cc407d23731841a0ff36ee582b2f64daa227e [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;
Jack Pham9a08de42012-02-06 15:43:23 -080047
48 /* debugging counters */
49 unsigned long bytes_to_host;
50 unsigned long bytes_to_mdm;
51 unsigned pending_reads;
52 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070053};
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080054struct diag_bridge *__dev[MAX_DIAG_BRIDGE_DEVS];
Jack Phame32cf322011-09-26 10:20:17 -070055
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080056int diag_bridge_open(int id, struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070057{
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080058 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -070059
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080060 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
61 pr_err("Invalid device ID");
62 return -ENODEV;
63 }
64
65 dev = __dev[id];
Jack Phame32cf322011-09-26 10:20:17 -070066 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -070067 pr_err("dev is null");
Jack Phame32cf322011-09-26 10:20:17 -070068 return -ENODEV;
69 }
70
Jack Pham3621f4c2012-09-07 17:29:08 -070071 if (dev->ops) {
72 pr_err("bridge already opened");
73 return -EALREADY;
74 }
75
Jack Phame32cf322011-09-26 10:20:17 -070076 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080077 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070078
Jack Pham76e61dd2012-06-14 18:48:53 -070079 kref_get(&dev->kref);
80
Jack Phame32cf322011-09-26 10:20:17 -070081 return 0;
82}
Jack Phamf6ed5582011-11-02 16:08:31 -070083EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070084
Jack Pham76e61dd2012-06-14 18:48:53 -070085static void diag_bridge_delete(struct kref *kref)
86{
87 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080088 int id = dev->pdev->id;
Jack Pham76e61dd2012-06-14 18:48:53 -070089
90 usb_put_dev(dev->udev);
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080091 __dev[id] = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -070092 kfree(dev);
93}
94
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080095void diag_bridge_close(int id)
Jack Phame32cf322011-09-26 10:20:17 -070096{
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080097 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -070098
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -080099 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
100 pr_err("Invalid device ID");
101 return;
102 }
103
104 dev = __dev[id];
Jack Pham3621f4c2012-09-07 17:29:08 -0700105 if (!dev) {
106 pr_err("dev is null");
107 return;
108 }
109
110 if (!dev->ops) {
111 pr_err("can't close bridge that was not open");
112 return;
113 }
114
Jack Phame8741502012-06-13 17:34:07 -0700115 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700116
117 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -0700118 dev->ops = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700119 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700120}
Jack Phamf6ed5582011-11-02 16:08:31 -0700121EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -0700122
Jack Phamf6ed5582011-11-02 16:08:31 -0700123static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700124{
125 struct diag_bridge *dev = urb->context;
126 struct diag_bridge_ops *cbs = dev->ops;
127
Jack Phame8741502012-06-13 17:34:07 -0700128 dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
Jack Phame32cf322011-09-26 10:20:17 -0700129 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700130
Jack Pham3a3ab242012-08-31 15:36:27 -0700131 /* save error so that subsequent read/write returns ENODEV */
132 if (urb->status == -EPROTO)
133 dev->err = urb->status;
134
Devin Kima8d28532012-09-07 14:17:16 -0700135 if (cbs && cbs->read_complete_cb)
136 cbs->read_complete_cb(cbs->ctxt,
137 urb->transfer_buffer,
138 urb->transfer_buffer_length,
139 urb->status < 0 ? urb->status : urb->actual_length);
140
Jack Pham9a08de42012-02-06 15:43:23 -0800141 dev->bytes_to_host += urb->actual_length;
142 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700143 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700144}
145
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800146int diag_bridge_read(int id, char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700147{
148 struct urb *urb = NULL;
149 unsigned int pipe;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800150 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700151 int ret;
152
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800153 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
154 pr_err("Invalid device ID");
155 return -ENODEV;
156 }
157
Jack Pham76e61dd2012-06-14 18:48:53 -0700158 pr_debug("reading %d bytes", size);
159
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800160 dev = __dev[id];
Jack Pham3d02d942012-09-04 17:13:37 -0700161 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700162 pr_err("device is disconnected");
163 return -ENODEV;
164 }
165
Jack Pham3d02d942012-09-04 17:13:37 -0700166 mutex_lock(&dev->ifc_mutex);
167 if (!dev->ifc) {
168 ret = -ENODEV;
169 goto error;
170 }
171
Jack Pham76e61dd2012-06-14 18:48:53 -0700172 if (!dev->ops) {
173 pr_err("bridge is not open");
Jack Pham3d02d942012-09-04 17:13:37 -0700174 ret = -ENODEV;
175 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700176 }
Jack Phame32cf322011-09-26 10:20:17 -0700177
178 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700179 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Pham3d02d942012-09-04 17:13:37 -0700180 ret = -EINVAL;
181 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700182 }
183
Jack Pham3ae820f2011-12-14 16:21:04 -0800184 /* if there was a previous unrecoverable error, just quit */
Jack Pham3d02d942012-09-04 17:13:37 -0700185 if (dev->err) {
186 ret = -ENODEV;
187 goto error;
188 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800189
Jack Pham76e61dd2012-06-14 18:48:53 -0700190 kref_get(&dev->kref);
191
Jack Phamb60775a2012-02-14 17:57:41 -0800192 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700193 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700194 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700195 ret = -ENOMEM;
Jack Pham3d02d942012-09-04 17:13:37 -0700196 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700197 }
198
Jack Phamb60775a2012-02-14 17:57:41 -0800199 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700200 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
201 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700202 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800203 }
204
Jack Phame32cf322011-09-26 10:20:17 -0700205 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
206 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700207 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700208 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800209 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700210
Jack Phamb60775a2012-02-14 17:57:41 -0800211 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700212 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700213 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800214 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700215 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700216 }
Jack Phamb60775a2012-02-14 17:57:41 -0800217 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700218
Jack Pham76e61dd2012-06-14 18:48:53 -0700219free_error:
220 usb_free_urb(urb);
Jack Pham3d02d942012-09-04 17:13:37 -0700221put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700222 if (ret) /* otherwise this is done in the completion handler */
223 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3d02d942012-09-04 17:13:37 -0700224error:
225 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700226 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700227}
Jack Phamf6ed5582011-11-02 16:08:31 -0700228EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700229
Jack Phamf6ed5582011-11-02 16:08:31 -0700230static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700231{
232 struct diag_bridge *dev = urb->context;
233 struct diag_bridge_ops *cbs = dev->ops;
234
Jack Phame8741502012-06-13 17:34:07 -0700235 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700236
Jack Phamb60775a2012-02-14 17:57:41 -0800237 usb_autopm_put_interface_async(dev->ifc);
238
Jack Pham3a3ab242012-08-31 15:36:27 -0700239 /* save error so that subsequent read/write returns ENODEV */
240 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800241 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800242
Vamsi Krishna90125642012-05-12 16:06:13 -0700243 if (cbs && cbs->write_complete_cb)
244 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700245 urb->transfer_buffer,
246 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700247 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800248
249 dev->bytes_to_mdm += urb->actual_length;
250 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700251 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700252}
253
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800254int diag_bridge_write(int id, char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700255{
256 struct urb *urb = NULL;
257 unsigned int pipe;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800258 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700259 int ret;
260
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800261 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
262 pr_err("Invalid device ID");
263 return -ENODEV;
264 }
265
Jack Pham76e61dd2012-06-14 18:48:53 -0700266 pr_debug("writing %d bytes", size);
267
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800268 dev = __dev[id];
Jack Pham3d02d942012-09-04 17:13:37 -0700269 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700270 pr_err("device is disconnected");
271 return -ENODEV;
272 }
273
Jack Pham3d02d942012-09-04 17:13:37 -0700274 mutex_lock(&dev->ifc_mutex);
275 if (!dev->ifc) {
276 ret = -ENODEV;
277 goto error;
278 }
279
Jack Pham76e61dd2012-06-14 18:48:53 -0700280 if (!dev->ops) {
281 pr_err("bridge is not open");
Jack Pham3d02d942012-09-04 17:13:37 -0700282 ret = -ENODEV;
283 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700284 }
Jack Phame32cf322011-09-26 10:20:17 -0700285
286 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700287 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Pham3d02d942012-09-04 17:13:37 -0700288 ret = -EINVAL;
289 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700290 }
291
Jack Pham3ae820f2011-12-14 16:21:04 -0800292 /* if there was a previous unrecoverable error, just quit */
Jack Pham3d02d942012-09-04 17:13:37 -0700293 if (dev->err) {
294 ret = -ENODEV;
295 goto error;
296 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800297
Jack Pham76e61dd2012-06-14 18:48:53 -0700298 kref_get(&dev->kref);
299
Jack Phamb60775a2012-02-14 17:57:41 -0800300 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700301 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700302 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700303 ret = -ENOMEM;
Jack Pham3d02d942012-09-04 17:13:37 -0700304 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700305 }
306
Jack Phamb60775a2012-02-14 17:57:41 -0800307 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700308 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
309 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700310 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800311 }
312
Jack Phame32cf322011-09-26 10:20:17 -0700313 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
314 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700315 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700316 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700317 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800318 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700319
Jack Phamb60775a2012-02-14 17:57:41 -0800320 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700321 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700322 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800323 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700324 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800325 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700326 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700327 }
328
Jack Pham76e61dd2012-06-14 18:48:53 -0700329free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700330 usb_free_urb(urb);
Jack Pham3d02d942012-09-04 17:13:37 -0700331put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700332 if (ret) /* otherwise this is done in the completion handler */
333 kref_put(&dev->kref, diag_bridge_delete);
Jack Pham3d02d942012-09-04 17:13:37 -0700334error:
335 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700336 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700337}
Jack Phamf6ed5582011-11-02 16:08:31 -0700338EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700339
Jack Pham9a08de42012-02-06 15:43:23 -0800340#if defined(CONFIG_DEBUG_FS)
341#define DEBUG_BUF_SIZE 512
342static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
343 size_t count, loff_t *ppos)
344{
Jack Pham9a08de42012-02-06 15:43:23 -0800345 char *buf;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800346 int i, ret = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700347
Jack Pham9a08de42012-02-06 15:43:23 -0800348 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
349 if (!buf)
350 return -ENOMEM;
351
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800352 for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
353 struct diag_bridge *dev = __dev[i];
354 if (!dev)
355 continue;
356
357 ret += scnprintf(buf, DEBUG_BUF_SIZE,
358 "epin:%d, epout:%d\n"
359 "bytes to host: %lu\n"
360 "bytes to mdm: %lu\n"
361 "pending reads: %u\n"
362 "pending writes: %u\n"
363 "last error: %d\n",
364 dev->in_epAddr, dev->out_epAddr,
365 dev->bytes_to_host, dev->bytes_to_mdm,
366 dev->pending_reads, dev->pending_writes,
367 dev->err);
368 }
Jack Pham9a08de42012-02-06 15:43:23 -0800369
370 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
371 kfree(buf);
372 return ret;
373}
374
375static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
376 size_t count, loff_t *ppos)
377{
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800378 int i;
Jack Pham9a08de42012-02-06 15:43:23 -0800379
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800380 for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
381 struct diag_bridge *dev = __dev[i];
382 if (dev) {
383 dev->bytes_to_host = dev->bytes_to_mdm = 0;
384 dev->pending_reads = dev->pending_writes = 0;
385 }
Jack Pham76e61dd2012-06-14 18:48:53 -0700386 }
Jack Pham9a08de42012-02-06 15:43:23 -0800387
388 return count;
389}
390
391const struct file_operations diag_stats_ops = {
392 .read = diag_read_stats,
393 .write = diag_reset_stats,
394};
395
396static struct dentry *dent;
397
398static void diag_bridge_debugfs_init(void)
399{
400 struct dentry *dfile;
401
402 dent = debugfs_create_dir("diag_bridge", 0);
403 if (IS_ERR(dent))
404 return;
405
406 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
407 if (!dfile || IS_ERR(dfile))
408 debugfs_remove(dent);
409}
410
411static void diag_bridge_debugfs_cleanup(void)
412{
413 if (dent) {
414 debugfs_remove_recursive(dent);
415 dent = NULL;
416 }
417}
418#else
419static inline void diag_bridge_debugfs_init(void) { }
420static inline void diag_bridge_debugfs_cleanup(void) { }
421#endif
422
Jack Phame32cf322011-09-26 10:20:17 -0700423static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700424diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700425{
426 struct diag_bridge *dev;
427 struct usb_host_interface *ifc_desc;
428 struct usb_endpoint_descriptor *ep_desc;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800429 int i, devid, ret = -ENOMEM;
Jack Phame32cf322011-09-26 10:20:17 -0700430 __u8 ifc_num;
431
Jack Pham76e61dd2012-06-14 18:48:53 -0700432 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700433
434 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
435
436 /* is this interface supported ? */
Jack Phamd4d94102013-01-24 16:42:47 -0800437 if (ifc_num != (id->driver_info & 0xFF))
Jack Phame32cf322011-09-26 10:20:17 -0700438 return -ENODEV;
439
Jack Phamd4d94102013-01-24 16:42:47 -0800440 devid = (id->driver_info >> 8) & 0xFF;
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800441 if (devid < 0 || devid >= MAX_DIAG_BRIDGE_DEVS)
442 return -ENODEV;
443
444 /* already probed? */
445 if (__dev[devid]) {
446 pr_err("Diag device already probed");
447 return -ENODEV;
448 }
449
Jack Phame32cf322011-09-26 10:20:17 -0700450 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
451 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700452 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700453 return -ENOMEM;
454 }
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800455 dev->pdev = platform_device_alloc("diag_bridge", devid);
Jack Phame32cf322011-09-26 10:20:17 -0700456 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700457 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700458 kfree(dev);
459 return -ENOMEM;
460 }
Ravi Aravamudhanb80bd452013-01-18 12:47:40 -0800461 __dev[devid] = dev;
Jack Phame32cf322011-09-26 10:20:17 -0700462
463 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
464 dev->ifc = ifc;
465 kref_init(&dev->kref);
Jack Pham3d02d942012-09-04 17:13:37 -0700466 mutex_init(&dev->ifc_mutex);
Jack Phame32cf322011-09-26 10:20:17 -0700467 init_usb_anchor(&dev->submitted);
468
469 ifc_desc = ifc->cur_altsetting;
470 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
471 ep_desc = &ifc_desc->endpoint[i].desc;
472
473 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
474 dev->in_epAddr = ep_desc->bEndpointAddress;
475
476 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
477 dev->out_epAddr = ep_desc->bEndpointAddress;
478 }
479
480 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700481 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700482 ret = -ENODEV;
483 goto error;
484 }
485
486 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800487 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700488 platform_device_add(dev->pdev);
489
Jack Phame8741502012-06-13 17:34:07 -0700490 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700491
492 return 0;
493
494error:
495 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700496 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700497
498 return ret;
499}
500
Jack Phamf6ed5582011-11-02 16:08:31 -0700501static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700502{
503 struct diag_bridge *dev = usb_get_intfdata(ifc);
504
Jack Phame8741502012-06-13 17:34:07 -0700505 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700506
Jack Pham1b1ba472012-06-13 16:40:15 -0700507 platform_device_unregister(dev->pdev);
Jack Pham3d02d942012-09-04 17:13:37 -0700508 mutex_lock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700509 dev->ifc = NULL;
Jack Pham3d02d942012-09-04 17:13:37 -0700510 mutex_unlock(&dev->ifc_mutex);
Jack Pham9a08de42012-02-06 15:43:23 -0800511 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700512 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700513 usb_set_intfdata(ifc, NULL);
514}
515
Jack Phamb60775a2012-02-14 17:57:41 -0800516static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
517{
518 struct diag_bridge *dev = usb_get_intfdata(ifc);
519 struct diag_bridge_ops *cbs = dev->ops;
520 int ret = 0;
521
522 if (cbs && cbs->suspend) {
523 ret = cbs->suspend(cbs->ctxt);
524 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700525 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800526 "%s: diag veto'd suspend\n", __func__);
527 return ret;
528 }
529
530 usb_kill_anchored_urbs(&dev->submitted);
531 }
532
533 return ret;
534}
535
536static int diag_bridge_resume(struct usb_interface *ifc)
537{
538 struct diag_bridge *dev = usb_get_intfdata(ifc);
539 struct diag_bridge_ops *cbs = dev->ops;
540
541
542 if (cbs && cbs->resume)
543 cbs->resume(cbs->ctxt);
544
545 return 0;
546}
Jack Phame32cf322011-09-26 10:20:17 -0700547
548#define VALID_INTERFACE_NUM 0
Jack Phamd4d94102013-01-24 16:42:47 -0800549#define DEV_ID(n) ((n)<<8)
550
Jack Phamf6ed5582011-11-02 16:08:31 -0700551static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800552 { USB_DEVICE(0x5c6, 0x9001),
Jack Phamd4d94102013-01-24 16:42:47 -0800553 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumar7a067f12012-01-05 15:35:15 -0800554 { USB_DEVICE(0x5c6, 0x9034),
Jack Phamd4d94102013-01-24 16:42:47 -0800555 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumar7f236832011-12-16 12:13:21 -0800556 { USB_DEVICE(0x5c6, 0x9048),
Jack Phamd4d94102013-01-24 16:42:47 -0800557 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800558 { USB_DEVICE(0x5c6, 0x904C),
Jack Phamd4d94102013-01-24 16:42:47 -0800559 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
560 { USB_DEVICE(0x5c6, 0x9079),
561 .driver_info = VALID_INTERFACE_NUM | DEV_ID(1), },
Jack Phame32cf322011-09-26 10:20:17 -0700562
563 {} /* terminating entry */
564};
Jack Phamf6ed5582011-11-02 16:08:31 -0700565MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700566
Jack Phamf6ed5582011-11-02 16:08:31 -0700567static struct usb_driver diag_bridge_driver = {
568 .name = "diag_bridge",
569 .probe = diag_bridge_probe,
570 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800571 .suspend = diag_bridge_suspend,
572 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700573 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800574 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700575};
576
Jack Phamf6ed5582011-11-02 16:08:31 -0700577static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700578{
579 int ret;
580
Jack Phamf6ed5582011-11-02 16:08:31 -0700581 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700582 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700583 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700584 return ret;
585 }
586
587 return 0;
588}
589
Jack Phamf6ed5582011-11-02 16:08:31 -0700590static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700591{
Jack Phamf6ed5582011-11-02 16:08:31 -0700592 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700593}
594
Jack Phamf6ed5582011-11-02 16:08:31 -0700595module_init(diag_bridge_init);
596module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700597
598MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700599MODULE_VERSION(DRIVER_VERSION);
600MODULE_LICENSE("GPL v2");