Branch data Line data Source code
1 : : /* ==========================================================================
2 : : * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
3 : : * $Revision: #21 $
4 : : * $Date: 2012/08/10 $
5 : : * $Change: 2047372 $
6 : : *
7 : : * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
8 : : * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9 : : * otherwise expressly agreed to in writing between Synopsys and you.
10 : : *
11 : : * The Software IS NOT an item of Licensed Software or Licensed Product under
12 : : * any End User Software License Agreement or Agreement for Licensed Product
13 : : * with Synopsys or any supplement thereto. You are permitted to use and
14 : : * redistribute this Software in source and binary forms, with or without
15 : : * modification, provided that redistributions of source code must retain this
16 : : * notice. You may not view, use, disclose, copy or distribute this file or
17 : : * any information contained herein except pursuant to this license grant from
18 : : * Synopsys. If you do not agree with this notice, including the disclaimer
19 : : * below, then you are not authorized to use the Software.
20 : : *
21 : : * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
22 : : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : : * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
25 : : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 : : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 : : * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 : : * DAMAGE.
32 : : * ========================================================================== */
33 : : #ifndef DWC_HOST_ONLY
34 : :
35 : : /** @file
36 : : * This file implements the Peripheral Controller Driver.
37 : : *
38 : : * The Peripheral Controller Driver (PCD) is responsible for
39 : : * translating requests from the Function Driver into the appropriate
40 : : * actions on the DWC_otg controller. It isolates the Function Driver
41 : : * from the specifics of the controller by providing an API to the
42 : : * Function Driver.
43 : : *
44 : : * The Peripheral Controller Driver for Linux will implement the
45 : : * Gadget API, so that the existing Gadget drivers can be used.
46 : : * (Gadget Driver is the Linux terminology for a Function Driver.)
47 : : *
48 : : * The Linux Gadget API is defined in the header file
49 : : * <code><linux/usb_gadget.h></code>. The USB EP operations API is
50 : : * defined in the structure <code>usb_ep_ops</code> and the USB
51 : : * Controller API is defined in the structure
52 : : * <code>usb_gadget_ops</code>.
53 : : *
54 : : */
55 : :
56 : : #include "dwc_otg_os_dep.h"
57 : : #include "dwc_otg_pcd_if.h"
58 : : #include "dwc_otg_pcd.h"
59 : : #include "dwc_otg_driver.h"
60 : : #include "dwc_otg_dbg.h"
61 : :
62 : : extern bool fiq_enable;
63 : :
64 : : static struct gadget_wrapper {
65 : : dwc_otg_pcd_t *pcd;
66 : :
67 : : struct usb_gadget gadget;
68 : : struct usb_gadget_driver *driver;
69 : :
70 : : struct usb_ep ep0;
71 : : struct usb_ep in_ep[16];
72 : : struct usb_ep out_ep[16];
73 : :
74 : : } *gadget_wrapper;
75 : :
76 : : /* Display the contents of the buffer */
77 : : extern void dump_msg(const u8 * buf, unsigned int length);
78 : : /**
79 : : * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case
80 : : * if the endpoint is not found
81 : : */
82 : : static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
83 : : {
84 : : int i;
85 [ # # # # ]: 0 : if (pcd->ep0.priv == handle) {
86 : 0 : return &pcd->ep0;
87 : : }
88 : :
89 [ # # # # ]: 0 : for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
90 [ # # # # ]: 0 : if (pcd->in_ep[i].priv == handle)
91 : 0 : return &pcd->in_ep[i];
92 [ # # # # ]: 0 : if (pcd->out_ep[i].priv == handle)
93 : 0 : return &pcd->out_ep[i];
94 : : }
95 : :
96 : : return NULL;
97 : : }
98 : :
99 : : /* USB Endpoint Operations */
100 : : /*
101 : : * The following sections briefly describe the behavior of the Gadget
102 : : * API endpoint operations implemented in the DWC_otg driver
103 : : * software. Detailed descriptions of the generic behavior of each of
104 : : * these functions can be found in the Linux header file
105 : : * include/linux/usb_gadget.h.
106 : : *
107 : : * The Gadget API provides wrapper functions for each of the function
108 : : * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
109 : : * function, which then calls the underlying PCD function. The
110 : : * following sections are named according to the wrapper
111 : : * functions. Within each section, the corresponding DWC_otg PCD
112 : : * function name is specified.
113 : : *
114 : : */
115 : :
116 : : /**
117 : : * This function is called by the Gadget Driver for each EP to be
118 : : * configured for the current configuration (SET_CONFIGURATION).
119 : : *
120 : : * This function initializes the dwc_otg_ep_t data structure, and then
121 : : * calls dwc_otg_ep_activate.
122 : : */
123 : 0 : static int ep_enable(struct usb_ep *usb_ep,
124 : : const struct usb_endpoint_descriptor *ep_desc)
125 : : {
126 : : int retval;
127 : :
128 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
129 : :
130 [ # # # # ]: 0 : if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
131 : 0 : DWC_WARN("%s, bad ep or descriptor\n", __func__);
132 : 0 : return -EINVAL;
133 : : }
134 [ # # ]: 0 : if (usb_ep == &gadget_wrapper->ep0) {
135 : 0 : DWC_WARN("%s, bad ep(0)\n", __func__);
136 : 0 : return -EINVAL;
137 : : }
138 : :
139 : : /* Check FIFO size? */
140 [ # # ]: 0 : if (!ep_desc->wMaxPacketSize) {
141 : 0 : DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
142 : 0 : return -ERANGE;
143 : : }
144 : :
145 [ # # # # ]: 0 : if (!gadget_wrapper->driver ||
146 : 0 : gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
147 : 0 : DWC_WARN("%s, bogus device state\n", __func__);
148 : 0 : return -ESHUTDOWN;
149 : : }
150 : :
151 : : /* Delete after check - MAS */
152 : : #if 0
153 : : nat = (uint32_t) ep_desc->wMaxPacketSize;
154 : : printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
155 : : nat = (nat >> 11) & 0x03;
156 : : printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
157 : : #endif
158 : 0 : retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
159 : : (const uint8_t *)ep_desc,
160 : : (void *)usb_ep);
161 [ # # ]: 0 : if (retval) {
162 : 0 : DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
163 : 0 : return -EINVAL;
164 : : }
165 : :
166 : 0 : usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
167 : :
168 : 0 : return 0;
169 : : }
170 : :
171 : : /**
172 : : * This function is called when an EP is disabled due to disconnect or
173 : : * change in configuration. Any pending requests will terminate with a
174 : : * status of -ESHUTDOWN.
175 : : *
176 : : * This function modifies the dwc_otg_ep_t data structure for this EP,
177 : : * and then calls dwc_otg_ep_deactivate.
178 : : */
179 : 0 : static int ep_disable(struct usb_ep *usb_ep)
180 : : {
181 : : int retval;
182 : :
183 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
184 [ # # ]: 0 : if (!usb_ep) {
185 : : DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
186 : : usb_ep ? usb_ep->name : NULL);
187 : : return -EINVAL;
188 : : }
189 : :
190 : 0 : retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
191 [ # # ]: 0 : if (retval) {
192 : : retval = -EINVAL;
193 : : }
194 : :
195 : 0 : return retval;
196 : : }
197 : :
198 : : /**
199 : : * This function allocates a request object to use with the specified
200 : : * endpoint.
201 : : *
202 : : * @param ep The endpoint to be used with with the request
203 : : * @param gfp_flags the GFP_* flags to use.
204 : : */
205 : 0 : static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
206 : : gfp_t gfp_flags)
207 : : {
208 : : struct usb_request *usb_req;
209 : :
210 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
211 [ # # ]: 0 : if (0 == ep) {
212 : 0 : DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
213 : 0 : return 0;
214 : : }
215 : 0 : usb_req = kzalloc(sizeof(*usb_req), gfp_flags);
216 [ # # ]: 0 : if (0 == usb_req) {
217 : 0 : DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
218 : 0 : return 0;
219 : : }
220 : 0 : usb_req->dma = DWC_DMA_ADDR_INVALID;
221 : :
222 : 0 : return usb_req;
223 : : }
224 : :
225 : : /**
226 : : * This function frees a request object.
227 : : *
228 : : * @param ep The endpoint associated with the request
229 : : * @param req The request being freed
230 : : */
231 : 0 : static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
232 : : {
233 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
234 : :
235 [ # # ]: 0 : if (0 == ep || 0 == req) {
236 : 0 : DWC_WARN("%s() %s\n", __func__,
237 : : "Invalid ep or req argument!\n");
238 : 0 : return;
239 : : }
240 : :
241 : 0 : kfree(req);
242 : : }
243 : :
244 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
245 : : /**
246 : : * This function allocates an I/O buffer to be used for a transfer
247 : : * to/from the specified endpoint.
248 : : *
249 : : * @param usb_ep The endpoint to be used with with the request
250 : : * @param bytes The desired number of bytes for the buffer
251 : : * @param dma Pointer to the buffer's DMA address; must be valid
252 : : * @param gfp_flags the GFP_* flags to use.
253 : : * @return address of a new buffer or null is buffer could not be allocated.
254 : : */
255 : : static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
256 : : dma_addr_t * dma, gfp_t gfp_flags)
257 : : {
258 : : void *buf;
259 : : dwc_otg_pcd_t *pcd = 0;
260 : :
261 : : pcd = gadget_wrapper->pcd;
262 : :
263 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
264 : : dma, gfp_flags);
265 : :
266 : : /* Check dword alignment */
267 : : if ((bytes & 0x3UL) != 0) {
268 : : DWC_WARN("%s() Buffer size is not a multiple of"
269 : : "DWORD size (%d)", __func__, bytes);
270 : : }
271 : :
272 : : buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
273 : : WARN_ON(!buf);
274 : :
275 : : /* Check dword alignment */
276 : : if (((int)buf & 0x3UL) != 0) {
277 : : DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
278 : : __func__, buf);
279 : : }
280 : :
281 : : return buf;
282 : : }
283 : :
284 : : /**
285 : : * This function frees an I/O buffer that was allocated by alloc_buffer.
286 : : *
287 : : * @param usb_ep the endpoint associated with the buffer
288 : : * @param buf address of the buffer
289 : : * @param dma The buffer's DMA address
290 : : * @param bytes The number of bytes of the buffer
291 : : */
292 : : static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
293 : : dma_addr_t dma, unsigned bytes)
294 : : {
295 : : dwc_otg_pcd_t *pcd = 0;
296 : :
297 : : pcd = gadget_wrapper->pcd;
298 : :
299 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
300 : :
301 : : dma_free_coherent(NULL, bytes, buf, dma);
302 : : }
303 : : #endif
304 : :
305 : : /**
306 : : * This function is used to submit an I/O Request to an EP.
307 : : *
308 : : * - When the request completes the request's completion callback
309 : : * is called to return the request to the driver.
310 : : * - An EP, except control EPs, may have multiple requests
311 : : * pending.
312 : : * - Once submitted the request cannot be examined or modified.
313 : : * - Each request is turned into one or more packets.
314 : : * - A BULK EP can queue any amount of data; the transfer is
315 : : * packetized.
316 : : * - Zero length Packets are specified with the request 'zero'
317 : : * flag.
318 : : */
319 : 0 : static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
320 : : gfp_t gfp_flags)
321 : : {
322 : : dwc_otg_pcd_t *pcd;
323 : : struct dwc_otg_pcd_ep *ep = NULL;
324 : : int retval = 0, is_isoc_ep = 0;
325 : : dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
326 : :
327 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
328 : : __func__, usb_ep, usb_req, gfp_flags);
329 : :
330 [ # # # # : 0 : if (!usb_req || !usb_req->complete || !usb_req->buf) {
# # ]
331 : 0 : DWC_WARN("bad params\n");
332 : 0 : return -EINVAL;
333 : : }
334 : :
335 [ # # ]: 0 : if (!usb_ep) {
336 : 0 : DWC_WARN("bad ep\n");
337 : 0 : return -EINVAL;
338 : : }
339 : :
340 : 0 : pcd = gadget_wrapper->pcd;
341 [ # # # # ]: 0 : if (!gadget_wrapper->driver ||
342 : 0 : gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
343 : : DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
344 : : gadget_wrapper->gadget.speed);
345 : 0 : DWC_WARN("bogus device state\n");
346 : 0 : return -ESHUTDOWN;
347 : : }
348 : :
349 : : DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
350 : : usb_ep->name, usb_req, usb_req->length, usb_req->buf);
351 : :
352 : 0 : usb_req->status = -EINPROGRESS;
353 : 0 : usb_req->actual = 0;
354 : :
355 : : ep = ep_from_handle(pcd, usb_ep);
356 : : if (ep == NULL)
357 : : is_isoc_ep = 0;
358 : : else
359 : : is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
360 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
361 : : dma_addr = usb_req->dma;
362 : : #else
363 [ # # ]: 0 : if (GET_CORE_IF(pcd)->dma_enable) {
364 : 0 : dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
365 : : struct device *dev = NULL;
366 : :
367 [ # # ]: 0 : if (otg_dev != NULL)
368 [ # # ]: 0 : dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
369 : :
370 [ # # # # ]: 0 : if (usb_req->length != 0 &&
371 : 0 : usb_req->dma == DWC_DMA_ADDR_INVALID) {
372 [ # # ]: 0 : dma_addr = dma_map_single(dev, usb_req->buf,
373 : : usb_req->length,
374 : : ep->dwc_ep.is_in ?
375 : : DMA_TO_DEVICE:
376 : : DMA_FROM_DEVICE);
377 : : }
378 : : }
379 : : #endif
380 : :
381 : : #ifdef DWC_UTE_PER_IO
382 : : if (is_isoc_ep == 1) {
383 : : retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
384 : : usb_req->length, usb_req->zero, usb_req,
385 : : gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
386 : : if (retval)
387 : : return -EINVAL;
388 : :
389 : : return 0;
390 : : }
391 : : #endif
392 : 0 : retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
393 : 0 : usb_req->length, usb_req->zero, usb_req,
394 : : gfp_flags == GFP_ATOMIC ? 1 : 0);
395 [ # # ]: 0 : if (retval) {
396 : : return -EINVAL;
397 : : }
398 : :
399 : 0 : return 0;
400 : : }
401 : :
402 : : /**
403 : : * This function cancels an I/O request from an EP.
404 : : */
405 : 0 : static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
406 : : {
407 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
408 : :
409 [ # # ]: 0 : if (!usb_ep || !usb_req) {
410 : 0 : DWC_WARN("bad argument\n");
411 : 0 : return -EINVAL;
412 : : }
413 [ # # # # ]: 0 : if (!gadget_wrapper->driver ||
414 : 0 : gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
415 : 0 : DWC_WARN("bogus device state\n");
416 : 0 : return -ESHUTDOWN;
417 : : }
418 [ # # ]: 0 : if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
419 : : return -EINVAL;
420 : : }
421 : :
422 : 0 : return 0;
423 : : }
424 : :
425 : : /**
426 : : * usb_ep_set_halt stalls an endpoint.
427 : : *
428 : : * usb_ep_clear_halt clears an endpoint halt and resets its data
429 : : * toggle.
430 : : *
431 : : * Both of these functions are implemented with the same underlying
432 : : * function. The behavior depends on the value argument.
433 : : *
434 : : * @param[in] usb_ep the Endpoint to halt or clear halt.
435 : : * @param[in] value
436 : : * - 0 means clear_halt.
437 : : * - 1 means set_halt,
438 : : * - 2 means clear stall lock flag.
439 : : * - 3 means set stall lock flag.
440 : : */
441 : 0 : static int ep_halt(struct usb_ep *usb_ep, int value)
442 : : {
443 : : int retval = 0;
444 : :
445 : : DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
446 : :
447 [ # # ]: 0 : if (!usb_ep) {
448 : 0 : DWC_WARN("bad ep\n");
449 : 0 : return -EINVAL;
450 : : }
451 : :
452 : 0 : retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
453 [ # # ]: 0 : if (retval == -DWC_E_AGAIN) {
454 : : return -EAGAIN;
455 [ # # ]: 0 : } else if (retval) {
456 : : retval = -EINVAL;
457 : : }
458 : :
459 : 0 : return retval;
460 : : }
461 : :
462 : : //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
463 : : #if 0
464 : : /**
465 : : * ep_wedge: sets the halt feature and ignores clear requests
466 : : *
467 : : * @usb_ep: the endpoint being wedged
468 : : *
469 : : * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
470 : : * requests. If the gadget driver clears the halt status, it will
471 : : * automatically unwedge the endpoint.
472 : : *
473 : : * Returns zero on success, else negative errno. *
474 : : * Check usb_ep_set_wedge() at "usb_gadget.h" for details
475 : : */
476 : : static int ep_wedge(struct usb_ep *usb_ep)
477 : : {
478 : : int retval = 0;
479 : :
480 : : DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);
481 : :
482 : : if (!usb_ep) {
483 : : DWC_WARN("bad ep\n");
484 : : return -EINVAL;
485 : : }
486 : :
487 : : retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
488 : : if (retval == -DWC_E_AGAIN) {
489 : : retval = -EAGAIN;
490 : : } else if (retval) {
491 : : retval = -EINVAL;
492 : : }
493 : :
494 : : return retval;
495 : : }
496 : : #endif
497 : :
498 : : #ifdef DWC_EN_ISOC
499 : : /**
500 : : * This function is used to submit an ISOC Transfer Request to an EP.
501 : : *
502 : : * - Every time a sync period completes the request's completion callback
503 : : * is called to provide data to the gadget driver.
504 : : * - Once submitted the request cannot be modified.
505 : : * - Each request is turned into periodic data packets untill ISO
506 : : * Transfer is stopped..
507 : : */
508 : : static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
509 : : gfp_t gfp_flags)
510 : : {
511 : : int retval = 0;
512 : :
513 : : if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
514 : : DWC_WARN("bad params\n");
515 : : return -EINVAL;
516 : : }
517 : :
518 : : if (!usb_ep) {
519 : : DWC_PRINTF("bad params\n");
520 : : return -EINVAL;
521 : : }
522 : :
523 : : req->status = -EINPROGRESS;
524 : :
525 : : retval =
526 : : dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
527 : : req->buf1, req->dma0, req->dma1,
528 : : req->sync_frame, req->data_pattern_frame,
529 : : req->data_per_frame,
530 : : req->
531 : : flags & USB_REQ_ISO_ASAP ? -1 :
532 : : req->start_frame, req->buf_proc_intrvl,
533 : : req, gfp_flags == GFP_ATOMIC ? 1 : 0);
534 : :
535 : : if (retval) {
536 : : return -EINVAL;
537 : : }
538 : :
539 : : return retval;
540 : : }
541 : :
542 : : /**
543 : : * This function stops ISO EP Periodic Data Transfer.
544 : : */
545 : : static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
546 : : {
547 : : int retval = 0;
548 : : if (!usb_ep) {
549 : : DWC_WARN("bad ep\n");
550 : : }
551 : :
552 : : if (!gadget_wrapper->driver ||
553 : : gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
554 : : DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
555 : : gadget_wrapper->gadget.speed);
556 : : DWC_WARN("bogus device state\n");
557 : : }
558 : :
559 : : dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
560 : : if (retval) {
561 : : retval = -EINVAL;
562 : : }
563 : :
564 : : return retval;
565 : : }
566 : :
567 : : static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
568 : : int packets, gfp_t gfp_flags)
569 : : {
570 : : struct usb_iso_request *pReq = NULL;
571 : : uint32_t req_size;
572 : :
573 : : req_size = sizeof(struct usb_iso_request);
574 : : req_size +=
575 : : (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
576 : :
577 : : pReq = kmalloc(req_size, gfp_flags);
578 : : if (!pReq) {
579 : : DWC_WARN("Can't allocate Iso Request\n");
580 : : return 0;
581 : : }
582 : : pReq->iso_packet_desc0 = (void *)(pReq + 1);
583 : :
584 : : pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
585 : :
586 : : return pReq;
587 : : }
588 : :
589 : : static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
590 : : {
591 : : kfree(req);
592 : : }
593 : :
594 : : static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
595 : : .ep_ops = {
596 : : .enable = ep_enable,
597 : : .disable = ep_disable,
598 : :
599 : : .alloc_request = dwc_otg_pcd_alloc_request,
600 : : .free_request = dwc_otg_pcd_free_request,
601 : :
602 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
603 : : .alloc_buffer = dwc_otg_pcd_alloc_buffer,
604 : : .free_buffer = dwc_otg_pcd_free_buffer,
605 : : #endif
606 : :
607 : : .queue = ep_queue,
608 : : .dequeue = ep_dequeue,
609 : :
610 : : .set_halt = ep_halt,
611 : : .fifo_status = 0,
612 : : .fifo_flush = 0,
613 : : },
614 : : .iso_ep_start = iso_ep_start,
615 : : .iso_ep_stop = iso_ep_stop,
616 : : .alloc_iso_request = alloc_iso_request,
617 : : .free_iso_request = free_iso_request,
618 : : };
619 : :
620 : : #else
621 : :
622 : : int (*enable) (struct usb_ep *ep,
623 : : const struct usb_endpoint_descriptor *desc);
624 : : int (*disable) (struct usb_ep *ep);
625 : :
626 : : struct usb_request *(*alloc_request) (struct usb_ep *ep,
627 : : gfp_t gfp_flags);
628 : : void (*free_request) (struct usb_ep *ep, struct usb_request *req);
629 : :
630 : : int (*queue) (struct usb_ep *ep, struct usb_request *req,
631 : : gfp_t gfp_flags);
632 : : int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
633 : :
634 : : int (*set_halt) (struct usb_ep *ep, int value);
635 : : int (*set_wedge) (struct usb_ep *ep);
636 : :
637 : : int (*fifo_status) (struct usb_ep *ep);
638 : : void (*fifo_flush) (struct usb_ep *ep);
639 : : static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
640 : : .enable = ep_enable,
641 : : .disable = ep_disable,
642 : :
643 : : .alloc_request = dwc_otg_pcd_alloc_request,
644 : : .free_request = dwc_otg_pcd_free_request,
645 : :
646 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
647 : : .alloc_buffer = dwc_otg_pcd_alloc_buffer,
648 : : .free_buffer = dwc_otg_pcd_free_buffer,
649 : : #else
650 : : /* .set_wedge = ep_wedge, */
651 : : .set_wedge = NULL, /* uses set_halt instead */
652 : : #endif
653 : :
654 : : .queue = ep_queue,
655 : : .dequeue = ep_dequeue,
656 : :
657 : : .set_halt = ep_halt,
658 : : .fifo_status = 0,
659 : : .fifo_flush = 0,
660 : :
661 : : };
662 : :
663 : : #endif /* _EN_ISOC_ */
664 : : /* Gadget Operations */
665 : : /**
666 : : * The following gadget operations will be implemented in the DWC_otg
667 : : * PCD. Functions in the API that are not described below are not
668 : : * implemented.
669 : : *
670 : : * The Gadget API provides wrapper functions for each of the function
671 : : * pointers defined in usb_gadget_ops. The Gadget Driver calls the
672 : : * wrapper function, which then calls the underlying PCD function. The
673 : : * following sections are named according to the wrapper functions
674 : : * (except for ioctl, which doesn't have a wrapper function). Within
675 : : * each section, the corresponding DWC_otg PCD function name is
676 : : * specified.
677 : : *
678 : : */
679 : :
680 : : /**
681 : : *Gets the USB Frame number of the last SOF.
682 : : */
683 : 0 : static int get_frame_number(struct usb_gadget *gadget)
684 : : {
685 : : struct gadget_wrapper *d;
686 : :
687 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
688 : :
689 [ # # ]: 0 : if (gadget == 0) {
690 : : return -ENODEV;
691 : : }
692 : :
693 : : d = container_of(gadget, struct gadget_wrapper, gadget);
694 : 0 : return dwc_otg_pcd_get_frame_number(d->pcd);
695 : : }
696 : :
697 : : #ifdef CONFIG_USB_DWC_OTG_LPM
698 : : static int test_lpm_enabled(struct usb_gadget *gadget)
699 : : {
700 : : struct gadget_wrapper *d;
701 : :
702 : : d = container_of(gadget, struct gadget_wrapper, gadget);
703 : :
704 : : return dwc_otg_pcd_is_lpm_enabled(d->pcd);
705 : : }
706 : : #endif
707 : :
708 : : /**
709 : : * Initiates Session Request Protocol (SRP) to wakeup the host if no
710 : : * session is in progress. If a session is already in progress, but
711 : : * the device is suspended, remote wakeup signaling is started.
712 : : *
713 : : */
714 : 0 : static int wakeup(struct usb_gadget *gadget)
715 : : {
716 : : struct gadget_wrapper *d;
717 : :
718 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
719 : :
720 [ # # ]: 0 : if (gadget == 0) {
721 : : return -ENODEV;
722 : : } else {
723 : : d = container_of(gadget, struct gadget_wrapper, gadget);
724 : : }
725 : 0 : dwc_otg_pcd_wakeup(d->pcd);
726 : 0 : return 0;
727 : : }
728 : :
729 : : static const struct usb_gadget_ops dwc_otg_pcd_ops = {
730 : : .get_frame = get_frame_number,
731 : : .wakeup = wakeup,
732 : : #ifdef CONFIG_USB_DWC_OTG_LPM
733 : : .lpm_support = test_lpm_enabled,
734 : : #endif
735 : : // current versions must always be self-powered
736 : : };
737 : :
738 : 0 : static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
739 : : {
740 : : int retval = -DWC_E_NOT_SUPPORTED;
741 [ # # # # ]: 0 : if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
742 : 0 : retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
743 : : (struct usb_ctrlrequest
744 : : *)bytes);
745 : : }
746 : :
747 [ # # ]: 0 : if (retval == -ENOTSUPP) {
748 : : retval = -DWC_E_NOT_SUPPORTED;
749 [ # # ]: 0 : } else if (retval < 0) {
750 : : retval = -DWC_E_INVALID;
751 : : }
752 : :
753 : 0 : return retval;
754 : : }
755 : :
756 : : #ifdef DWC_EN_ISOC
757 : : static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
758 : : void *req_handle, int proc_buf_num)
759 : : {
760 : : int i, packet_count;
761 : : struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
762 : : struct usb_iso_request *iso_req = req_handle;
763 : :
764 : : if (proc_buf_num) {
765 : : iso_packet = iso_req->iso_packet_desc1;
766 : : } else {
767 : : iso_packet = iso_req->iso_packet_desc0;
768 : : }
769 : : packet_count =
770 : : dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
771 : : for (i = 0; i < packet_count; ++i) {
772 : : int status;
773 : : int actual;
774 : : int offset;
775 : : dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
776 : : i, &status, &actual, &offset);
777 : : switch (status) {
778 : : case -DWC_E_NO_DATA:
779 : : status = -ENODATA;
780 : : break;
781 : : default:
782 : : if (status) {
783 : : DWC_PRINTF("unknown status in isoc packet\n");
784 : : }
785 : :
786 : : }
787 : : iso_packet[i].status = status;
788 : : iso_packet[i].offset = offset;
789 : : iso_packet[i].actual_length = actual;
790 : : }
791 : :
792 : : iso_req->status = 0;
793 : : iso_req->process_buffer(ep_handle, iso_req);
794 : :
795 : : return 0;
796 : : }
797 : : #endif /* DWC_EN_ISOC */
798 : :
799 : : #ifdef DWC_UTE_PER_IO
800 : : /**
801 : : * Copy the contents of the extended request to the Linux usb_request's
802 : : * extended part and call the gadget's completion.
803 : : *
804 : : * @param pcd Pointer to the pcd structure
805 : : * @param ep_handle Void pointer to the usb_ep structure
806 : : * @param req_handle Void pointer to the usb_request structure
807 : : * @param status Request status returned from the portable logic
808 : : * @param ereq_port Void pointer to the extended request structure
809 : : * created in the the portable part that contains the
810 : : * results of the processed iso packets.
811 : : */
812 : : static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
813 : : void *req_handle, int32_t status, void *ereq_port)
814 : : {
815 : : struct dwc_ute_iso_req_ext *ereqorg = NULL;
816 : : struct dwc_iso_xreq_port *ereqport = NULL;
817 : : struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
818 : : int i;
819 : : struct usb_request *req;
820 : : //struct dwc_ute_iso_packet_descriptor *
821 : : //int status = 0;
822 : :
823 : : req = (struct usb_request *)req_handle;
824 : : ereqorg = &req->ext_req;
825 : : ereqport = (struct dwc_iso_xreq_port *)ereq_port;
826 : : desc_org = ereqorg->per_io_frame_descs;
827 : :
828 : : if (req && req->complete) {
829 : : /* Copy the request data from the portable logic to our request */
830 : : for (i = 0; i < ereqport->pio_pkt_count; i++) {
831 : : desc_org[i].actual_length =
832 : : ereqport->per_io_frame_descs[i].actual_length;
833 : : desc_org[i].status =
834 : : ereqport->per_io_frame_descs[i].status;
835 : : }
836 : :
837 : : switch (status) {
838 : : case -DWC_E_SHUTDOWN:
839 : : req->status = -ESHUTDOWN;
840 : : break;
841 : : case -DWC_E_RESTART:
842 : : req->status = -ECONNRESET;
843 : : break;
844 : : case -DWC_E_INVALID:
845 : : req->status = -EINVAL;
846 : : break;
847 : : case -DWC_E_TIMEOUT:
848 : : req->status = -ETIMEDOUT;
849 : : break;
850 : : default:
851 : : req->status = status;
852 : : }
853 : :
854 : : /* And call the gadget's completion */
855 : : req->complete(ep_handle, req);
856 : : }
857 : :
858 : : return 0;
859 : : }
860 : : #endif /* DWC_UTE_PER_IO */
861 : :
862 : 0 : static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
863 : : void *req_handle, int32_t status, uint32_t actual)
864 : : {
865 : : struct usb_request *req = (struct usb_request *)req_handle;
866 : : #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
867 : : struct dwc_otg_pcd_ep *ep = NULL;
868 : : #endif
869 : :
870 [ # # # # ]: 0 : if (req && req->complete) {
871 [ # # # # : 0 : switch (status) {
# ]
872 : : case -DWC_E_SHUTDOWN:
873 : 0 : req->status = -ESHUTDOWN;
874 : 0 : break;
875 : : case -DWC_E_RESTART:
876 : 0 : req->status = -ECONNRESET;
877 : 0 : break;
878 : : case -DWC_E_INVALID:
879 : 0 : req->status = -EINVAL;
880 : 0 : break;
881 : : case -DWC_E_TIMEOUT:
882 : 0 : req->status = -ETIMEDOUT;
883 : 0 : break;
884 : : default:
885 : 0 : req->status = status;
886 : :
887 : : }
888 : :
889 : 0 : req->actual = actual;
890 : 0 : DWC_SPINUNLOCK(pcd->lock);
891 : 0 : req->complete(ep_handle, req);
892 : 0 : DWC_SPINLOCK(pcd->lock);
893 : : }
894 : : #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
895 : : ep = ep_from_handle(pcd, ep_handle);
896 [ # # ]: 0 : if (GET_CORE_IF(pcd)->dma_enable) {
897 [ # # ]: 0 : if (req->length != 0) {
898 : 0 : dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev;
899 : : struct device *dev = NULL;
900 : :
901 [ # # ]: 0 : if (otg_dev != NULL)
902 [ # # ]: 0 : dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep);
903 : :
904 [ # # ]: 0 : dma_unmap_single(dev, req->dma, req->length,
905 : : ep->dwc_ep.is_in ?
906 : : DMA_TO_DEVICE: DMA_FROM_DEVICE);
907 : : }
908 : : }
909 : : #endif
910 : :
911 : 0 : return 0;
912 : : }
913 : :
914 : 0 : static int _connect(dwc_otg_pcd_t * pcd, int speed)
915 : : {
916 : 0 : gadget_wrapper->gadget.speed = speed;
917 : 0 : return 0;
918 : : }
919 : :
920 : 0 : static int _disconnect(dwc_otg_pcd_t * pcd)
921 : : {
922 [ # # # # ]: 0 : if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
923 : 0 : gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
924 : : }
925 : 0 : return 0;
926 : : }
927 : :
928 : 0 : static int _resume(dwc_otg_pcd_t * pcd)
929 : : {
930 [ # # # # ]: 0 : if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
931 : 0 : gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
932 : : }
933 : :
934 : 0 : return 0;
935 : : }
936 : :
937 : 0 : static int _suspend(dwc_otg_pcd_t * pcd)
938 : : {
939 [ # # # # ]: 0 : if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
940 : 0 : gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
941 : : }
942 : 0 : return 0;
943 : : }
944 : :
945 : : /**
946 : : * This function updates the otg values in the gadget structure.
947 : : */
948 : 0 : static int _hnp_changed(dwc_otg_pcd_t * pcd)
949 : : {
950 : :
951 [ # # ]: 0 : if (!gadget_wrapper->gadget.is_otg)
952 : : return 0;
953 : :
954 : 0 : gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
955 : 0 : gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
956 : 0 : gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
957 : 0 : return 0;
958 : : }
959 : :
960 : 0 : static int _reset(dwc_otg_pcd_t * pcd)
961 : : {
962 : 0 : return 0;
963 : : }
964 : :
965 : : #ifdef DWC_UTE_CFI
966 : : static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
967 : : {
968 : : int retval = -DWC_E_INVALID;
969 : : if (gadget_wrapper->driver->cfi_feature_setup) {
970 : : retval =
971 : : gadget_wrapper->driver->
972 : : cfi_feature_setup(&gadget_wrapper->gadget,
973 : : (struct cfi_usb_ctrlrequest *)cfi_req);
974 : : }
975 : :
976 : : return retval;
977 : : }
978 : : #endif
979 : :
980 : : static const struct dwc_otg_pcd_function_ops fops = {
981 : : .complete = _complete,
982 : : #ifdef DWC_EN_ISOC
983 : : .isoc_complete = _isoc_complete,
984 : : #endif
985 : : .setup = _setup,
986 : : .disconnect = _disconnect,
987 : : .connect = _connect,
988 : : .resume = _resume,
989 : : .suspend = _suspend,
990 : : .hnp_changed = _hnp_changed,
991 : : .reset = _reset,
992 : : #ifdef DWC_UTE_CFI
993 : : .cfi_setup = _cfi_setup,
994 : : #endif
995 : : #ifdef DWC_UTE_PER_IO
996 : : .xisoc_complete = _xisoc_complete,
997 : : #endif
998 : : };
999 : :
1000 : : /**
1001 : : * This function is the top level PCD interrupt handler.
1002 : : */
1003 : 134565738 : static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
1004 : : {
1005 : : dwc_otg_pcd_t *pcd = dev;
1006 : : int32_t retval = IRQ_NONE;
1007 : :
1008 : 134565738 : retval = dwc_otg_pcd_handle_intr(pcd);
1009 : : if (retval != 0) {
1010 : : S3C2410X_CLEAR_EINTPEND();
1011 : : }
1012 : 134565738 : return IRQ_RETVAL(retval);
1013 : : }
1014 : :
1015 : : /**
1016 : : * This function initialized the usb_ep structures to there default
1017 : : * state.
1018 : : *
1019 : : * @param d Pointer on gadget_wrapper.
1020 : : */
1021 : 404 : void gadget_add_eps(struct gadget_wrapper *d)
1022 : : {
1023 : : static const char *names[] = {
1024 : :
1025 : : "ep0",
1026 : : "ep1in",
1027 : : "ep2in",
1028 : : "ep3in",
1029 : : "ep4in",
1030 : : "ep5in",
1031 : : "ep6in",
1032 : : "ep7in",
1033 : : "ep8in",
1034 : : "ep9in",
1035 : : "ep10in",
1036 : : "ep11in",
1037 : : "ep12in",
1038 : : "ep13in",
1039 : : "ep14in",
1040 : : "ep15in",
1041 : : "ep1out",
1042 : : "ep2out",
1043 : : "ep3out",
1044 : : "ep4out",
1045 : : "ep5out",
1046 : : "ep6out",
1047 : : "ep7out",
1048 : : "ep8out",
1049 : : "ep9out",
1050 : : "ep10out",
1051 : : "ep11out",
1052 : : "ep12out",
1053 : : "ep13out",
1054 : : "ep14out",
1055 : : "ep15out"
1056 : : };
1057 : :
1058 : : int i;
1059 : : struct usb_ep *ep;
1060 : : int8_t dev_endpoints;
1061 : :
1062 : : DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
1063 : :
1064 : 404 : INIT_LIST_HEAD(&d->gadget.ep_list);
1065 : 404 : d->gadget.ep0 = &d->ep0;
1066 : 404 : d->gadget.speed = USB_SPEED_UNKNOWN;
1067 : :
1068 : 404 : INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
1069 : :
1070 : : /**
1071 : : * Initialize the EP0 structure.
1072 : : */
1073 : : ep = &d->ep0;
1074 : :
1075 : : /* Init the usb_ep structure. */
1076 : 404 : ep->name = names[0];
1077 : 404 : ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
1078 : :
1079 : : /**
1080 : : * @todo NGS: What should the max packet size be set to
1081 : : * here? Before EP type is set?
1082 : : */
1083 : 404 : ep->maxpacket = MAX_PACKET_SIZE;
1084 : 404 : dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
1085 : :
1086 : : list_add_tail(&ep->ep_list, &d->gadget.ep_list);
1087 : :
1088 : : /**
1089 : : * Initialize the EP structures.
1090 : : */
1091 : 404 : dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
1092 : :
1093 [ - + ]: 404 : for (i = 0; i < dev_endpoints; i++) {
1094 : : ep = &d->in_ep[i];
1095 : :
1096 : : /* Init the usb_ep structure. */
1097 : 0 : ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
1098 : 0 : ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
1099 : :
1100 : : /**
1101 : : * @todo NGS: What should the max packet size be set to
1102 : : * here? Before EP type is set?
1103 : : */
1104 : 0 : ep->maxpacket = MAX_PACKET_SIZE;
1105 : 0 : list_add_tail(&ep->ep_list, &d->gadget.ep_list);
1106 : : }
1107 : :
1108 : 404 : dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
1109 : :
1110 [ - + ]: 404 : for (i = 0; i < dev_endpoints; i++) {
1111 : : ep = &d->out_ep[i];
1112 : :
1113 : : /* Init the usb_ep structure. */
1114 : 0 : ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
1115 : 0 : ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
1116 : :
1117 : : /**
1118 : : * @todo NGS: What should the max packet size be set to
1119 : : * here? Before EP type is set?
1120 : : */
1121 : 0 : ep->maxpacket = MAX_PACKET_SIZE;
1122 : :
1123 : 0 : list_add_tail(&ep->ep_list, &d->gadget.ep_list);
1124 : : }
1125 : :
1126 : : /* remove ep0 from the list. There is a ep0 pointer. */
1127 : : list_del_init(&d->ep0.ep_list);
1128 : :
1129 : 404 : d->ep0.maxpacket = MAX_EP0_SIZE;
1130 : 404 : }
1131 : :
1132 : : /**
1133 : : * This function releases the Gadget device.
1134 : : * required by device_unregister().
1135 : : *
1136 : : * @todo Should this do something? Should it free the PCD?
1137 : : */
1138 : 0 : static void dwc_otg_pcd_gadget_release(struct device *dev)
1139 : : {
1140 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
1141 : 0 : }
1142 : :
1143 : 404 : static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev)
1144 : : {
1145 : : static char pcd_name[] = "dwc_otg_pcd";
1146 : : dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
1147 : : struct gadget_wrapper *d;
1148 : : int retval;
1149 : :
1150 : 404 : d = DWC_ALLOC(sizeof(*d));
1151 [ + - ]: 404 : if (d == NULL) {
1152 : : return NULL;
1153 : : }
1154 : :
1155 : 404 : memset(d, 0, sizeof(*d));
1156 : :
1157 : 404 : d->gadget.name = pcd_name;
1158 : 404 : d->pcd = otg_dev->pcd;
1159 : :
1160 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
1161 : : strcpy(d->gadget.dev.bus_id, "gadget");
1162 : : #else
1163 : 404 : dev_set_name(&d->gadget.dev, "%s", "gadget");
1164 : : #endif
1165 : :
1166 : 404 : d->gadget.dev.parent = &_dev->dev;
1167 : 404 : d->gadget.dev.release = dwc_otg_pcd_gadget_release;
1168 : 404 : d->gadget.ops = &dwc_otg_pcd_ops;
1169 [ - + ]: 404 : d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL;
1170 : 404 : d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
1171 : :
1172 : 404 : d->driver = 0;
1173 : : /* Register the gadget device */
1174 : 404 : retval = device_register(&d->gadget.dev);
1175 [ - + ]: 404 : if (retval != 0) {
1176 : 0 : DWC_ERROR("device_register failed\n");
1177 : 0 : DWC_FREE(d);
1178 : 0 : return NULL;
1179 : : }
1180 : :
1181 : : return d;
1182 : : }
1183 : :
1184 : 0 : static void free_wrapper(struct gadget_wrapper *d)
1185 : : {
1186 [ # # ]: 0 : if (d->driver) {
1187 : : /* should have been done already by driver model core */
1188 : 0 : DWC_WARN("driver '%s' is still registered\n",
1189 : : d->driver->driver.name);
1190 : : #ifdef CONFIG_USB_GADGET
1191 : : usb_gadget_unregister_driver(d->driver);
1192 : : #endif
1193 : : }
1194 : :
1195 : 0 : device_unregister(&d->gadget.dev);
1196 : 0 : DWC_FREE(d);
1197 : 0 : }
1198 : :
1199 : : /**
1200 : : * This function initialized the PCD portion of the driver.
1201 : : *
1202 : : */
1203 : 404 : int pcd_init(dwc_bus_dev_t *_dev)
1204 : : {
1205 : : dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
1206 : : int retval = 0;
1207 : :
1208 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev);
1209 : :
1210 : 404 : otg_dev->pcd = dwc_otg_pcd_init(otg_dev);
1211 : :
1212 [ - + ]: 404 : if (!otg_dev->pcd) {
1213 : 0 : DWC_ERROR("dwc_otg_pcd_init failed\n");
1214 : 0 : return -ENOMEM;
1215 : : }
1216 : :
1217 : 404 : otg_dev->pcd->otg_dev = otg_dev;
1218 : 404 : gadget_wrapper = alloc_wrapper(_dev);
1219 : :
1220 : : /*
1221 : : * Initialize EP structures
1222 : : */
1223 : 404 : gadget_add_eps(gadget_wrapper);
1224 : : /*
1225 : : * Setup interupt handler
1226 : : */
1227 : : DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n",
1228 : : otg_dev->os_dep.irq_num);
1229 : 808 : retval = request_irq(otg_dev->os_dep.irq_num, dwc_otg_pcd_irq,
1230 : 404 : IRQF_SHARED, gadget_wrapper->gadget.name,
1231 : 404 : otg_dev->pcd);
1232 [ - + ]: 404 : if (retval != 0) {
1233 : 0 : DWC_ERROR("request of irq%d failed\n", otg_dev->os_dep.irq_num);
1234 : 0 : free_wrapper(gadget_wrapper);
1235 : 0 : return -EBUSY;
1236 : : }
1237 : :
1238 : 404 : dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
1239 : :
1240 : 404 : return retval;
1241 : : }
1242 : :
1243 : : /**
1244 : : * Cleanup the PCD.
1245 : : */
1246 : 0 : void pcd_remove(dwc_bus_dev_t *_dev)
1247 : : {
1248 : : dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
1249 : 0 : dwc_otg_pcd_t *pcd = otg_dev->pcd;
1250 : :
1251 : : DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev);
1252 : :
1253 : : /*
1254 : : * Free the IRQ
1255 : : */
1256 : 0 : free_irq(otg_dev->os_dep.irq_num, pcd);
1257 : 0 : dwc_otg_pcd_remove(otg_dev->pcd);
1258 : 0 : free_wrapper(gadget_wrapper);
1259 : 0 : otg_dev->pcd = 0;
1260 : 0 : }
1261 : :
1262 : : #endif /* DWC_HOST_ONLY */
|