blob: b3419f413e751d295f387f1a065afe4ea72f486b [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"
26#define DRIVER_VERSION "0.1"
27
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
40int diag_open(struct diag_bridge_ops *ops)
41{
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}
53EXPORT_SYMBOL(diag_open);
54
55void diag_close(void)
56{
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}
65EXPORT_SYMBOL(diag_close);
66
67static void diag_read_cb(struct urb *urb)
68{
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);
74 if (urb->status)
75 urb->actual_length = urb->status;
76
77 cbs->read_complete_cb(cbs->ctxt,
78 urb->transfer_buffer,
79 urb->transfer_buffer_length,
80 urb->actual_length);
81}
82
83int diag_read(char *data, size_t size)
84{
85 struct urb *urb = NULL;
86 unsigned int pipe;
87 struct diag_bridge *dev = __dev;
88 int ret;
89
90 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
91
92 if (!size) {
93 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
94 return -EINVAL;
95 }
96
97 if (!dev->ifc) {
98 dev_err(&dev->udev->dev, "device is disconnected\n");
99 return -ENODEV;
100 }
101
102 urb = usb_alloc_urb(0, GFP_KERNEL);
103 if (!urb) {
104 dev_err(&dev->udev->dev, "unable to allocate urb\n");
105 return -ENOMEM;
106 }
107
108 pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
109 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
110 diag_read_cb, dev);
111 usb_anchor_urb(urb, &dev->submitted);
112
113 ret = usb_submit_urb(urb, GFP_KERNEL);
114 if (ret) {
115 dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
116 usb_unanchor_urb(urb);
117 usb_free_urb(urb);
118 return ret;
119 }
120
121 usb_free_urb(urb);
122
123 return 0;
124}
125EXPORT_SYMBOL(diag_read);
126
127static void diag_write_cb(struct urb *urb)
128{
129 struct diag_bridge *dev = urb->context;
130 struct diag_bridge_ops *cbs = dev->ops;
131
132 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
133
134 if (urb->status)
135 urb->actual_length = urb->status;
136
137 cbs->write_complete_cb(cbs->ctxt,
138 urb->transfer_buffer,
139 urb->transfer_buffer_length,
140 urb->actual_length);
141}
142
143int diag_write(char *data, size_t size)
144{
145 struct urb *urb = NULL;
146 unsigned int pipe;
147 struct diag_bridge *dev = __dev;
148 int ret;
149
150 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
151
152 if (!size) {
153 dev_err(&dev->udev->dev, "invalid size:%d\n", size);
154 return -EINVAL;
155 }
156
157 if (!dev->ifc) {
158 dev_err(&dev->udev->dev, "device is disconnected\n");
159 return -ENODEV;
160 }
161
162 urb = usb_alloc_urb(0, GFP_KERNEL);
163 if (!urb) {
164 err("unable to allocate urb");
165 return -ENOMEM;
166 }
167
168 pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
169 usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
170 diag_write_cb, dev);
171 usb_anchor_urb(urb, &dev->submitted);
172
173 ret = usb_submit_urb(urb, GFP_KERNEL);
174 if (ret) {
175 err("submitting urb failed err:%d", ret);
176 usb_unanchor_urb(urb);
177 usb_free_urb(urb);
178 return ret;
179 }
180
181 usb_free_urb(urb);
182
183 return 0;
184}
185EXPORT_SYMBOL(diag_write);
186
187static void diag_delete(struct kref *kref)
188{
189 struct diag_bridge *dev =
190 container_of(kref, struct diag_bridge, kref);
191
192 usb_put_dev(dev->udev);
193 __dev = 0;
194 kfree(dev);
195}
196
197static int
198diag_probe(struct usb_interface *ifc, const struct usb_device_id *id)
199{
200 struct diag_bridge *dev;
201 struct usb_host_interface *ifc_desc;
202 struct usb_endpoint_descriptor *ep_desc;
203 int i;
204 int ret = -ENOMEM;
205 __u8 ifc_num;
206
207 dbg("%s: id:%lu", __func__, id->driver_info);
208
209 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
210
211 /* is this interface supported ? */
212 if (ifc_num != id->driver_info)
213 return -ENODEV;
214
215 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
216 if (!dev) {
217 pr_err("%s: unable to allocate dev\n", __func__);
218 return -ENOMEM;
219 }
220 dev->pdev = platform_device_alloc("diag_bridge", -1);
221 if (!dev->pdev) {
222 pr_err("%s: unable to allocate platform device\n", __func__);
223 kfree(dev);
224 return -ENOMEM;
225 }
226 __dev = dev;
227
228 dev->udev = usb_get_dev(interface_to_usbdev(ifc));
229 dev->ifc = ifc;
230 kref_init(&dev->kref);
231 init_usb_anchor(&dev->submitted);
232
233 ifc_desc = ifc->cur_altsetting;
234 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
235 ep_desc = &ifc_desc->endpoint[i].desc;
236
237 if (!dev->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
238 dev->in_epAddr = ep_desc->bEndpointAddress;
239
240 if (!dev->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
241 dev->out_epAddr = ep_desc->bEndpointAddress;
242 }
243
244 if (!(dev->in_epAddr && dev->out_epAddr)) {
245 err("could not find bulk in and bulk out endpoints");
246 ret = -ENODEV;
247 goto error;
248 }
249
250 usb_set_intfdata(ifc, dev);
251
252 platform_device_add(dev->pdev);
253
254 dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
255
256 return 0;
257
258error:
259 if (dev)
260 kref_put(&dev->kref, diag_delete);
261
262 return ret;
263}
264
265static void diag_disconnect(struct usb_interface *ifc)
266{
267 struct diag_bridge *dev = usb_get_intfdata(ifc);
268
269 dev_dbg(&dev->udev->dev, "%s:\n", __func__);
270
271 platform_device_del(dev->pdev);
272 kref_put(&dev->kref, diag_delete);
273 usb_set_intfdata(ifc, NULL);
274}
275
276
277#define VALID_INTERFACE_NUM 0
278static const struct usb_device_id diag_ids[] = {
279 { USB_DEVICE(0x5c6, 0x9001),
280 .driver_info = VALID_INTERFACE_NUM, },
281
282 {} /* terminating entry */
283};
284MODULE_DEVICE_TABLE(usb, diag_ids);
285
286static struct usb_driver diag_driver = {
287 .name = "diag_qc",
288 .probe = diag_probe,
289 .disconnect = diag_disconnect,
290 .id_table = diag_ids,
291};
292
293static int __init diag_init(void)
294{
295 int ret;
296
297 ret = usb_register(&diag_driver);
298 if (ret) {
299 err("%s: unable to register diag driver",
300 __func__);
301 return ret;
302 }
303
304 return 0;
305}
306
307static void __exit diag_exit(void)
308{
309 usb_deregister(&diag_driver);
310}
311
312module_init(diag_init);
313module_exit(diag_exit);
314
315MODULE_DESCRIPTION(DRIVER_DESC);
316MODULE_LICENSE("GPL V2");