blob: 96e5a900794d8993ecd0245e3c705baf22fa6cf2 [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
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/kref.h>
20#include <linux/platform_device.h>
21#include <linux/uaccess.h>
22#include <linux/usb.h>
Jack Pham9a08de42012-02-06 15:43:23 -080023#include <linux/debugfs.h>
Jack Phame32cf322011-09-26 10:20:17 -070024#include <mach/diag_bridge.h>
25
26#define DRIVER_DESC "USB host diag bridge driver"
Jack Phamf6ed5582011-11-02 16:08:31 -070027#define DRIVER_VERSION "1.0"
Jack Phame32cf322011-09-26 10:20:17 -070028
29struct diag_bridge {
30 struct usb_device *udev;
31 struct usb_interface *ifc;
32 struct usb_anchor submitted;
33 __u8 in_epAddr;
34 __u8 out_epAddr;
Jack Pham3ae820f2011-12-14 16:21:04 -080035 int err;
Jack Phame32cf322011-09-26 10:20:17 -070036 struct kref kref;
37 struct diag_bridge_ops *ops;
38 struct platform_device *pdev;
Jack Pham9a08de42012-02-06 15:43:23 -080039
40 /* debugging counters */
41 unsigned long bytes_to_host;
42 unsigned long bytes_to_mdm;
43 unsigned pending_reads;
44 unsigned pending_writes;
Jack Phame32cf322011-09-26 10:20:17 -070045};
46struct diag_bridge *__dev;
47
Jack Phamf6ed5582011-11-02 16:08:31 -070048int diag_bridge_open(struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070049{
50 struct diag_bridge *dev = __dev;
51
52 if (!dev) {
53 err("dev is null");
54 return -ENODEV;
55 }
56
57 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080058 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070059
60 return 0;
61}
Jack Phamf6ed5582011-11-02 16:08:31 -070062EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070063
Jack Phamf6ed5582011-11-02 16:08:31 -070064void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070065{
66 struct diag_bridge *dev = __dev;
67
68 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
69
70 usb_kill_anchored_urbs(&dev->submitted);
71
72 dev->ops = 0;
73}
Jack Phamf6ed5582011-11-02 16:08:31 -070074EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -070075
Jack Phamf6ed5582011-11-02 16:08:31 -070076static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -070077{
78 struct diag_bridge *dev = urb->context;
79 struct diag_bridge_ops *cbs = dev->ops;
80
81 dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
82 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070083
Jack Pham3ae820f2011-12-14 16:21:04 -080084 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -080085 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Pham3ae820f2011-12-14 16:21:04 -080086 /* save error so that subsequent read/write returns ESHUTDOWN */
87 dev->err = urb->status;
88 return;
89 }
90
Vamsi Krishna90125642012-05-12 16:06:13 -070091 if (cbs && cbs->read_complete_cb)
92 cbs->read_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -070093 urb->transfer_buffer,
94 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -070095 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -080096
97 dev->bytes_to_host += urb->actual_length;
98 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -070099}
100
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800101int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700102{
103 struct urb *urb = NULL;
104 unsigned int pipe;
105 struct diag_bridge *dev = __dev;
106 int ret;
107
108 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
109
110 if (!size) {
111 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
112 return -EINVAL;
113 }
114
115 if (!dev->ifc) {
116 dev_err(&dev->udev->dev, "device is disconnected\n");
117 return -ENODEV;
118 }
119
Jack Pham3ae820f2011-12-14 16:21:04 -0800120 /* if there was a previous unrecoverable error, just quit */
121 if (dev->err)
122 return -ESHUTDOWN;
123
Jack Phamb60775a2012-02-14 17:57:41 -0800124 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700125 if (!urb) {
126 dev_err(&dev->udev->dev, "unable to allocate urb\n");
127 return -ENOMEM;
128 }
129
Jack Phamb60775a2012-02-14 17:57:41 -0800130 ret = usb_autopm_get_interface(dev->ifc);
131 if (ret < 0) {
132 dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
133 usb_free_urb(urb);
134 return ret;
135 }
136
Jack Phame32cf322011-09-26 10:20:17 -0700137 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
138 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700139 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700140 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800141 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700142
Jack Phamb60775a2012-02-14 17:57:41 -0800143 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700144 if (ret) {
145 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800146 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700147 usb_unanchor_urb(urb);
148 usb_free_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800149 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700150 return ret;
151 }
152
Jack Phamb60775a2012-02-14 17:57:41 -0800153 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700154 usb_free_urb(urb);
155
156 return 0;
157}
Jack Phamf6ed5582011-11-02 16:08:31 -0700158EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700159
Jack Phamf6ed5582011-11-02 16:08:31 -0700160static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700161{
162 struct diag_bridge *dev = urb->context;
163 struct diag_bridge_ops *cbs = dev->ops;
164
165 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
166
Jack Phamb60775a2012-02-14 17:57:41 -0800167 usb_autopm_put_interface_async(dev->ifc);
168
Jack Pham3ae820f2011-12-14 16:21:04 -0800169 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -0800170 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Pham3ae820f2011-12-14 16:21:04 -0800171 /* save error so that subsequent read/write returns ESHUTDOWN */
172 dev->err = urb->status;
173 return;
174 }
175
Vamsi Krishna90125642012-05-12 16:06:13 -0700176 if (cbs && cbs->write_complete_cb)
177 cbs->write_complete_cb(cbs->ctxt,
Jack Phame32cf322011-09-26 10:20:17 -0700178 urb->transfer_buffer,
179 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700180 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800181
182 dev->bytes_to_mdm += urb->actual_length;
183 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700184}
185
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800186int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700187{
188 struct urb *urb = NULL;
189 unsigned int pipe;
190 struct diag_bridge *dev = __dev;
191 int ret;
192
193 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
194
195 if (!size) {
196 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
197 return -EINVAL;
198 }
199
200 if (!dev->ifc) {
201 dev_err(&dev->udev->dev, "device is disconnected\n");
202 return -ENODEV;
203 }
204
Jack Pham3ae820f2011-12-14 16:21:04 -0800205 /* if there was a previous unrecoverable error, just quit */
206 if (dev->err)
207 return -ESHUTDOWN;
208
Jack Phamb60775a2012-02-14 17:57:41 -0800209 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700210 if (!urb) {
211 err("unable to allocate urb");
212 return -ENOMEM;
213 }
214
Jack Phamb60775a2012-02-14 17:57:41 -0800215 ret = usb_autopm_get_interface(dev->ifc);
216 if (ret < 0) {
217 dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
218 usb_free_urb(urb);
219 return ret;
220 }
221
Jack Phame32cf322011-09-26 10:20:17 -0700222 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
223 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700224 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700225 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800226 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700227
Jack Phamb60775a2012-02-14 17:57:41 -0800228 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700229 if (ret) {
Jack Pham9a08de42012-02-06 15:43:23 -0800230 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
231 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700232 usb_unanchor_urb(urb);
233 usb_free_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800234 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700235 return ret;
236 }
237
238 usb_free_urb(urb);
239
240 return 0;
241}
Jack Phamf6ed5582011-11-02 16:08:31 -0700242EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700243
Jack Phamf6ed5582011-11-02 16:08:31 -0700244static void diag_bridge_delete(struct kref *kref)
Jack Phame32cf322011-09-26 10:20:17 -0700245{
246 struct diag_bridge *dev =
247 container_of(kref, struct diag_bridge, kref);
248
249 usb_put_dev(dev->udev);
250 __dev = 0;
251 kfree(dev);
252}
253
Jack Pham9a08de42012-02-06 15:43:23 -0800254#if defined(CONFIG_DEBUG_FS)
255#define DEBUG_BUF_SIZE 512
256static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
257 size_t count, loff_t *ppos)
258{
259 struct diag_bridge *dev = __dev;
260 char *buf;
261 int ret;
262
263 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
264 if (!buf)
265 return -ENOMEM;
266
267 ret = scnprintf(buf, DEBUG_BUF_SIZE,
268 "epin:%d, epout:%d\n"
269 "bytes to host: %lu\n"
270 "bytes to mdm: %lu\n"
271 "pending reads: %u\n"
272 "pending writes: %u\n"
273 "last error: %d\n",
274 dev->in_epAddr, dev->out_epAddr,
275 dev->bytes_to_host, dev->bytes_to_mdm,
276 dev->pending_reads, dev->pending_writes,
277 dev->err);
278
279 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
280 kfree(buf);
281 return ret;
282}
283
284static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
285 size_t count, loff_t *ppos)
286{
287 struct diag_bridge *dev = __dev;
288
289 dev->bytes_to_host = dev->bytes_to_mdm = 0;
290 dev->pending_reads = dev->pending_writes = 0;
291
292 return count;
293}
294
295const struct file_operations diag_stats_ops = {
296 .read = diag_read_stats,
297 .write = diag_reset_stats,
298};
299
300static struct dentry *dent;
301
302static void diag_bridge_debugfs_init(void)
303{
304 struct dentry *dfile;
305
306 dent = debugfs_create_dir("diag_bridge", 0);
307 if (IS_ERR(dent))
308 return;
309
310 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
311 if (!dfile || IS_ERR(dfile))
312 debugfs_remove(dent);
313}
314
315static void diag_bridge_debugfs_cleanup(void)
316{
317 if (dent) {
318 debugfs_remove_recursive(dent);
319 dent = NULL;
320 }
321}
322#else
323static inline void diag_bridge_debugfs_init(void) { }
324static inline void diag_bridge_debugfs_cleanup(void) { }
325#endif
326
Jack Phame32cf322011-09-26 10:20:17 -0700327static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700328diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700329{
330 struct diag_bridge *dev;
331 struct usb_host_interface *ifc_desc;
332 struct usb_endpoint_descriptor *ep_desc;
333 int i;
334 int ret = -ENOMEM;
335 __u8 ifc_num;
336
337 dbg("%s: id:%lu", __func__, id->driver_info);
338
339 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
340
341 /* is this interface supported ? */
342 if (ifc_num != id->driver_info)
343 return -ENODEV;
344
345 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
346 if (!dev) {
347 pr_err("%s: unable to allocate dev\n", __func__);
348 return -ENOMEM;
349 }
350 dev->pdev = platform_device_alloc("diag_bridge", -1);
351 if (!dev->pdev) {
352 pr_err("%s: unable to allocate platform device\n", __func__);
353 kfree(dev);
354 return -ENOMEM;
355 }
356 __dev = dev;
357
358 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
359 dev->ifc = ifc;
360 kref_init(&dev->kref);
361 init_usb_anchor(&dev->submitted);
362
363 ifc_desc = ifc->cur_altsetting;
364 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
365 ep_desc = &ifc_desc->endpoint[i].desc;
366
367 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
368 dev->in_epAddr = ep_desc->bEndpointAddress;
369
370 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
371 dev->out_epAddr = ep_desc->bEndpointAddress;
372 }
373
374 if (!(dev->in_epAddr && dev->out_epAddr)) {
375 err("could not find bulk in and bulk out endpoints");
376 ret = -ENODEV;
377 goto error;
378 }
379
380 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800381 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700382 platform_device_add(dev->pdev);
383
384 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
385
386 return 0;
387
388error:
389 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700390 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700391
392 return ret;
393}
394
Jack Phamf6ed5582011-11-02 16:08:31 -0700395static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700396{
397 struct diag_bridge *dev = usb_get_intfdata(ifc);
398
399 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
400
401 platform_device_del(dev->pdev);
Jack Pham9a08de42012-02-06 15:43:23 -0800402 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700403 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700404 usb_set_intfdata(ifc, NULL);
405}
406
Jack Phamb60775a2012-02-14 17:57:41 -0800407static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
408{
409 struct diag_bridge *dev = usb_get_intfdata(ifc);
410 struct diag_bridge_ops *cbs = dev->ops;
411 int ret = 0;
412
413 if (cbs && cbs->suspend) {
414 ret = cbs->suspend(cbs->ctxt);
415 if (ret) {
416 dev_dbg(&dev->udev->dev,
417 "%s: diag veto'd suspend\n", __func__);
418 return ret;
419 }
420
421 usb_kill_anchored_urbs(&dev->submitted);
422 }
423
424 return ret;
425}
426
427static int diag_bridge_resume(struct usb_interface *ifc)
428{
429 struct diag_bridge *dev = usb_get_intfdata(ifc);
430 struct diag_bridge_ops *cbs = dev->ops;
431
432
433 if (cbs && cbs->resume)
434 cbs->resume(cbs->ctxt);
435
436 return 0;
437}
Jack Phame32cf322011-09-26 10:20:17 -0700438
439#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700440static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800441 { USB_DEVICE(0x5c6, 0x9001),
442 .driver_info = VALID_INTERFACE_NUM, },
443 { USB_DEVICE(0x5c6, 0x9034),
444 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800445 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700446 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800447 { USB_DEVICE(0x5c6, 0x904C),
448 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700449
450 {} /* terminating entry */
451};
Jack Phamf6ed5582011-11-02 16:08:31 -0700452MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700453
Jack Phamf6ed5582011-11-02 16:08:31 -0700454static struct usb_driver diag_bridge_driver = {
455 .name = "diag_bridge",
456 .probe = diag_bridge_probe,
457 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800458 .suspend = diag_bridge_suspend,
459 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700460 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800461 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700462};
463
Jack Phamf6ed5582011-11-02 16:08:31 -0700464static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700465{
466 int ret;
467
Jack Phamf6ed5582011-11-02 16:08:31 -0700468 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700469 if (ret) {
Jack Phamb60775a2012-02-14 17:57:41 -0800470 err("%s: unable to register diag driver", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700471 return ret;
472 }
473
474 return 0;
475}
476
Jack Phamf6ed5582011-11-02 16:08:31 -0700477static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700478{
Jack Phamf6ed5582011-11-02 16:08:31 -0700479 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700480}
481
Jack Phamf6ed5582011-11-02 16:08:31 -0700482module_init(diag_bridge_init);
483module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700484
485MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700486MODULE_VERSION(DRIVER_VERSION);
487MODULE_LICENSE("GPL v2");