blob: 5ab987ec4ec899d0d7e98f0b26c1c320df45dd4a [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) {
85 /* save error so that subsequent read/write returns ESHUTDOWN */
86 dev->err = urb->status;
87 return;
88 }
89
Jack Phame32cf322011-09-26 10:20:17 -070090 cbs->read_complete_cb(cbs->ctxt,
91 urb->transfer_buffer,
92 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -070093 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -080094
95 dev->bytes_to_host += urb->actual_length;
96 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -070097}
98
Dixon Peterson32e70bb2011-12-16 13:26:45 -080099int diag_bridge_read(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700100{
101 struct urb *urb = NULL;
102 unsigned int pipe;
103 struct diag_bridge *dev = __dev;
104 int ret;
105
106 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
107
108 if (!size) {
109 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
110 return -EINVAL;
111 }
112
113 if (!dev->ifc) {
114 dev_err(&dev->udev->dev, "device is disconnected\n");
115 return -ENODEV;
116 }
117
Jack Pham3ae820f2011-12-14 16:21:04 -0800118 /* if there was a previous unrecoverable error, just quit */
119 if (dev->err)
120 return -ESHUTDOWN;
121
Jack Pham290b1082011-12-07 18:41:12 -0800122 urb = usb_alloc_urb(0, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700123 if (!urb) {
124 dev_err(&dev->udev->dev, "unable to allocate urb\n");
125 return -ENOMEM;
126 }
127
128 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
129 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700130 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700131 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800132 dev->pending_reads++;
Jack Phame32cf322011-09-26 10:20:17 -0700133
Jack Pham290b1082011-12-07 18:41:12 -0800134 ret = usb_submit_urb(urb, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700135 if (ret) {
136 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
Jack Pham9a08de42012-02-06 15:43:23 -0800137 dev->pending_reads--;
Jack Phame32cf322011-09-26 10:20:17 -0700138 usb_unanchor_urb(urb);
139 usb_free_urb(urb);
140 return ret;
141 }
142
143 usb_free_urb(urb);
144
145 return 0;
146}
Jack Phamf6ed5582011-11-02 16:08:31 -0700147EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700148
Jack Phamf6ed5582011-11-02 16:08:31 -0700149static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700150{
151 struct diag_bridge *dev = urb->context;
152 struct diag_bridge_ops *cbs = dev->ops;
153
154 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
155
Jack Pham3ae820f2011-12-14 16:21:04 -0800156 if (urb->status == -EPROTO) {
157 /* save error so that subsequent read/write returns ESHUTDOWN */
158 dev->err = urb->status;
159 return;
160 }
161
Jack Phame32cf322011-09-26 10:20:17 -0700162 cbs->write_complete_cb(cbs->ctxt,
163 urb->transfer_buffer,
164 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700165 urb->status < 0 ? urb->status : urb->actual_length);
Jack Pham9a08de42012-02-06 15:43:23 -0800166
167 dev->bytes_to_mdm += urb->actual_length;
168 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700169}
170
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800171int diag_bridge_write(char *data, int size)
Jack Phame32cf322011-09-26 10:20:17 -0700172{
173 struct urb *urb = NULL;
174 unsigned int pipe;
175 struct diag_bridge *dev = __dev;
176 int ret;
177
178 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
179
180 if (!size) {
181 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
182 return -EINVAL;
183 }
184
185 if (!dev->ifc) {
186 dev_err(&dev->udev->dev, "device is disconnected\n");
187 return -ENODEV;
188 }
189
Jack Pham3ae820f2011-12-14 16:21:04 -0800190 /* if there was a previous unrecoverable error, just quit */
191 if (dev->err)
192 return -ESHUTDOWN;
193
Jack Pham290b1082011-12-07 18:41:12 -0800194 urb = usb_alloc_urb(0, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700195 if (!urb) {
196 err("unable to allocate urb");
197 return -ENOMEM;
198 }
199
200 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
201 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700202 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700203 usb_anchor_urb(urb, &dev->submitted);
Jack Pham9a08de42012-02-06 15:43:23 -0800204 dev->pending_writes++;
Jack Phame32cf322011-09-26 10:20:17 -0700205
Jack Pham290b1082011-12-07 18:41:12 -0800206 ret = usb_submit_urb(urb, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700207 if (ret) {
Jack Pham9a08de42012-02-06 15:43:23 -0800208 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
209 dev->pending_writes--;
Jack Phame32cf322011-09-26 10:20:17 -0700210 usb_unanchor_urb(urb);
211 usb_free_urb(urb);
212 return ret;
213 }
214
215 usb_free_urb(urb);
216
217 return 0;
218}
Jack Phamf6ed5582011-11-02 16:08:31 -0700219EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700220
Jack Phamf6ed5582011-11-02 16:08:31 -0700221static void diag_bridge_delete(struct kref *kref)
Jack Phame32cf322011-09-26 10:20:17 -0700222{
223 struct diag_bridge *dev =
224 container_of(kref, struct diag_bridge, kref);
225
226 usb_put_dev(dev->udev);
227 __dev = 0;
228 kfree(dev);
229}
230
Jack Pham9a08de42012-02-06 15:43:23 -0800231#if defined(CONFIG_DEBUG_FS)
232#define DEBUG_BUF_SIZE 512
233static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
234 size_t count, loff_t *ppos)
235{
236 struct diag_bridge *dev = __dev;
237 char *buf;
238 int ret;
239
240 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
241 if (!buf)
242 return -ENOMEM;
243
244 ret = scnprintf(buf, DEBUG_BUF_SIZE,
245 "epin:%d, epout:%d\n"
246 "bytes to host: %lu\n"
247 "bytes to mdm: %lu\n"
248 "pending reads: %u\n"
249 "pending writes: %u\n"
250 "last error: %d\n",
251 dev->in_epAddr, dev->out_epAddr,
252 dev->bytes_to_host, dev->bytes_to_mdm,
253 dev->pending_reads, dev->pending_writes,
254 dev->err);
255
256 ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
257 kfree(buf);
258 return ret;
259}
260
261static ssize_t diag_reset_stats(struct file *file, const char __user *buf,
262 size_t count, loff_t *ppos)
263{
264 struct diag_bridge *dev = __dev;
265
266 dev->bytes_to_host = dev->bytes_to_mdm = 0;
267 dev->pending_reads = dev->pending_writes = 0;
268
269 return count;
270}
271
272const struct file_operations diag_stats_ops = {
273 .read = diag_read_stats,
274 .write = diag_reset_stats,
275};
276
277static struct dentry *dent;
278
279static void diag_bridge_debugfs_init(void)
280{
281 struct dentry *dfile;
282
283 dent = debugfs_create_dir("diag_bridge", 0);
284 if (IS_ERR(dent))
285 return;
286
287 dfile = debugfs_create_file("status", 0444, dent, 0, &diag_stats_ops);
288 if (!dfile || IS_ERR(dfile))
289 debugfs_remove(dent);
290}
291
292static void diag_bridge_debugfs_cleanup(void)
293{
294 if (dent) {
295 debugfs_remove_recursive(dent);
296 dent = NULL;
297 }
298}
299#else
300static inline void diag_bridge_debugfs_init(void) { }
301static inline void diag_bridge_debugfs_cleanup(void) { }
302#endif
303
Jack Phame32cf322011-09-26 10:20:17 -0700304static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700305diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700306{
307 struct diag_bridge *dev;
308 struct usb_host_interface *ifc_desc;
309 struct usb_endpoint_descriptor *ep_desc;
310 int i;
311 int ret = -ENOMEM;
312 __u8 ifc_num;
313
314 dbg("%s: id:%lu", __func__, id->driver_info);
315
316 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
317
318 /* is this interface supported ? */
319 if (ifc_num != id->driver_info)
320 return -ENODEV;
321
322 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
323 if (!dev) {
324 pr_err("%s: unable to allocate dev\n", __func__);
325 return -ENOMEM;
326 }
327 dev->pdev = platform_device_alloc("diag_bridge", -1);
328 if (!dev->pdev) {
329 pr_err("%s: unable to allocate platform device\n", __func__);
330 kfree(dev);
331 return -ENOMEM;
332 }
333 __dev = dev;
334
335 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
336 dev->ifc = ifc;
337 kref_init(&dev->kref);
338 init_usb_anchor(&dev->submitted);
339
340 ifc_desc = ifc->cur_altsetting;
341 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
342 ep_desc = &ifc_desc->endpoint[i].desc;
343
344 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
345 dev->in_epAddr = ep_desc->bEndpointAddress;
346
347 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
348 dev->out_epAddr = ep_desc->bEndpointAddress;
349 }
350
351 if (!(dev->in_epAddr && dev->out_epAddr)) {
352 err("could not find bulk in and bulk out endpoints");
353 ret = -ENODEV;
354 goto error;
355 }
356
357 usb_set_intfdata(ifc, dev);
Jack Pham9a08de42012-02-06 15:43:23 -0800358 diag_bridge_debugfs_init();
Jack Phame32cf322011-09-26 10:20:17 -0700359 platform_device_add(dev->pdev);
360
361 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
362
363 return 0;
364
365error:
366 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700367 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700368
369 return ret;
370}
371
Jack Phamf6ed5582011-11-02 16:08:31 -0700372static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700373{
374 struct diag_bridge *dev = usb_get_intfdata(ifc);
375
376 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
377
378 platform_device_del(dev->pdev);
Jack Pham9a08de42012-02-06 15:43:23 -0800379 diag_bridge_debugfs_cleanup();
Jack Phamf6ed5582011-11-02 16:08:31 -0700380 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700381 usb_set_intfdata(ifc, NULL);
382}
383
384
385#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700386static const struct usb_device_id diag_bridge_ids[] = {
Hemant Kumar7a067f12012-01-05 15:35:15 -0800387 { USB_DEVICE(0x5c6, 0x9001),
388 .driver_info = VALID_INTERFACE_NUM, },
389 { USB_DEVICE(0x5c6, 0x9034),
390 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumar7f236832011-12-16 12:13:21 -0800391 { USB_DEVICE(0x5c6, 0x9048),
Jack Phame32cf322011-09-26 10:20:17 -0700392 .driver_info = VALID_INTERFACE_NUM, },
Hemant Kumarcfc0dad2012-02-21 14:34:39 -0800393 { USB_DEVICE(0x5c6, 0x904C),
394 .driver_info = VALID_INTERFACE_NUM, },
Jack Phame32cf322011-09-26 10:20:17 -0700395
396 {} /* terminating entry */
397};
Jack Phamf6ed5582011-11-02 16:08:31 -0700398MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700399
Jack Phamf6ed5582011-11-02 16:08:31 -0700400static struct usb_driver diag_bridge_driver = {
401 .name = "diag_bridge",
402 .probe = diag_bridge_probe,
403 .disconnect = diag_bridge_disconnect,
404 .id_table = diag_bridge_ids,
Jack Phame32cf322011-09-26 10:20:17 -0700405};
406
Jack Phamf6ed5582011-11-02 16:08:31 -0700407static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700408{
409 int ret;
410
Jack Phamf6ed5582011-11-02 16:08:31 -0700411 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700412 if (ret) {
413 err("%s: unable to register diag driver",
414 __func__);
415 return ret;
416 }
417
418 return 0;
419}
420
Jack Phamf6ed5582011-11-02 16:08:31 -0700421static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700422{
Jack Phamf6ed5582011-11-02 16:08:31 -0700423 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700424}
425
Jack Phamf6ed5582011-11-02 16:08:31 -0700426module_init(diag_bridge_init);
427module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700428
429MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700430MODULE_VERSION(DRIVER_VERSION);
431MODULE_LICENSE("GPL v2");