blob: 9b60f7036f39d3beb2b0279393e737160e5e2eb7 [file] [log] [blame]
Jack Phame32cf322011-09-26 10:20:17 -07001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
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>
23#include <mach/diag_bridge.h>
24
25#define DRIVER_DESC "USB host diag bridge driver"
Jack Phamf6ed5582011-11-02 16:08:31 -070026#define DRIVER_VERSION "1.0"
Jack Phame32cf322011-09-26 10:20:17 -070027
28struct diag_bridge {
29 struct usb_device *udev;
30 struct usb_interface *ifc;
31 struct usb_anchor submitted;
32 __u8 in_epAddr;
33 __u8 out_epAddr;
Jack Pham3ae820f2011-12-14 16:21:04 -080034 int err;
Jack Phame32cf322011-09-26 10:20:17 -070035 struct kref kref;
36 struct diag_bridge_ops *ops;
37 struct platform_device *pdev;
38};
39struct diag_bridge *__dev;
40
Jack Phamf6ed5582011-11-02 16:08:31 -070041int diag_bridge_open(struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070042{
43 struct diag_bridge *dev = __dev;
44
45 if (!dev) {
46 err("dev is null");
47 return -ENODEV;
48 }
49
50 dev->ops = ops;
Jack Pham3ae820f2011-12-14 16:21:04 -080051 dev->err = 0;
Jack Phame32cf322011-09-26 10:20:17 -070052
53 return 0;
54}
Jack Phamf6ed5582011-11-02 16:08:31 -070055EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070056
Jack Phamf6ed5582011-11-02 16:08:31 -070057void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070058{
59 struct diag_bridge *dev = __dev;
60
61 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
62
63 usb_kill_anchored_urbs(&dev->submitted);
64
65 dev->ops = 0;
66}
Jack Phamf6ed5582011-11-02 16:08:31 -070067EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -070068
Jack Phamf6ed5582011-11-02 16:08:31 -070069static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -070070{
71 struct diag_bridge *dev = urb->context;
72 struct diag_bridge_ops *cbs = dev->ops;
73
74 dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
75 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070076
Jack Pham3ae820f2011-12-14 16:21:04 -080077 if (urb->status == -EPROTO) {
78 /* save error so that subsequent read/write returns ESHUTDOWN */
79 dev->err = urb->status;
80 return;
81 }
82
Jack Phame32cf322011-09-26 10:20:17 -070083 cbs->read_complete_cb(cbs->ctxt,
84 urb->transfer_buffer,
85 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -070086 urb->status < 0 ? urb->status : urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070087}
88
Jack Phamf6ed5582011-11-02 16:08:31 -070089int diag_bridge_read(char *data, size_t size)
Jack Phame32cf322011-09-26 10:20:17 -070090{
91 struct urb *urb = NULL;
92 unsigned int pipe;
93 struct diag_bridge *dev = __dev;
94 int ret;
95
96 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
97
98 if (!size) {
99 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
100 return -EINVAL;
101 }
102
103 if (!dev->ifc) {
104 dev_err(&dev->udev->dev, "device is disconnected\n");
105 return -ENODEV;
106 }
107
Jack Pham3ae820f2011-12-14 16:21:04 -0800108 /* if there was a previous unrecoverable error, just quit */
109 if (dev->err)
110 return -ESHUTDOWN;
111
Jack Pham290b1082011-12-07 18:41:12 -0800112 urb = usb_alloc_urb(0, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700113 if (!urb) {
114 dev_err(&dev->udev->dev, "unable to allocate urb\n");
115 return -ENOMEM;
116 }
117
118 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
119 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700120 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700121 usb_anchor_urb(urb, &dev->submitted);
122
Jack Pham290b1082011-12-07 18:41:12 -0800123 ret = usb_submit_urb(urb, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700124 if (ret) {
125 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
126 usb_unanchor_urb(urb);
127 usb_free_urb(urb);
128 return ret;
129 }
130
131 usb_free_urb(urb);
132
133 return 0;
134}
Jack Phamf6ed5582011-11-02 16:08:31 -0700135EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700136
Jack Phamf6ed5582011-11-02 16:08:31 -0700137static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700138{
139 struct diag_bridge *dev = urb->context;
140 struct diag_bridge_ops *cbs = dev->ops;
141
142 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
143
Jack Pham3ae820f2011-12-14 16:21:04 -0800144 if (urb->status == -EPROTO) {
145 /* save error so that subsequent read/write returns ESHUTDOWN */
146 dev->err = urb->status;
147 return;
148 }
149
Jack Phame32cf322011-09-26 10:20:17 -0700150 cbs->write_complete_cb(cbs->ctxt,
151 urb->transfer_buffer,
152 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700153 urb->status < 0 ? urb->status : urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700154}
155
Jack Phamf6ed5582011-11-02 16:08:31 -0700156int diag_bridge_write(char *data, size_t size)
Jack Phame32cf322011-09-26 10:20:17 -0700157{
158 struct urb *urb = NULL;
159 unsigned int pipe;
160 struct diag_bridge *dev = __dev;
161 int ret;
162
163 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
164
165 if (!size) {
166 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
167 return -EINVAL;
168 }
169
170 if (!dev->ifc) {
171 dev_err(&dev->udev->dev, "device is disconnected\n");
172 return -ENODEV;
173 }
174
Jack Pham3ae820f2011-12-14 16:21:04 -0800175 /* if there was a previous unrecoverable error, just quit */
176 if (dev->err)
177 return -ESHUTDOWN;
178
Jack Pham290b1082011-12-07 18:41:12 -0800179 urb = usb_alloc_urb(0, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700180 if (!urb) {
181 err("unable to allocate urb");
182 return -ENOMEM;
183 }
184
185 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
186 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700187 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700188 usb_anchor_urb(urb, &dev->submitted);
189
Jack Pham290b1082011-12-07 18:41:12 -0800190 ret = usb_submit_urb(urb, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700191 if (ret) {
192 err("submitting urb failed err:%d", ret);
193 usb_unanchor_urb(urb);
194 usb_free_urb(urb);
195 return ret;
196 }
197
198 usb_free_urb(urb);
199
200 return 0;
201}
Jack Phamf6ed5582011-11-02 16:08:31 -0700202EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700203
Jack Phamf6ed5582011-11-02 16:08:31 -0700204static void diag_bridge_delete(struct kref *kref)
Jack Phame32cf322011-09-26 10:20:17 -0700205{
206 struct diag_bridge *dev =
207 container_of(kref, struct diag_bridge, kref);
208
209 usb_put_dev(dev->udev);
210 __dev = 0;
211 kfree(dev);
212}
213
214static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700215diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700216{
217 struct diag_bridge *dev;
218 struct usb_host_interface *ifc_desc;
219 struct usb_endpoint_descriptor *ep_desc;
220 int i;
221 int ret = -ENOMEM;
222 __u8 ifc_num;
223
224 dbg("%s: id:%lu", __func__, id->driver_info);
225
226 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
227
228 /* is this interface supported ? */
229 if (ifc_num != id->driver_info)
230 return -ENODEV;
231
232 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
233 if (!dev) {
234 pr_err("%s: unable to allocate dev\n", __func__);
235 return -ENOMEM;
236 }
237 dev->pdev = platform_device_alloc("diag_bridge", -1);
238 if (!dev->pdev) {
239 pr_err("%s: unable to allocate platform device\n", __func__);
240 kfree(dev);
241 return -ENOMEM;
242 }
243 __dev = dev;
244
245 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
246 dev->ifc = ifc;
247 kref_init(&dev->kref);
248 init_usb_anchor(&dev->submitted);
249
250 ifc_desc = ifc->cur_altsetting;
251 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
252 ep_desc = &ifc_desc->endpoint[i].desc;
253
254 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
255 dev->in_epAddr = ep_desc->bEndpointAddress;
256
257 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
258 dev->out_epAddr = ep_desc->bEndpointAddress;
259 }
260
261 if (!(dev->in_epAddr && dev->out_epAddr)) {
262 err("could not find bulk in and bulk out endpoints");
263 ret = -ENODEV;
264 goto error;
265 }
266
267 usb_set_intfdata(ifc, dev);
268
269 platform_device_add(dev->pdev);
270
271 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
272
273 return 0;
274
275error:
276 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700277 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700278
279 return ret;
280}
281
Jack Phamf6ed5582011-11-02 16:08:31 -0700282static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700283{
284 struct diag_bridge *dev = usb_get_intfdata(ifc);
285
286 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
287
288 platform_device_del(dev->pdev);
Jack Phamf6ed5582011-11-02 16:08:31 -0700289 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700290 usb_set_intfdata(ifc, NULL);
291}
292
293
294#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700295static const struct usb_device_id diag_bridge_ids[] = {
Jack Phame32cf322011-09-26 10:20:17 -0700296 { USB_DEVICE(0x5c6, 0x9001),
297 .driver_info = VALID_INTERFACE_NUM, },
298
299 {} /* terminating entry */
300};
Jack Phamf6ed5582011-11-02 16:08:31 -0700301MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700302
Jack Phamf6ed5582011-11-02 16:08:31 -0700303static struct usb_driver diag_bridge_driver = {
304 .name = "diag_bridge",
305 .probe = diag_bridge_probe,
306 .disconnect = diag_bridge_disconnect,
307 .id_table = diag_bridge_ids,
Jack Phame32cf322011-09-26 10:20:17 -0700308};
309
Jack Phamf6ed5582011-11-02 16:08:31 -0700310static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700311{
312 int ret;
313
Jack Phamf6ed5582011-11-02 16:08:31 -0700314 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700315 if (ret) {
316 err("%s: unable to register diag driver",
317 __func__);
318 return ret;
319 }
320
321 return 0;
322}
323
Jack Phamf6ed5582011-11-02 16:08:31 -0700324static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700325{
Jack Phamf6ed5582011-11-02 16:08:31 -0700326 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700327}
328
Jack Phamf6ed5582011-11-02 16:08:31 -0700329module_init(diag_bridge_init);
330module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700331
332MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700333MODULE_VERSION(DRIVER_VERSION);
334MODULE_LICENSE("GPL v2");