blob: 00b2ec1d8adbd2d56a223790a2b0934d17874991 [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;
34 struct kref kref;
35 struct diag_bridge_ops *ops;
36 struct platform_device *pdev;
37};
38struct diag_bridge *__dev;
39
Jack Phamf6ed5582011-11-02 16:08:31 -070040int diag_bridge_open(struct diag_bridge_ops *ops)
Jack Phame32cf322011-09-26 10:20:17 -070041{
42 struct diag_bridge *dev = __dev;
43
44 if (!dev) {
45 err("dev is null");
46 return -ENODEV;
47 }
48
49 dev->ops = ops;
50
51 return 0;
52}
Jack Phamf6ed5582011-11-02 16:08:31 -070053EXPORT_SYMBOL(diag_bridge_open);
Jack Phame32cf322011-09-26 10:20:17 -070054
Jack Phamf6ed5582011-11-02 16:08:31 -070055void diag_bridge_close(void)
Jack Phame32cf322011-09-26 10:20:17 -070056{
57 struct diag_bridge *dev = __dev;
58
59 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
60
61 usb_kill_anchored_urbs(&dev->submitted);
62
63 dev->ops = 0;
64}
Jack Phamf6ed5582011-11-02 16:08:31 -070065EXPORT_SYMBOL(diag_bridge_close);
Jack Phame32cf322011-09-26 10:20:17 -070066
Jack Phamf6ed5582011-11-02 16:08:31 -070067static void diag_bridge_read_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -070068{
69 struct diag_bridge *dev = urb->context;
70 struct diag_bridge_ops *cbs = dev->ops;
71
72 dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
73 urb->status, urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070074
75 cbs->read_complete_cb(cbs->ctxt,
76 urb->transfer_buffer,
77 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -070078 urb->status < 0 ? urb->status : urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -070079}
80
Jack Phamf6ed5582011-11-02 16:08:31 -070081int diag_bridge_read(char *data, size_t size)
Jack Phame32cf322011-09-26 10:20:17 -070082{
83 struct urb *urb = NULL;
84 unsigned int pipe;
85 struct diag_bridge *dev = __dev;
86 int ret;
87
88 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
89
90 if (!size) {
91 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
92 return -EINVAL;
93 }
94
95 if (!dev->ifc) {
96 dev_err(&dev->udev->dev, "device is disconnected\n");
97 return -ENODEV;
98 }
99
Jack Pham290b1082011-12-07 18:41:12 -0800100 urb = usb_alloc_urb(0, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700101 if (!urb) {
102 dev_err(&dev->udev->dev, "unable to allocate urb\n");
103 return -ENOMEM;
104 }
105
106 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
107 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700108 diag_bridge_read_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700109 usb_anchor_urb(urb, &dev->submitted);
110
Jack Pham290b1082011-12-07 18:41:12 -0800111 ret = usb_submit_urb(urb, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700112 if (ret) {
113 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
114 usb_unanchor_urb(urb);
115 usb_free_urb(urb);
116 return ret;
117 }
118
119 usb_free_urb(urb);
120
121 return 0;
122}
Jack Phamf6ed5582011-11-02 16:08:31 -0700123EXPORT_SYMBOL(diag_bridge_read);
Jack Phame32cf322011-09-26 10:20:17 -0700124
Jack Phamf6ed5582011-11-02 16:08:31 -0700125static void diag_bridge_write_cb(struct urb *urb)
Jack Phame32cf322011-09-26 10:20:17 -0700126{
127 struct diag_bridge *dev = urb->context;
128 struct diag_bridge_ops *cbs = dev->ops;
129
130 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
131
Jack Phame32cf322011-09-26 10:20:17 -0700132 cbs->write_complete_cb(cbs->ctxt,
133 urb->transfer_buffer,
134 urb->transfer_buffer_length,
Jack Phamf6ed5582011-11-02 16:08:31 -0700135 urb->status < 0 ? urb->status : urb->actual_length);
Jack Phame32cf322011-09-26 10:20:17 -0700136}
137
Jack Phamf6ed5582011-11-02 16:08:31 -0700138int diag_bridge_write(char *data, size_t size)
Jack Phame32cf322011-09-26 10:20:17 -0700139{
140 struct urb *urb = NULL;
141 unsigned int pipe;
142 struct diag_bridge *dev = __dev;
143 int ret;
144
145 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
146
147 if (!size) {
148 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
149 return -EINVAL;
150 }
151
152 if (!dev->ifc) {
153 dev_err(&dev->udev->dev, "device is disconnected\n");
154 return -ENODEV;
155 }
156
Jack Pham290b1082011-12-07 18:41:12 -0800157 urb = usb_alloc_urb(0, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700158 if (!urb) {
159 err("unable to allocate urb");
160 return -ENOMEM;
161 }
162
163 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
164 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
Jack Phamf6ed5582011-11-02 16:08:31 -0700165 diag_bridge_write_cb, dev);
Jack Phame32cf322011-09-26 10:20:17 -0700166 usb_anchor_urb(urb, &dev->submitted);
167
Jack Pham290b1082011-12-07 18:41:12 -0800168 ret = usb_submit_urb(urb, GFP_ATOMIC);
Jack Phame32cf322011-09-26 10:20:17 -0700169 if (ret) {
170 err("submitting urb failed err:%d", ret);
171 usb_unanchor_urb(urb);
172 usb_free_urb(urb);
173 return ret;
174 }
175
176 usb_free_urb(urb);
177
178 return 0;
179}
Jack Phamf6ed5582011-11-02 16:08:31 -0700180EXPORT_SYMBOL(diag_bridge_write);
Jack Phame32cf322011-09-26 10:20:17 -0700181
Jack Phamf6ed5582011-11-02 16:08:31 -0700182static void diag_bridge_delete(struct kref *kref)
Jack Phame32cf322011-09-26 10:20:17 -0700183{
184 struct diag_bridge *dev =
185 container_of(kref, struct diag_bridge, kref);
186
187 usb_put_dev(dev->udev);
188 __dev = 0;
189 kfree(dev);
190}
191
192static int
Jack Phamf6ed5582011-11-02 16:08:31 -0700193diag_bridge_probe(struct usb_interface *ifc, const struct usb_device_id *id)
Jack Phame32cf322011-09-26 10:20:17 -0700194{
195 struct diag_bridge *dev;
196 struct usb_host_interface *ifc_desc;
197 struct usb_endpoint_descriptor *ep_desc;
198 int i;
199 int ret = -ENOMEM;
200 __u8 ifc_num;
201
202 dbg("%s: id:%lu", __func__, id->driver_info);
203
204 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
205
206 /* is this interface supported ? */
207 if (ifc_num != id->driver_info)
208 return -ENODEV;
209
210 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
211 if (!dev) {
212 pr_err("%s: unable to allocate dev\n", __func__);
213 return -ENOMEM;
214 }
215 dev->pdev = platform_device_alloc("diag_bridge", -1);
216 if (!dev->pdev) {
217 pr_err("%s: unable to allocate platform device\n", __func__);
218 kfree(dev);
219 return -ENOMEM;
220 }
221 __dev = dev;
222
223 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
224 dev->ifc = ifc;
225 kref_init(&dev->kref);
226 init_usb_anchor(&dev->submitted);
227
228 ifc_desc = ifc->cur_altsetting;
229 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
230 ep_desc = &ifc_desc->endpoint[i].desc;
231
232 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
233 dev->in_epAddr = ep_desc->bEndpointAddress;
234
235 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
236 dev->out_epAddr = ep_desc->bEndpointAddress;
237 }
238
239 if (!(dev->in_epAddr && dev->out_epAddr)) {
240 err("could not find bulk in and bulk out endpoints");
241 ret = -ENODEV;
242 goto error;
243 }
244
245 usb_set_intfdata(ifc, dev);
246
247 platform_device_add(dev->pdev);
248
249 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
250
251 return 0;
252
253error:
254 if (dev)
Jack Phamf6ed5582011-11-02 16:08:31 -0700255 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700256
257 return ret;
258}
259
Jack Phamf6ed5582011-11-02 16:08:31 -0700260static void diag_bridge_disconnect(struct usb_interface *ifc)
Jack Phame32cf322011-09-26 10:20:17 -0700261{
262 struct diag_bridge *dev = usb_get_intfdata(ifc);
263
264 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
265
266 platform_device_del(dev->pdev);
Jack Phamf6ed5582011-11-02 16:08:31 -0700267 kref_put(&dev->kref, diag_bridge_delete);
Jack Phame32cf322011-09-26 10:20:17 -0700268 usb_set_intfdata(ifc, NULL);
269}
270
271
272#define VALID_INTERFACE_NUM 0
Jack Phamf6ed5582011-11-02 16:08:31 -0700273static const struct usb_device_id diag_bridge_ids[] = {
Jack Phame32cf322011-09-26 10:20:17 -0700274 { USB_DEVICE(0x5c6, 0x9001),
275 .driver_info = VALID_INTERFACE_NUM, },
276
277 {} /* terminating entry */
278};
Jack Phamf6ed5582011-11-02 16:08:31 -0700279MODULE_DEVICE_TABLE(usb, diag_bridge_ids);
Jack Phame32cf322011-09-26 10:20:17 -0700280
Jack Phamf6ed5582011-11-02 16:08:31 -0700281static struct usb_driver diag_bridge_driver = {
282 .name = "diag_bridge",
283 .probe = diag_bridge_probe,
284 .disconnect = diag_bridge_disconnect,
285 .id_table = diag_bridge_ids,
Jack Phame32cf322011-09-26 10:20:17 -0700286};
287
Jack Phamf6ed5582011-11-02 16:08:31 -0700288static int __init diag_bridge_init(void)
Jack Phame32cf322011-09-26 10:20:17 -0700289{
290 int ret;
291
Jack Phamf6ed5582011-11-02 16:08:31 -0700292 ret = usb_register(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700293 if (ret) {
294 err("%s: unable to register diag driver",
295 __func__);
296 return ret;
297 }
298
299 return 0;
300}
301
Jack Phamf6ed5582011-11-02 16:08:31 -0700302static void __exit diag_bridge_exit(void)
Jack Phame32cf322011-09-26 10:20:17 -0700303{
Jack Phamf6ed5582011-11-02 16:08:31 -0700304 usb_deregister(&diag_bridge_driver);
Jack Phame32cf322011-09-26 10:20:17 -0700305}
306
Jack Phamf6ed5582011-11-02 16:08:31 -0700307module_init(diag_bridge_init);
308module_exit(diag_bridge_exit);
Jack Phame32cf322011-09-26 10:20:17 -0700309
310MODULE_DESCRIPTION(DRIVER_DESC);
Jack Phamf6ed5582011-11-02 16:08:31 -0700311MODULE_VERSION(DRIVER_VERSION);
312MODULE_LICENSE("GPL v2");