blob: 97949184075061461041b76cfc6dbe44e92499bf [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
Jack Phame32cf322011-09-26 10:20:17 -070091 cbs->read_complete_cb(cbs->ctxt,
92 urb->transfer_buffer,
93 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -070094 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -080095
96 dev->bytes_to_host += urb->actual_length;
97 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -070098}
99
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800100int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700101{
102 struct urb *urb = NULL;
103 unsigned int pipe;
104 struct diag_bridge *dev = __dev;
105 int ret;
106
107 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
108
109 if (!size) {
110 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
111 return -EINVAL;
112 }
113
114 if (!dev->ifc) {
115 dev_err(&dev->udev->dev, "device is disconnected\n");
116 return -ENODEV;
117 }
118
Jack Pham3ae820f2011-12-14 16:21:04 -0800119 /* if there was a previous unrecoverable error, just quit */
120 if (dev->err)
121 return -ESHUTDOWN;
122
Jack Phamb60775a2012-02-14 17:57:41 -0800123 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700124 if (!urb) {
125 dev_err(&dev->udev->dev, "unable to allocate urb\n");
126 return -ENOMEM;
127 }
128
Jack Phamb60775a2012-02-14 17:57:41 -0800129 ret = usb_autopm_get_interface(dev->ifc);
130 if (ret < 0) {
131 dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
132 usb_free_urb(urb);
133 return ret;
134 }
135
Jack Phame32cf322011-09-26 10:20:17 -0700136 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
137 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700138 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700139 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800140 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700141
Jack Phamb60775a2012-02-14 17:57:41 -0800142 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700143 if (ret) {
144 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800145 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700146 usb_unanchor_urb(urb);
147 usb_free_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800148 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700149 return ret;
150 }
151
Jack Phamb60775a2012-02-14 17:57:41 -0800152 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700153 usb_free_urb(urb);
154
155 return 0;
156}
Jack Phamf6ed5582011-11-02 16:08:31 -0700157EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700158
Jack Phamf6ed5582011-11-02 16:08:31 -0700159static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700160{
161 struct diag_bridge *dev = urb->context;
162 struct diag_bridge_ops *cbs = dev->ops;
163
164 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
165
Jack Phamb60775a2012-02-14 17:57:41 -0800166 usb_autopm_put_interface_async(dev->ifc);
167
Jack Pham3ae820f2011-12-14 16:21:04 -0800168 if (urb->status == -EPROTO) {
Jack Phamb60775a2012-02-14 17:57:41 -0800169 dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
Jack Pham3ae820f2011-12-14 16:21:04 -0800170 /* save error so that subsequent read/write returns ESHUTDOWN */
171 dev->err = urb->status;
172 return;
173 }
174
Jack Phame32cf322011-09-26 10:20:17 -0700175 cbs->write_complete_cb(cbs->ctxt,
176 urb->transfer_buffer,
177 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700178 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800179
180 dev->bytes_to_mdm += urb->actual_length;
181 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700182}
183
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800184int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700185{
186 struct urb *urb = NULL;
187 unsigned int pipe;
188 struct diag_bridge *dev = __dev;
189 int ret;
190
191 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
192
193 if (!size) {
194 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
195 return -EINVAL;
196 }
197
198 if (!dev->ifc) {
199 dev_err(&dev->udev->dev, "device is disconnected\n");
200 return -ENODEV;
201 }
202
Jack Pham3ae820f2011-12-14 16:21:04 -0800203 /* if there was a previous unrecoverable error, just quit */
204 if (dev->err)
205 return -ESHUTDOWN;
206
Jack Phamb60775a2012-02-14 17:57:41 -0800207 urb = usb_alloc_urb(0, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700208 if (!urb) {
209 err("unable to allocate urb");
210 return -ENOMEM;
211 }
212
Jack Phamb60775a2012-02-14 17:57:41 -0800213 ret = usb_autopm_get_interface(dev->ifc);
214 if (ret < 0) {
215 dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
216 usb_free_urb(urb);
217 return ret;
218 }
219
Jack Phame32cf322011-09-26 10:20:17 -0700220 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
221 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700222 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700223 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800224 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700225
Jack Phamb60775a2012-02-14 17:57:41 -0800226 ret = usb_submit_urb(urb, GFP_KERNEL);
Jack Phame32cf322011-09-26 10:20:17 -0700227 if (ret) {
Jack Pham9a08de42012-02-06 15:43:23 -0800228 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
229 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700230 usb_unanchor_urb(urb);
231 usb_free_urb(urb);
Jack Phamb60775a2012-02-14 17:57:41 -0800232 usb_autopm_put_interface(dev->ifc);
Jack Phame32cf322011-09-26 10:20:17 -0700233 return ret;
234 }
235
236 usb_free_urb(urb);
237
238 return 0;
239}
Jack Phamf6ed5582011-11-02 16:08:31 -0700240EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700241
Jack Phamf6ed5582011-11-02 16:08:31 -0700242static void diag_bridge_delete(struct kref *kref)
Jack Phame32cf322011-09-26 10:20:17 -0700243{
244 struct diag_bridge *dev =
245 container_of(kref, struct diag_bridge, kref);
246
247 usb_put_dev(dev->udev);
248 __dev = 0;
249 kfree(dev);
250}
251
Jack Pham9a08de42012-02-06 15:43:23 -0800252#if defined(CONFIG_DEBUG_FS)
253#define DEBUG_BUF_SIZE 512
254static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
255 size_t count, loff_t *ppos)
256{
257 struct diag_bridge *dev = __dev;
258 char *buf;
259 int ret;
260
261 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
262 if (!buf)
263 return -ENOMEM;
264
265 ret = scnprintf(buf, DEBUG_BUF_SIZE,
266 "epin:%d, epout:%d\n"
267 "bytes to host: %lu\n"
268 "bytes to mdm: %lu\n"
269 "pending reads: %u\n"
270 "pending writes: %u\n"
271 "last error: %d\n",
272 dev->in_epAddr, dev->out_epAddr,
273 dev->bytes_to_host, dev->bytes_to_mdm,
274 dev->pending_reads, dev->pending_writes,
275 dev->err);
276
277 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
278 kfree(buf);
279 return ret;
280}
281
282static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
283 size_t count, loff_t *ppos)
284{
285 struct diag_bridge *dev = __dev;
286
287 dev->bytes_to_host = dev->bytes_to_mdm = 0;
288 dev->pending_reads = dev->pending_writes = 0;
289
290 return count;
291}
292
293const struct file_operations diag_stats_ops = {
294 .read = diag_read_stats,
295 .write = diag_reset_stats,
296};
297
298static struct dentry *dent;
299
300static void diag_bridge_debugfs_init(void)
301{
302 struct dentry *dfile;
303
304 dent = debugfs_create_dir("diag_bridge", 0);
305 if (IS_ERR(dent))
306 return;
307
308 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
309 if (!dfile || IS_ERR(dfile))
310 debugfs_remove(dent);
311}
312
313static void diag_bridge_debugfs_cleanup(void)
314{
315 if (dent) {
316 debugfs_remove_recursive(dent);
317 dent = NULL;
318 }
319}
320#else
321static inline void diag_bridge_debugfs_init(void) { }
322static inline void diag_bridge_debugfs_cleanup(void) { }
323#endif
324
Jack Phame32cf322011-09-26 10:20:17 -0700325static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700326diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700327{
328 struct diag_bridge *dev;
329 struct usb_host_interface *ifc_desc;
330 struct usb_endpoint_descriptor *ep_desc;
331 int i;
332 int ret = -ENOMEM;
333 __u8 ifc_num;
334
335 dbg("%s: id:%lu", __func__, id->driver_info);
336
337 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
338
339 /* is this interface supported ? */
340 if (ifc_num != id->driver_info)
341 return -ENODEV;
342
343 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
344 if (!dev) {
345 pr_err("%s: unable to allocate dev\n", __func__);
346 return -ENOMEM;
347 }
348 dev->pdev = platform_device_alloc("diag_bridge", -1);
349 if (!dev->pdev) {
350 pr_err("%s: unable to allocate platform device\n", __func__);
351 kfree(dev);
352 return -ENOMEM;
353 }
354 __dev = dev;
355
356 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
357 dev->ifc = ifc;
358 kref_init(&dev->kref);
359 init_usb_anchor(&dev->submitted);
360
361 ifc_desc = ifc->cur_altsetting;
362 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
363 ep_desc = &ifc_desc->endpoint[i].desc;
364
365 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
366 dev->in_epAddr = ep_desc->bEndpointAddress;
367
368 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
369 dev->out_epAddr = ep_desc->bEndpointAddress;
370 }
371
372 if (!(dev->in_epAddr && dev->out_epAddr)) {
373 err("could not find bulk in and bulk out endpoints");
374 ret = -ENODEV;
375 goto error;
376 }
377
378 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800379 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700380 platform_device_add(dev->pdev);
381
382 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
383
384 return 0;
385
386error:
387 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700388 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700389
390 return ret;
391}
392
Jack Phamf6ed5582011-11-02 16:08:31 -0700393static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700394{
395 struct diag_bridge *dev = usb_get_intfdata(ifc);
396
397 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
398
399 platform_device_del(dev->pdev);
Jack Pham9a08de42012-02-06 15:43:23 -0800400 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700401 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700402 usb_set_intfdata(ifc, NULL);
403}
404
Jack Phamb60775a2012-02-14 17:57:41 -0800405static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
406{
407 struct diag_bridge *dev = usb_get_intfdata(ifc);
408 struct diag_bridge_ops *cbs = dev->ops;
409 int ret = 0;
410
411 if (cbs && cbs->suspend) {
412 ret = cbs->suspend(cbs->ctxt);
413 if (ret) {
414 dev_dbg(&dev->udev->dev,
415 "%s: diag veto'd suspend\n", __func__);
416 return ret;
417 }
418
419 usb_kill_anchored_urbs(&dev->submitted);
420 }
421
422 return ret;
423}
424
425static int diag_bridge_resume(struct usb_interface *ifc)
426{
427 struct diag_bridge *dev = usb_get_intfdata(ifc);
428 struct diag_bridge_ops *cbs = dev->ops;
429
430
431 if (cbs && cbs->resume)
432 cbs->resume(cbs->ctxt);
433
434 return 0;
435}
Jack Phame32cf322011-09-26 10:20:17 -0700436
437#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700438static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800439 { USB_DEVICE(0x5c6, 0x9001),
440 .driver_info = VALID_INTERFACE_NUM, },
441 { USB_DEVICE(0x5c6, 0x9034),
442 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800443 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700444 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800445 { USB_DEVICE(0x5c6, 0x904C),
446 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700447
448 {} /* terminating entry */
449};
Jack Phamf6ed5582011-11-02 16:08:31 -0700450MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700451
Jack Phamf6ed5582011-11-02 16:08:31 -0700452static struct usb_driver diag_bridge_driver = {
453 .name = "diag_bridge",
454 .probe = diag_bridge_probe,
455 .disconnect = diag_bridge_disconnect,
Jack Phamb60775a2012-02-14 17:57:41 -0800456 .suspend = diag_bridge_suspend,
457 .resume = diag_bridge_resume,
Jack Phamf6ed5582011-11-02 16:08:31 -0700458 .id_table = diag_bridge_ids,
Jack Phamb60775a2012-02-14 17:57:41 -0800459 .supports_autosuspend = 1,
Jack Phame32cf322011-09-26 10:20:17 -0700460};
461
Jack Phamf6ed5582011-11-02 16:08:31 -0700462static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700463{
464 int ret;
465
Jack Phamf6ed5582011-11-02 16:08:31 -0700466 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700467 if (ret) {
Jack Phamb60775a2012-02-14 17:57:41 -0800468 err("%s: unable to register diag driver", __func__);
Jack Phame32cf322011-09-26 10:20:17 -0700469 return ret;
470 }
471
472 return 0;
473}
474
Jack Phamf6ed5582011-11-02 16:08:31 -0700475static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700476{
Jack Phamf6ed5582011-11-02 16:08:31 -0700477 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700478}
479
Jack Phamf6ed5582011-11-02 16:08:31 -0700480module_init(diag_bridge_init);
481module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700482
483MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700484MODULE_VERSION(DRIVER_VERSION);
485MODULE_LICENSE("GPL v2");