1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/compat.h>
17#include <malloc.h>
18#include <asm/cache.h>
19#include <asm/dma-mapping.h>
20#include <common.h>
21#include <dm.h>
22#include <dm/device-internal.h>
23#include <linux/usb/ch9.h>
24#include <linux/usb/gadget.h>
25
26
27
28
29
30
31
32
33
34
35
36struct usb_udc {
37 struct usb_gadget_driver *driver;
38 struct usb_gadget *gadget;
39 struct device dev;
40 struct list_head list;
41};
42
43static struct class *udc_class;
44static LIST_HEAD(udc_list);
45DEFINE_MUTEX(udc_lock);
46
47
48
49int usb_gadget_map_request(struct usb_gadget *gadget,
50 struct usb_request *req, int is_in)
51{
52 if (req->length == 0)
53 return 0;
54
55 req->dma = dma_map_single(req->buf, req->length,
56 is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
57
58 return 0;
59}
60EXPORT_SYMBOL_GPL(usb_gadget_map_request);
61
62void usb_gadget_unmap_request(struct usb_gadget *gadget,
63 struct usb_request *req, int is_in)
64{
65 if (req->length == 0)
66 return;
67
68 dma_unmap_single((void *)(uintptr_t)req->dma, req->length,
69 is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
70}
71EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
72
73
74
75
76
77
78
79
80
81
82void usb_gadget_giveback_request(struct usb_ep *ep,
83 struct usb_request *req)
84{
85 req->complete(ep, req);
86}
87EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
88
89
90
91void usb_gadget_set_state(struct usb_gadget *gadget,
92 enum usb_device_state state)
93{
94 gadget->state = state;
95}
96EXPORT_SYMBOL_GPL(usb_gadget_set_state);
97
98
99
100
101
102
103
104
105
106
107
108
109void usb_gadget_udc_reset(struct usb_gadget *gadget,
110 struct usb_gadget_driver *driver)
111{
112 driver->reset(gadget);
113 usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
114}
115EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130static inline int usb_gadget_udc_start(struct usb_udc *udc)
131{
132 return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
133}
134
135
136
137
138
139
140
141
142
143
144
145
146
147static inline void usb_gadget_udc_stop(struct usb_udc *udc)
148{
149 udc->gadget->ops->udc_stop(udc->gadget);
150}
151
152
153
154
155
156
157
158
159static void usb_udc_release(struct device *dev)
160{
161 struct usb_udc *udc;
162
163 udc = container_of(dev, struct usb_udc, dev);
164 kfree(udc);
165}
166
167
168
169
170
171
172
173
174
175
176int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
177 void (*release)(struct device *dev))
178{
179 struct usb_udc *udc;
180 int ret = -ENOMEM;
181
182 udc = kzalloc(sizeof(*udc), GFP_KERNEL);
183 if (!udc)
184 goto err1;
185
186 dev_set_name(&gadget->dev, "gadget");
187 gadget->dev.parent = parent;
188
189 udc->dev.release = usb_udc_release;
190 udc->dev.class = udc_class;
191 udc->dev.parent = parent;
192
193 udc->gadget = gadget;
194
195 mutex_lock(&udc_lock);
196 list_add_tail(&udc->list, &udc_list);
197
198 usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
199
200 mutex_unlock(&udc_lock);
201
202 return 0;
203
204err1:
205 return ret;
206}
207EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
208
209
210
211
212
213
214
215
216
217int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
218{
219 return usb_add_gadget_udc_release(parent, gadget, NULL);
220}
221EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
222
223static void usb_gadget_remove_driver(struct usb_udc *udc)
224{
225 dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
226 udc->driver->function);
227
228 usb_gadget_disconnect(udc->gadget);
229 udc->driver->disconnect(udc->gadget);
230 udc->driver->unbind(udc->gadget);
231 usb_gadget_udc_stop(udc);
232
233 udc->driver = NULL;
234}
235
236
237
238
239
240
241
242
243void usb_del_gadget_udc(struct usb_gadget *gadget)
244{
245 struct usb_udc *udc = NULL;
246
247 mutex_lock(&udc_lock);
248 list_for_each_entry(udc, &udc_list, list)
249 if (udc->gadget == gadget)
250 goto found;
251
252 dev_err(gadget->dev.parent, "gadget not registered.\n");
253 mutex_unlock(&udc_lock);
254
255 return;
256
257found:
258 dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
259
260 list_del(&udc->list);
261 mutex_unlock(&udc_lock);
262
263 if (udc->driver)
264 usb_gadget_remove_driver(udc);
265}
266EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
267
268
269
270static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
271{
272 int ret;
273
274 dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
275 driver->function);
276
277 udc->driver = driver;
278
279 ret = driver->bind(udc->gadget);
280 if (ret)
281 goto err1;
282 ret = usb_gadget_udc_start(udc);
283 if (ret) {
284 driver->unbind(udc->gadget);
285 goto err1;
286 }
287 usb_gadget_connect(udc->gadget);
288
289 return 0;
290err1:
291 if (ret != -EISNAM)
292 dev_err(&udc->dev, "failed to start %s: %d\n",
293 udc->driver->function, ret);
294 udc->driver = NULL;
295 return ret;
296}
297
298int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
299{
300 struct usb_udc *udc = NULL;
301 int ret;
302
303 if (!driver || !driver->bind || !driver->setup)
304 return -EINVAL;
305
306 mutex_lock(&udc_lock);
307 list_for_each_entry(udc, &udc_list, list) {
308
309 if (!udc->driver)
310 goto found;
311 }
312
313 printf("couldn't find an available UDC\n");
314 mutex_unlock(&udc_lock);
315 return -ENODEV;
316found:
317 ret = udc_bind_to_driver(udc, driver);
318 mutex_unlock(&udc_lock);
319 return ret;
320}
321EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
322
323int usb_gadget_register_driver(struct usb_gadget_driver *driver)
324{
325 return usb_gadget_probe_driver(driver);
326}
327EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
328
329int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
330{
331 struct usb_udc *udc = NULL;
332 int ret = -ENODEV;
333
334 if (!driver || !driver->unbind)
335 return -EINVAL;
336
337 mutex_lock(&udc_lock);
338 list_for_each_entry(udc, &udc_list, list)
339 if (udc->driver == driver) {
340 usb_gadget_remove_driver(udc);
341 usb_gadget_set_state(udc->gadget,
342 USB_STATE_NOTATTACHED);
343 ret = 0;
344 break;
345 }
346
347 mutex_unlock(&udc_lock);
348 return ret;
349}
350EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
351
352MODULE_DESCRIPTION("UDC Framework");
353MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
354MODULE_LICENSE("GPL v2");
355