blob: 22e2a25edb0757cf814c349491db9fef0b756447 [file] [log] [blame]
Shalabh Jainb0037c02013-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 Phamb1795542012-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
Shalabh Jainb0037c02013-01-18 12:47:40 -080033#define MAX_DIAG_BRIDGE_DEVS 2
Hemant Kumara3d4a6e2012-10-16 17:57:08 -070034#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 Phamb1795542012-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;
Hemant Kumara3d4a6e2012-10-16 17:57:08 -070047 unsigned default_autosusp_delay;
Pavankumar Kondeti52df2fd2013-04-02 14:46:24 +053048 int id;
Jack Pham9a08de42012-02-06 15:43:23 -080049
50 /* debugging counters */
51 unsigned long bytes_to_host;
52 unsigned long bytes_to_mdm;
53 unsigned pending_reads;
54 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070055};
Shalabh Jainb0037c02013-01-18 12:47:40 -080056struct diag_bridge *__dev[MAX_DIAG_BRIDGE_DEVS];
Jack Phame32cf322011-09-26 10:20:17 -070057
Shalabh Jainb0037c02013-01-18 12:47:40 -080058int diag_bridge_open(int id, struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070059{
Shalabh Jainb0037c02013-01-18 12:47:40 -080060 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -070061
Shalabh Jainb0037c02013-01-18 12:47:40 -080062 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
63 pr_err("Invalid device ID");
64 return -ENODEV;
65 }
66
67 dev = __dev[id];
Jack Phame32cf322011-09-26 10:20:17 -070068 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -070069 pr_err("dev is null");
Jack Phame32cf322011-09-26 10:20:17 -070070 return -ENODEV;
71 }
72
Jack Phamfbd22552012-09-07 17:29:08 -070073 if (dev->ops) {
74 pr_err("bridge already opened");
75 return -EALREADY;
76 }
77
Jack Phame32cf322011-09-26 10:20:17 -070078 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080079 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070080
Hemant Kumara3d4a6e2012-10-16 17:57:08 -070081#ifdef CONFIG_PM_RUNTIME
82 dev->default_autosusp_delay = dev->udev->dev.power.autosuspend_delay;
83#endif
84 pm_runtime_set_autosuspend_delay(&dev->udev->dev,
85 AUTOSUSP_DELAY_WITH_USB);
86
Jack Pham76e61dd2012-06-14 18:48:53 -070087 kref_get(&dev->kref);
88
Jack Phame32cf322011-09-26 10:20:17 -070089 return 0;
90}
Jack Phamf6ed5582011-11-02 16:08:31 -070091EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070092
Jack Pham76e61dd2012-06-14 18:48:53 -070093static void diag_bridge_delete(struct kref *kref)
94{
95 struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
Pavankumar Kondeti52df2fd2013-04-02 14:46:24 +053096 int id = dev->id;
Jack Pham76e61dd2012-06-14 18:48:53 -070097
98 usb_put_dev(dev->udev);
Shalabh Jainb0037c02013-01-18 12:47:40 -080099 __dev[id] = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700100 kfree(dev);
101}
102
Shalabh Jainb0037c02013-01-18 12:47:40 -0800103void diag_bridge_close(int id)
Jack Phame32cf322011-09-26 10:20:17 -0700104{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800105 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700106
Shalabh Jainb0037c02013-01-18 12:47:40 -0800107 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
108 pr_err("Invalid device ID");
109 return;
110 }
111
112 dev = __dev[id];
Jack Phamfbd22552012-09-07 17:29:08 -0700113 if (!dev) {
114 pr_err("dev is null");
115 return;
116 }
117
118 if (!dev->ops) {
119 pr_err("can't close bridge that was not open");
120 return;
121 }
122
Jack Phame8741502012-06-13 17:34:07 -0700123 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700124
125 usb_kill_anchored_urbs(&dev->submitted);
Jack Phame32cf322011-09-26 10:20:17 -0700126 dev->ops = 0;
Hemant Kumara3d4a6e2012-10-16 17:57:08 -0700127
128 pm_runtime_set_autosuspend_delay(&dev->udev->dev,
129 dev->default_autosusp_delay);
130
Jack Pham76e61dd2012-06-14 18:48:53 -0700131 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700132}
Jack Phamf6ed5582011-11-02 16:08:31 -0700133EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -0700134
Jack Phamf6ed5582011-11-02 16:08:31 -0700135static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700136{
137 struct diag_bridge *dev = urb->context;
138 struct diag_bridge_ops *cbs = dev->ops;
139
Jack Phame8741502012-06-13 17:34:07 -0700140 dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
Jack Phame32cf322011-09-26 10:20:17 -0700141 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700142
Jack Pham3ec42b62012-08-31 15:36:27 -0700143 /* save error so that subsequent read/write returns ENODEV */
144 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800145 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800146
Vamsi Krishna90125642012-05-12 16:06:13 -0700147 if (cbs && cbs->read_complete_cb)
148 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700149 urb->transfer_buffer,
150 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700151 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800152
153 dev->bytes_to_host += urb->actual_length;
154 dev->pending_reads--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700155 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700156}
157
Shalabh Jainb0037c02013-01-18 12:47:40 -0800158int diag_bridge_read(int id, char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700159{
160 struct urb *urb = NULL;
161 unsigned int pipe;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800162 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700163 int ret;
164
Shalabh Jainb0037c02013-01-18 12:47:40 -0800165 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
166 pr_err("Invalid device ID");
167 return -ENODEV;
168 }
169
Jack Pham76e61dd2012-06-14 18:48:53 -0700170 pr_debug("reading %d bytes", size);
171
Shalabh Jainb0037c02013-01-18 12:47:40 -0800172 dev = __dev[id];
Jack Phamb1795542012-09-04 17:13:37 -0700173 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700174 pr_err("device is disconnected");
175 return -ENODEV;
176 }
177
Jack Phamb1795542012-09-04 17:13:37 -0700178 mutex_lock(&dev->ifc_mutex);
179 if (!dev->ifc) {
180 ret = -ENODEV;
181 goto error;
182 }
183
Jack Pham76e61dd2012-06-14 18:48:53 -0700184 if (!dev->ops) {
185 pr_err("bridge is not open");
Jack Phamb1795542012-09-04 17:13:37 -0700186 ret = -ENODEV;
187 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700188 }
Jack Phame32cf322011-09-26 10:20:17 -0700189
190 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700191 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phamb1795542012-09-04 17:13:37 -0700192 ret = -EINVAL;
193 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700194 }
195
Jack Pham3ae820f2011-12-14 16:21:04 -0800196 /* if there was a previous unrecoverable error, just quit */
Jack Phamb1795542012-09-04 17:13:37 -0700197 if (dev->err) {
198 ret = -ENODEV;
199 goto error;
200 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800201
Jack Pham76e61dd2012-06-14 18:48:53 -0700202 kref_get(&dev->kref);
203
Jack Phamb60775a2012-02-14 17:57:41 -0800204 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700205 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700206 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700207 ret = -ENOMEM;
Jack Phamb1795542012-09-04 17:13:37 -0700208 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700209 }
210
Jack Phamb60775a2012-02-14 17:57:41 -0800211 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700212 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
213 pr_err_ratelimited("read: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700214 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800215 }
216
Jack Phame32cf322011-09-26 10:20:17 -0700217 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
218 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700219 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700220 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800221 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700222
Jack Phamb60775a2012-02-14 17:57:41 -0800223 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700224 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700225 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800226 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700227 usb_unanchor_urb(urb);
Jack Phame32cf322011-09-26 10:20:17 -0700228 }
Jack Phamb60775a2012-02-14 17:57:41 -0800229 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700230
Jack Pham76e61dd2012-06-14 18:48:53 -0700231free_error:
232 usb_free_urb(urb);
Jack Phamb1795542012-09-04 17:13:37 -0700233put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700234 if (ret) /* otherwise this is done in the completion handler */
235 kref_put(&dev->kref, diag_bridge_delete);
Jack Phamb1795542012-09-04 17:13:37 -0700236error:
237 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700238 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700239}
Jack Phamf6ed5582011-11-02 16:08:31 -0700240EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700241
Jack Phamf6ed5582011-11-02 16:08:31 -0700242static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700243{
244 struct diag_bridge *dev = urb->context;
245 struct diag_bridge_ops *cbs = dev->ops;
246
Jack Phame8741502012-06-13 17:34:07 -0700247 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700248
Jack Phamb60775a2012-02-14 17:57:41 -0800249 usb_autopm_put_interface_async(dev->ifc);
250
Jack Pham3ec42b62012-08-31 15:36:27 -0700251 /* save error so that subsequent read/write returns ENODEV */
252 if (urb->status == -EPROTO)
Jack Pham3ae820f2011-12-14 16:21:04 -0800253 dev->err = urb->status;
Jack Pham3ae820f2011-12-14 16:21:04 -0800254
Vamsi Krishna90125642012-05-12 16:06:13 -0700255 if (cbs && cbs->write_complete_cb)
256 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700257 urb->transfer_buffer,
258 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700259 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800260
261 dev->bytes_to_mdm += urb->actual_length;
262 dev->pending_writes--;
Jack Pham76e61dd2012-06-14 18:48:53 -0700263 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700264}
265
Shalabh Jainb0037c02013-01-18 12:47:40 -0800266int diag_bridge_write(int id, char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700267{
268 struct urb *urb = NULL;
269 unsigned int pipe;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800270 struct diag_bridge *dev;
Jack Phame32cf322011-09-26 10:20:17 -0700271 int ret;
272
Shalabh Jainb0037c02013-01-18 12:47:40 -0800273 if (id < 0 || id >= MAX_DIAG_BRIDGE_DEVS) {
274 pr_err("Invalid device ID");
275 return -ENODEV;
276 }
277
Jack Pham76e61dd2012-06-14 18:48:53 -0700278 pr_debug("writing %d bytes", size);
279
Shalabh Jainb0037c02013-01-18 12:47:40 -0800280 dev = __dev[id];
Jack Phamb1795542012-09-04 17:13:37 -0700281 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700282 pr_err("device is disconnected");
283 return -ENODEV;
284 }
285
Jack Phamb1795542012-09-04 17:13:37 -0700286 mutex_lock(&dev->ifc_mutex);
287 if (!dev->ifc) {
288 ret = -ENODEV;
289 goto error;
290 }
291
Jack Pham76e61dd2012-06-14 18:48:53 -0700292 if (!dev->ops) {
293 pr_err("bridge is not open");
Jack Phamb1795542012-09-04 17:13:37 -0700294 ret = -ENODEV;
295 goto error;
Jack Pham76e61dd2012-06-14 18:48:53 -0700296 }
Jack Phame32cf322011-09-26 10:20:17 -0700297
298 if (!size) {
Jack Phame8741502012-06-13 17:34:07 -0700299 dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
Jack Phamb1795542012-09-04 17:13:37 -0700300 ret = -EINVAL;
301 goto error;
Jack Phame32cf322011-09-26 10:20:17 -0700302 }
303
Jack Pham3ae820f2011-12-14 16:21:04 -0800304 /* if there was a previous unrecoverable error, just quit */
Jack Phamb1795542012-09-04 17:13:37 -0700305 if (dev->err) {
306 ret = -ENODEV;
307 goto error;
308 }
Jack Pham3ae820f2011-12-14 16:21:04 -0800309
Jack Pham76e61dd2012-06-14 18:48:53 -0700310 kref_get(&dev->kref);
311
Jack Phamb60775a2012-02-14 17:57:41 -0800312 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700313 if (!urb) {
Jack Phame8741502012-06-13 17:34:07 -0700314 dev_err(&dev->ifc->dev, "unable to allocate urb\n");
Jack Pham76e61dd2012-06-14 18:48:53 -0700315 ret = -ENOMEM;
Jack Phamb1795542012-09-04 17:13:37 -0700316 goto put_error;
Jack Phame32cf322011-09-26 10:20:17 -0700317 }
318
Jack Phamb60775a2012-02-14 17:57:41 -0800319 ret = usb_autopm_get_interface(dev->ifc);
Jack Phamcca03322012-06-14 19:00:31 -0700320 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
321 pr_err_ratelimited("write: autopm_get failed:%d", ret);
Jack Pham76e61dd2012-06-14 18:48:53 -0700322 goto free_error;
Jack Phamb60775a2012-02-14 17:57:41 -0800323 }
324
Jack Phame32cf322011-09-26 10:20:17 -0700325 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
326 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700327 diag_bridge_write_cb, dev);
Jack Pham5a10c6f2012-06-26 11:41:28 -0700328 urb->transfer_flags |= URB_ZERO_PACKET;
Jack Phame32cf322011-09-26 10:20:17 -0700329 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800330 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700331
Jack Phamb60775a2012-02-14 17:57:41 -0800332 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700333 if (ret) {
Jack Phamcca03322012-06-14 19:00:31 -0700334 pr_err_ratelimited("submitting urb failed err:%d", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800335 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700336 usb_unanchor_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800337 usb_autopm_put_interface(dev->ifc);
Jack Pham76e61dd2012-06-14 18:48:53 -0700338 goto free_error;
Jack Phame32cf322011-09-26 10:20:17 -0700339 }
340
Jack Pham76e61dd2012-06-14 18:48:53 -0700341free_error:
Jack Phame32cf322011-09-26 10:20:17 -0700342 usb_free_urb(urb);
Jack Phamb1795542012-09-04 17:13:37 -0700343put_error:
Jack Pham76e61dd2012-06-14 18:48:53 -0700344 if (ret) /* otherwise this is done in the completion handler */
345 kref_put(&dev->kref, diag_bridge_delete);
Jack Phamb1795542012-09-04 17:13:37 -0700346error:
347 mutex_unlock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700348 return ret;
Jack Phame32cf322011-09-26 10:20:17 -0700349}
Jack Phamf6ed5582011-11-02 16:08:31 -0700350EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700351
Jack Pham9a08de42012-02-06 15:43:23 -0800352#if defined(CONFIG_DEBUG_FS)
353#define DEBUG_BUF_SIZE 512
354static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
355 size_t count, loff_t *ppos)
356{
Jack Pham9a08de42012-02-06 15:43:23 -0800357 char *buf;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800358 int i, ret = 0;
Jack Pham76e61dd2012-06-14 18:48:53 -0700359
Jack Pham9a08de42012-02-06 15:43:23 -0800360 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
361 if (!buf)
362 return -ENOMEM;
363
Shalabh Jainb0037c02013-01-18 12:47:40 -0800364 for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
365 struct diag_bridge *dev = __dev[i];
366 if (!dev)
367 continue;
368
369 ret += scnprintf(buf, DEBUG_BUF_SIZE,
370 "epin:%d, epout:%d\n"
371 "bytes to host: %lu\n"
372 "bytes to mdm: %lu\n"
373 "pending reads: %u\n"
374 "pending writes: %u\n"
375 "last error: %d\n",
376 dev->in_epAddr, dev->out_epAddr,
377 dev->bytes_to_host, dev->bytes_to_mdm,
378 dev->pending_reads, dev->pending_writes,
379 dev->err);
380 }
Jack Pham9a08de42012-02-06 15:43:23 -0800381
382 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
383 kfree(buf);
384 return ret;
385}
386
387static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
388 size_t count, loff_t *ppos)
389{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800390 int i;
Jack Pham9a08de42012-02-06 15:43:23 -0800391
Shalabh Jainb0037c02013-01-18 12:47:40 -0800392 for (i = 0; i < MAX_DIAG_BRIDGE_DEVS; i++) {
393 struct diag_bridge *dev = __dev[i];
394 if (dev) {
395 dev->bytes_to_host = dev->bytes_to_mdm = 0;
396 dev->pending_reads = dev->pending_writes = 0;
397 }
Jack Pham76e61dd2012-06-14 18:48:53 -0700398 }
Jack Pham9a08de42012-02-06 15:43:23 -0800399
400 return count;
401}
402
403const struct file_operations diag_stats_ops = {
404 .read = diag_read_stats,
405 .write = diag_reset_stats,
406};
407
408static struct dentry *dent;
409
410static void diag_bridge_debugfs_init(void)
411{
412 struct dentry *dfile;
413
414 dent = debugfs_create_dir("diag_bridge", 0);
415 if (IS_ERR(dent))
416 return;
417
418 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
419 if (!dfile || IS_ERR(dfile))
420 debugfs_remove(dent);
421}
422
423static void diag_bridge_debugfs_cleanup(void)
424{
425 if (dent) {
426 debugfs_remove_recursive(dent);
427 dent = NULL;
428 }
429}
430#else
431static inline void diag_bridge_debugfs_init(void) { }
432static inline void diag_bridge_debugfs_cleanup(void) { }
433#endif
434
Jack Phame32cf322011-09-26 10:20:17 -0700435static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700436diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700437{
438 struct diag_bridge *dev;
439 struct usb_host_interface *ifc_desc;
440 struct usb_endpoint_descriptor *ep_desc;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800441 int i, devid, ret = -ENOMEM;
Jack Phame32cf322011-09-26 10:20:17 -0700442 __u8 ifc_num;
443
Jack Pham76e61dd2012-06-14 18:48:53 -0700444 pr_debug("id:%lu", id->driver_info);
Jack Phame32cf322011-09-26 10:20:17 -0700445
446 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
447
448 /* is this interface supported ? */
Jack Phamf81139b2013-01-24 16:42:47 -0800449 if (ifc_num != (id->driver_info & 0xFF))
Jack Phame32cf322011-09-26 10:20:17 -0700450 return -ENODEV;
451
Jack Phamf81139b2013-01-24 16:42:47 -0800452 devid = (id->driver_info >> 8) & 0xFF;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800453 if (devid < 0 || devid >= MAX_DIAG_BRIDGE_DEVS)
454 return -ENODEV;
455
456 /* already probed? */
457 if (__dev[devid]) {
458 pr_err("Diag device already probed");
459 return -ENODEV;
460 }
461
Jack Phame32cf322011-09-26 10:20:17 -0700462 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
463 if (!dev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700464 pr_err("unable to allocate dev");
Jack Phame32cf322011-09-26 10:20:17 -0700465 return -ENOMEM;
466 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800467 dev->pdev = platform_device_alloc("diag_bridge", devid);
Jack Phame32cf322011-09-26 10:20:17 -0700468 if (!dev->pdev) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700469 pr_err("unable to allocate platform device");
Jack Phame32cf322011-09-26 10:20:17 -0700470 kfree(dev);
471 return -ENOMEM;
472 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800473 __dev[devid] = dev;
Pavankumar Kondeti52df2fd2013-04-02 14:46:24 +0530474 dev->id = devid;
Jack Phame32cf322011-09-26 10:20:17 -0700475
476 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
477 dev->ifc = ifc;
478 kref_init(&dev->kref);
Jack Phamb1795542012-09-04 17:13:37 -0700479 mutex_init(&dev->ifc_mutex);
Jack Phame32cf322011-09-26 10:20:17 -0700480 init_usb_anchor(&dev->submitted);
481
482 ifc_desc = ifc->cur_altsetting;
483 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
484 ep_desc = &ifc_desc->endpoint[i].desc;
485
486 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
487 dev->in_epAddr = ep_desc->bEndpointAddress;
488
489 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
490 dev->out_epAddr = ep_desc->bEndpointAddress;
491 }
492
493 if (!(dev->in_epAddr && dev->out_epAddr)) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700494 pr_err("could not find bulk in and bulk out endpoints");
Jack Phame32cf322011-09-26 10:20:17 -0700495 ret = -ENODEV;
496 goto error;
497 }
498
499 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800500 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700501 platform_device_add(dev->pdev);
502
Jack Phame8741502012-06-13 17:34:07 -0700503 dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700504
505 return 0;
506
507error:
508 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700509 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700510
511 return ret;
512}
513
Jack Phamf6ed5582011-11-02 16:08:31 -0700514static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700515{
516 struct diag_bridge *dev = usb_get_intfdata(ifc);
517
Jack Phame8741502012-06-13 17:34:07 -0700518 dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700519
Jack Pham1b1ba472012-06-13 16:40:15 -0700520 platform_device_unregister(dev->pdev);
Jack Phamb1795542012-09-04 17:13:37 -0700521 mutex_lock(&dev->ifc_mutex);
Jack Pham76e61dd2012-06-14 18:48:53 -0700522 dev->ifc = NULL;
Jack Phamb1795542012-09-04 17:13:37 -0700523 mutex_unlock(&dev->ifc_mutex);
Jack Pham9a08de42012-02-06 15:43:23 -0800524 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700525 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700526 usb_set_intfdata(ifc, NULL);
527}
528
Jack Phamb60775a2012-02-14 17:57:41 -0800529static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
530{
531 struct diag_bridge *dev = usb_get_intfdata(ifc);
532 struct diag_bridge_ops *cbs = dev->ops;
533 int ret = 0;
534
535 if (cbs && cbs->suspend) {
536 ret = cbs->suspend(cbs->ctxt);
537 if (ret) {
Jack Phame8741502012-06-13 17:34:07 -0700538 dev_dbg(&dev->ifc->dev,
Jack Phamb60775a2012-02-14 17:57:41 -0800539 "%s: diag veto'd suspend\n", __func__);
540 return ret;
541 }
542
543 usb_kill_anchored_urbs(&dev->submitted);
544 }
545
546 return ret;
547}
548
549static int diag_bridge_resume(struct usb_interface *ifc)
550{
551 struct diag_bridge *dev = usb_get_intfdata(ifc);
552 struct diag_bridge_ops *cbs = dev->ops;
553
554
555 if (cbs && cbs->resume)
556 cbs->resume(cbs->ctxt);
557
558 return 0;
559}
Jack Phame32cf322011-09-26 10:20:17 -0700560
561#define VALID_INTERFACE_NUM 0
Jack Phamf81139b2013-01-24 16:42:47 -0800562#define DEV_ID(n) ((n)<<8)
563
Jack Phamf6ed5582011-11-02 16:08:31 -0700564static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800565 { USB_DEVICE(0x5c6, 0x9001),
Jack Phamf81139b2013-01-24 16:42:47 -0800566 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumar7a067f12012-01-05 15:35:15 -0800567 { USB_DEVICE(0x5c6, 0x9034),
Jack Phamf81139b2013-01-24 16:42:47 -0800568 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumar7f236832011-12-16 12:13:21 -0800569 { USB_DEVICE(0x5c6, 0x9048),
Jack Phamf81139b2013-01-24 16:42:47 -0800570 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800571 { USB_DEVICE(0x5c6, 0x904C),
Jack Phamf81139b2013-01-24 16:42:47 -0800572 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
Hemant Kumarce3c5bf2012-12-06 15:52:02 -0800573 { USB_DEVICE(0x5c6, 0x9075),
Jack Phamf81139b2013-01-24 16:42:47 -0800574 .driver_info = VALID_INTERFACE_NUM | DEV_ID(0), },
575 { USB_DEVICE(0x5c6, 0x9079),
576 .driver_info = VALID_INTERFACE_NUM | DEV_ID(1), },
Jack Phame32cf322011-09-26 10:20:17 -0700577
578 {} /* terminating entry */
579};
Jack Phamf6ed5582011-11-02 16:08:31 -0700580MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700581
Jack Phamf6ed5582011-11-02 16:08:31 -0700582static struct usb_driver diag_bridge_driver = {
583 .name = "diag_bridge",
584 .probe = diag_bridge_probe,
585 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800586 .suspend = diag_bridge_suspend,
587 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700588 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800589 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700590};
591
Jack Phamf6ed5582011-11-02 16:08:31 -0700592static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700593{
594 int ret;
595
Jack Phamf6ed5582011-11-02 16:08:31 -0700596 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700597 if (ret) {
Jack Pham76e61dd2012-06-14 18:48:53 -0700598 pr_err("unable to register diag driver");
Jack Phame32cf322011-09-26 10:20:17 -0700599 return ret;
600 }
601
602 return 0;
603}
604
Jack Phamf6ed5582011-11-02 16:08:31 -0700605static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700606{
Jack Phamf6ed5582011-11-02 16:08:31 -0700607 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700608}
609
Jack Phamf6ed5582011-11-02 16:08:31 -0700610module_init(diag_bridge_init);
611module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700612
613MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700614MODULE_VERSION(DRIVER_VERSION);
615MODULE_LICENSE("GPL v2");