Branch data Line data Source code
1 : :
2 : : /* ==========================================================================
3 : : * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
4 : : * $Revision: #20 $
5 : : * $Date: 2011/10/26 $
6 : : * $Change: 1872981 $
7 : : *
8 : : * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
9 : : * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
10 : : * otherwise expressly agreed to in writing between Synopsys and you.
11 : : *
12 : : * The Software IS NOT an item of Licensed Software or Licensed Product under
13 : : * any End User Software License Agreement or Agreement for Licensed Product
14 : : * with Synopsys or any supplement thereto. You are permitted to use and
15 : : * redistribute this Software in source and binary forms, with or without
16 : : * modification, provided that redistributions of source code must retain this
17 : : * notice. You may not view, use, disclose, copy or distribute this file or
18 : : * any information contained herein except pursuant to this license grant from
19 : : * Synopsys. If you do not agree with this notice, including the disclaimer
20 : : * below, then you are not authorized to use the Software.
21 : : *
22 : : * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
23 : : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 : : * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
26 : : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 : : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 : : * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 : : * DAMAGE.
33 : : * ========================================================================== */
34 : : #ifndef DWC_DEVICE_ONLY
35 : :
36 : : /**
37 : : * @file
38 : : *
39 : : * This file contains the implementation of the HCD. In Linux, the HCD
40 : : * implements the hc_driver API.
41 : : */
42 : : #include <linux/kernel.h>
43 : : #include <linux/module.h>
44 : : #include <linux/moduleparam.h>
45 : : #include <linux/init.h>
46 : : #include <linux/device.h>
47 : : #include <linux/errno.h>
48 : : #include <linux/list.h>
49 : : #include <linux/interrupt.h>
50 : : #include <linux/string.h>
51 : : #include <linux/dma-mapping.h>
52 : : #include <linux/version.h>
53 : : #include <asm/io.h>
54 : : #ifdef CONFIG_ARM
55 : : #include <asm/fiq.h>
56 : : #endif
57 : : #include <linux/usb.h>
58 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
59 : : #include <../drivers/usb/core/hcd.h>
60 : : #else
61 : : #include <linux/usb/hcd.h>
62 : : #endif
63 : : #include <asm/bug.h>
64 : :
65 : : #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
66 : : #define USB_URB_EP_LINKING 1
67 : : #else
68 : : #define USB_URB_EP_LINKING 0
69 : : #endif
70 : :
71 : : #include "dwc_otg_hcd_if.h"
72 : : #include "dwc_otg_dbg.h"
73 : : #include "dwc_otg_driver.h"
74 : : #include "dwc_otg_hcd.h"
75 : :
76 : : #ifndef __virt_to_bus
77 : : #define __virt_to_bus __virt_to_phys
78 : : #define __bus_to_virt __phys_to_virt
79 : : #define __pfn_to_bus(x) __pfn_to_phys(x)
80 : : #define __bus_to_pfn(x) __phys_to_pfn(x)
81 : : #endif
82 : :
83 : : extern unsigned char _dwc_otg_fiq_stub, _dwc_otg_fiq_stub_end;
84 : :
85 : : /**
86 : : * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
87 : : * qualified with its direction (possible 32 endpoints per device).
88 : : */
89 : : #define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
90 : : ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
91 : :
92 : : static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
93 : :
94 : : extern bool fiq_enable;
95 : :
96 : : /** @name Linux HC Driver API Functions */
97 : : /** @{ */
98 : : /* manage i/o requests, device state */
99 : : static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
100 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
101 : : struct usb_host_endpoint *ep,
102 : : #endif
103 : : struct urb *urb, gfp_t mem_flags);
104 : :
105 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
106 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
107 : : static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
108 : : #endif
109 : : #else /* kernels at or post 2.6.30 */
110 : : static int dwc_otg_urb_dequeue(struct usb_hcd *hcd,
111 : : struct urb *urb, int status);
112 : : #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */
113 : :
114 : : static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
115 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
116 : : static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
117 : : #endif
118 : : static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
119 : : extern int hcd_start(struct usb_hcd *hcd);
120 : : extern void hcd_stop(struct usb_hcd *hcd);
121 : : static int get_frame_number(struct usb_hcd *hcd);
122 : : extern int hub_status_data(struct usb_hcd *hcd, char *buf);
123 : : extern int hub_control(struct usb_hcd *hcd,
124 : : u16 typeReq,
125 : : u16 wValue, u16 wIndex, char *buf, u16 wLength);
126 : :
127 : : struct wrapper_priv_data {
128 : : dwc_otg_hcd_t *dwc_otg_hcd;
129 : : };
130 : :
131 : : /** @} */
132 : :
133 : : static struct hc_driver dwc_otg_hc_driver = {
134 : :
135 : : .description = dwc_otg_hcd_name,
136 : : .product_desc = "DWC OTG Controller",
137 : : .hcd_priv_size = sizeof(struct wrapper_priv_data),
138 : :
139 : : .irq = dwc_otg_hcd_irq,
140 : :
141 : : .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
142 : :
143 : : //.reset =
144 : : .start = hcd_start,
145 : : //.suspend =
146 : : //.resume =
147 : : .stop = hcd_stop,
148 : :
149 : : .urb_enqueue = dwc_otg_urb_enqueue,
150 : : .urb_dequeue = dwc_otg_urb_dequeue,
151 : : .endpoint_disable = endpoint_disable,
152 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
153 : : .endpoint_reset = endpoint_reset,
154 : : #endif
155 : : .get_frame_number = get_frame_number,
156 : :
157 : : .hub_status_data = hub_status_data,
158 : : .hub_control = hub_control,
159 : : //.bus_suspend =
160 : : //.bus_resume =
161 : : };
162 : :
163 : : /** Gets the dwc_otg_hcd from a struct usb_hcd */
164 : : static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
165 : : {
166 : : struct wrapper_priv_data *p;
167 : : p = (struct wrapper_priv_data *)(hcd->hcd_priv);
168 : 14035494 : return p->dwc_otg_hcd;
169 : : }
170 : :
171 : : /** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
172 : : static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
173 : : {
174 : 8902324 : return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
175 : : }
176 : :
177 : : /** Gets the usb_host_endpoint associated with an URB. */
178 : 0 : inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
179 : : {
180 : 221 : struct usb_device *dev = urb->dev;
181 : 221 : int ep_num = usb_pipeendpoint(urb->pipe);
182 : :
183 [ + - # # ]: 221 : if (usb_pipein(urb->pipe))
184 : 221 : return dev->ep_in[ep_num];
185 : : else
186 : 0 : return dev->ep_out[ep_num];
187 : : }
188 : :
189 : 0 : static int _disconnect(dwc_otg_hcd_t * hcd)
190 : : {
191 : : struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
192 : :
193 : 0 : usb_hcd->self.is_b_host = 0;
194 : 0 : return 0;
195 : : }
196 : :
197 : 0 : static int _start(dwc_otg_hcd_t * hcd)
198 : : {
199 : : struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
200 : :
201 : 0 : usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
202 : 0 : hcd_start(usb_hcd);
203 : :
204 : 0 : return 0;
205 : : }
206 : :
207 : 8665365 : static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
208 : : uint32_t * port_addr)
209 : : {
210 : : struct urb *urb = (struct urb *)urb_handle;
211 : : struct usb_bus *bus;
212 : : #if 1 //GRAYG - temporary
213 [ - + ]: 8665365 : if (NULL == urb_handle)
214 : 0 : DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
215 [ - + ]: 8665365 : if (NULL == urb->dev)
216 : 0 : DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
217 [ - + ]: 8665365 : if (NULL == port_addr)
218 : 0 : DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
219 : : #endif
220 [ + + ]: 8665365 : if (urb->dev->tt) {
221 [ - + ]: 8663709 : if (NULL == urb->dev->tt->hub) {
222 : 0 : DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n",
223 : : __func__); //GRAYG
224 : : //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG
225 : 0 : *hub_addr = 0; //GRAYG
226 : : // we probably shouldn't have a transaction translator if
227 : : // there's no associated hub?
228 : : } else {
229 : : bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd));
230 [ - + ]: 8663709 : if (urb->dev->tt->hub == bus->root_hub)
231 : 0 : *hub_addr = 0;
232 : : else
233 : 8663709 : *hub_addr = urb->dev->tt->hub->devnum;
234 : : }
235 : 8663709 : *port_addr = urb->dev->ttport;
236 : : } else {
237 : 1656 : *hub_addr = 0;
238 : 1656 : *port_addr = urb->dev->ttport;
239 : : }
240 : 8665365 : return 0;
241 : : }
242 : :
243 : 137827 : static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
244 : : {
245 : : struct urb *urb = (struct urb *)urb_handle;
246 : 137827 : return urb->dev->speed;
247 : : }
248 : :
249 : 0 : static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
250 : : {
251 : : struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
252 : 0 : return usb_hcd->self.b_hnp_enable;
253 : : }
254 : :
255 : : static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
256 : : struct urb *urb)
257 : : {
258 : 2 : hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
259 [ - + ]: 2 : if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
260 : 0 : hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
261 : : } else {
262 : 2 : hcd_to_bus(hcd)->bandwidth_int_reqs++;
263 : : }
264 : : }
265 : :
266 : : static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
267 : : struct urb *urb)
268 : : {
269 : 221 : hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
270 [ - + ]: 221 : if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
271 : 0 : hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
272 : : } else {
273 : 221 : hcd_to_bus(hcd)->bandwidth_int_reqs--;
274 : : }
275 : : }
276 : :
277 : : /**
278 : : * Sets the final status of an URB and returns it to the device driver. Any
279 : : * required cleanup of the URB is performed. The HCD lock should be held on
280 : : * entry.
281 : : */
282 : 119197 : static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
283 : : dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
284 : : {
285 : : struct urb *urb = (struct urb *)urb_handle;
286 : : urb_tq_entry_t *new_entry;
287 : : int rc = 0;
288 : : if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
289 : : DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
290 : : __func__, urb, usb_pipedevice(urb->pipe),
291 : : usb_pipeendpoint(urb->pipe),
292 : : usb_pipein(urb->pipe) ? "IN" : "OUT", status);
293 : : if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
294 : : int i;
295 : : for (i = 0; i < urb->number_of_packets; i++) {
296 : : DWC_PRINTF(" ISO Desc %d status: %d\n",
297 : : i, urb->iso_frame_desc[i].status);
298 : : }
299 : : }
300 : : }
301 : 119197 : new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t));
302 : 119197 : urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
303 : : /* Convert status value. */
304 [ - + - - : 119197 : switch (status) {
- - + - ]
305 : : case -DWC_E_PROTOCOL:
306 : : status = -EPROTO;
307 : : break;
308 : : case -DWC_E_IN_PROGRESS:
309 : : status = -EINPROGRESS;
310 : 0 : break;
311 : : case -DWC_E_PIPE:
312 : : status = -EPIPE;
313 : 207 : break;
314 : : case -DWC_E_IO:
315 : : status = -EIO;
316 : 0 : break;
317 : : case -DWC_E_TIMEOUT:
318 : : status = -ETIMEDOUT;
319 : 0 : break;
320 : : case -DWC_E_OVERFLOW:
321 : : status = -EOVERFLOW;
322 : 0 : break;
323 : : case -DWC_E_SHUTDOWN:
324 : : status = -ESHUTDOWN;
325 : 0 : break;
326 : : default:
327 [ - + ]: 118990 : if (status) {
328 : 0 : DWC_PRINTF("Uknown urb status %d\n", status);
329 : :
330 : : }
331 : : }
332 : :
333 [ - + ]: 119197 : if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
334 : : int i;
335 : :
336 : 0 : urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
337 : 0 : urb->actual_length = 0;
338 [ # # ]: 0 : for (i = 0; i < urb->number_of_packets; ++i) {
339 : 0 : urb->iso_frame_desc[i].actual_length =
340 : 0 : dwc_otg_hcd_urb_get_iso_desc_actual_length
341 : : (dwc_otg_urb, i);
342 : 0 : urb->actual_length += urb->iso_frame_desc[i].actual_length;
343 : 0 : urb->iso_frame_desc[i].status =
344 : 0 : dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
345 : : }
346 : : }
347 : :
348 : 119197 : urb->status = status;
349 : 119197 : urb->hcpriv = NULL;
350 [ + + ]: 119197 : if (!status) {
351 [ - + # # ]: 118990 : if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
352 : 0 : (urb->actual_length < urb->transfer_buffer_length)) {
353 : 0 : urb->status = -EREMOTEIO;
354 : : }
355 : : }
356 : :
357 [ + + ]: 119197 : if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
358 : : (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
359 : : struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
360 [ + - ]: 221 : if (ep) {
361 : 221 : free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
362 : 221 : dwc_otg_hcd_get_ep_bandwidth(hcd,
363 : : ep->hcpriv),
364 : : urb);
365 : : }
366 : : }
367 : 119197 : DWC_FREE(dwc_otg_urb);
368 [ - + ]: 119197 : if (!new_entry) {
369 : 0 : DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n");
370 : 0 : urb->status = -EPROTO;
371 : : /* don't schedule the tasklet -
372 : : * directly return the packet here with error. */
373 : : #if USB_URB_EP_LINKING
374 : 0 : usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
375 : : #endif
376 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
377 : : usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
378 : : #else
379 : 0 : usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
380 : : #endif
381 : : } else {
382 : 119197 : new_entry->urb = urb;
383 : : #if USB_URB_EP_LINKING
384 : 119197 : rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
385 [ + - ]: 119197 : if(0 == rc) {
386 : 119197 : usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
387 : : }
388 : : #endif
389 [ + - ]: 119197 : if(0 == rc) {
390 : 119197 : DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
391 : : urb_tq_entries);
392 : 119197 : DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
393 : : }
394 : : }
395 : 119197 : return 0;
396 : : }
397 : :
398 : : static struct dwc_otg_hcd_function_ops hcd_fops = {
399 : : .start = _start,
400 : : .disconnect = _disconnect,
401 : : .hub_info = _hub_info,
402 : : .speed = _speed,
403 : : .complete = _complete,
404 : : .get_b_hnp_enable = _get_b_hnp_enable,
405 : : };
406 : :
407 : : #ifdef CONFIG_ARM64
408 : :
409 : : static int simfiq_irq = -1;
410 : :
411 : : void local_fiq_enable(void)
412 : : {
413 : : if (simfiq_irq >= 0)
414 : : enable_irq(simfiq_irq);
415 : : }
416 : :
417 : : void local_fiq_disable(void)
418 : : {
419 : : if (simfiq_irq >= 0)
420 : : disable_irq(simfiq_irq);
421 : : }
422 : :
423 : : irqreturn_t fiq_irq_handler(int irq, void *dev_id)
424 : : {
425 : : dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *)dev_id;
426 : :
427 : : if (fiq_fsm_enable)
428 : : dwc_otg_fiq_fsm(dwc_otg_hcd->fiq_state, dwc_otg_hcd->core_if->core_params->host_channels);
429 : : else
430 : : dwc_otg_fiq_nop(dwc_otg_hcd->fiq_state);
431 : :
432 : : return IRQ_HANDLED;
433 : : }
434 : :
435 : : #else
436 : : static struct fiq_handler fh = {
437 : : .name = "usb_fiq",
438 : : };
439 : :
440 : : #endif
441 : :
442 : 207 : static void hcd_init_fiq(void *cookie)
443 : : {
444 : : dwc_otg_device_t *otg_dev = cookie;
445 : 207 : dwc_otg_hcd_t *dwc_otg_hcd = otg_dev->hcd;
446 : : #ifdef CONFIG_ARM64
447 : : int retval = 0;
448 : : int irq;
449 : : #else
450 : : struct pt_regs regs;
451 : : int irq;
452 : :
453 [ - + ]: 207 : if (claim_fiq(&fh)) {
454 : 0 : DWC_ERROR("Can't claim FIQ");
455 : 0 : BUG();
456 : : }
457 : 207 : DWC_WARN("FIQ on core %d", smp_processor_id());
458 : 207 : DWC_WARN("FIQ ASM at %px length %d", &_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
459 : 207 : set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
460 : 207 : memset(®s,0,sizeof(regs));
461 : :
462 : 207 : regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state;
463 [ + - ]: 207 : if (fiq_fsm_enable) {
464 : 207 : regs.ARM_r9 = dwc_otg_hcd->core_if->core_params->host_channels;
465 : : //regs.ARM_r10 = dwc_otg_hcd->dma;
466 : 207 : regs.ARM_fp = (long) dwc_otg_fiq_fsm;
467 : : } else {
468 : 0 : regs.ARM_fp = (long) dwc_otg_fiq_nop;
469 : : }
470 : :
471 : 207 : regs.ARM_sp = (long) dwc_otg_hcd->fiq_stack + (sizeof(struct fiq_stack) - 4);
472 : :
473 : : // __show_regs(®s);
474 : : set_fiq_regs(®s);
475 : : #endif
476 : :
477 : 207 : dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
478 : : //Set the mphi periph to the required registers
479 : 207 : dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
480 [ - + ]: 207 : if (otg_dev->os_dep.use_swirq) {
481 : 0 : dwc_otg_hcd->fiq_state->mphi_regs.swirq_set =
482 : 0 : otg_dev->os_dep.mphi_base + 0x1f0;
483 : 0 : dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr =
484 : 0 : otg_dev->os_dep.mphi_base + 0x1f4;
485 : 0 : DWC_WARN("Fake MPHI regs_base at 0x%08x",
486 : : (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
487 : : } else {
488 : 414 : dwc_otg_hcd->fiq_state->mphi_regs.ctrl =
489 : 207 : otg_dev->os_dep.mphi_base + 0x4c;
490 : 207 : dwc_otg_hcd->fiq_state->mphi_regs.outdda
491 : 207 : = otg_dev->os_dep.mphi_base + 0x28;
492 : 207 : dwc_otg_hcd->fiq_state->mphi_regs.outddb
493 : 207 : = otg_dev->os_dep.mphi_base + 0x2c;
494 : 207 : dwc_otg_hcd->fiq_state->mphi_regs.intstat
495 : 207 : = otg_dev->os_dep.mphi_base + 0x50;
496 : 207 : DWC_WARN("MPHI regs_base at %px",
497 : : dwc_otg_hcd->fiq_state->mphi_regs.base);
498 : :
499 : : //Enable mphi peripheral
500 : 207 : writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
501 : : #ifdef DEBUG
502 : : if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
503 : : DWC_WARN("MPHI periph has been enabled");
504 : : else
505 : : DWC_WARN("MPHI periph has NOT been enabled");
506 : : #endif
507 : : }
508 : : // Enable FIQ interrupt from USB peripheral
509 : : #ifdef CONFIG_ARM64
510 : : irq = otg_dev->os_dep.fiq_num;
511 : :
512 : : if (irq < 0) {
513 : : DWC_ERROR("Can't get SIM-FIQ irq");
514 : : return;
515 : : }
516 : :
517 : : retval = request_irq(irq, fiq_irq_handler, 0, "dwc_otg_sim-fiq", dwc_otg_hcd);
518 : :
519 : : if (retval < 0) {
520 : : DWC_ERROR("Unable to request SIM-FIQ irq\n");
521 : : return;
522 : : }
523 : :
524 : : simfiq_irq = irq;
525 : : #else
526 : : #ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLER
527 : 207 : irq = otg_dev->os_dep.fiq_num;
528 : : #else
529 : : irq = INTERRUPT_VC_USB;
530 : : #endif
531 [ - + ]: 207 : if (irq < 0) {
532 : 0 : DWC_ERROR("Can't get FIQ irq");
533 : 207 : return;
534 : : }
535 : : /*
536 : : * We could take an interrupt immediately after enabling the FIQ.
537 : : * Ensure coherency of hcd->fiq_state.
538 : : */
539 : 207 : smp_mb();
540 : 207 : enable_fiq(irq);
541 : 207 : local_fiq_enable();
542 : : #endif
543 : :
544 : : }
545 : :
546 : : /**
547 : : * Initializes the HCD. This function allocates memory for and initializes the
548 : : * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
549 : : * USB bus with the core and calls the hc_driver->start() function. It returns
550 : : * a negative error on failure.
551 : : */
552 : 207 : int hcd_init(dwc_bus_dev_t *_dev)
553 : : {
554 : : struct usb_hcd *hcd = NULL;
555 : : dwc_otg_hcd_t *dwc_otg_hcd = NULL;
556 : : dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
557 : : int retval = 0;
558 : : u64 dmamask;
559 : :
560 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
561 : :
562 : : /* Set device flags indicating whether the HCD supports DMA. */
563 [ - + ]: 207 : if (dwc_otg_is_dma_enable(otg_dev->core_if))
564 : : dmamask = DMA_BIT_MASK(32);
565 : : else
566 : : dmamask = 0;
567 : :
568 : : #if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE)
569 : 207 : dma_set_mask(&_dev->dev, dmamask);
570 : 207 : dma_set_coherent_mask(&_dev->dev, dmamask);
571 : : #elif defined(PCI_INTERFACE)
572 : : pci_set_dma_mask(_dev, dmamask);
573 : : pci_set_consistent_dma_mask(_dev, dmamask);
574 : : #endif
575 : :
576 : : /*
577 : : * Allocate memory for the base HCD plus the DWC OTG HCD.
578 : : * Initialize the base HCD.
579 : : */
580 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
581 : : hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
582 : : #else
583 : 207 : hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
584 : 207 : hcd->has_tt = 1;
585 : : // hcd->uses_new_polling = 1;
586 : : // hcd->poll_rh = 0;
587 : : #endif
588 [ + - ]: 207 : if (!hcd) {
589 : : retval = -ENOMEM;
590 : : goto error1;
591 : : }
592 : :
593 : 207 : hcd->regs = otg_dev->os_dep.base;
594 : :
595 : :
596 : : /* Initialize the DWC OTG HCD. */
597 : 207 : dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
598 [ + - ]: 207 : if (!dwc_otg_hcd) {
599 : : goto error2;
600 : : }
601 : 207 : ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
602 : : dwc_otg_hcd;
603 : 207 : otg_dev->hcd = dwc_otg_hcd;
604 : 207 : otg_dev->hcd->otg_dev = otg_dev;
605 : :
606 : : #ifdef CONFIG_ARM64
607 : : if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if))
608 : : goto error2;
609 : :
610 : : if (fiq_enable)
611 : : hcd_init_fiq(otg_dev);
612 : : #else
613 [ + - ]: 207 : if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
614 : : goto error2;
615 : : }
616 : :
617 [ + - ]: 207 : if (fiq_enable) {
618 [ + - ]: 207 : if (num_online_cpus() > 1) {
619 : : /*
620 : : * bcm2709: can run the FIQ on a separate core to IRQs.
621 : : * Ensure driver state is visible to other cores before setting up the FIQ.
622 : : */
623 : 207 : smp_mb();
624 : 207 : smp_call_function_single(1, hcd_init_fiq, otg_dev, 1);
625 : : } else {
626 : 0 : smp_call_function_single(0, hcd_init_fiq, otg_dev, 1);
627 : : }
628 : : }
629 : : #endif
630 : :
631 : 207 : hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
632 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
633 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later
634 : : hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
635 : : #endif
636 : : /* Don't support SG list at this point */
637 : 207 : hcd->self.sg_tablesize = 0;
638 : : #endif
639 : : /*
640 : : * Finish generic HCD initialization and start the HCD. This function
641 : : * allocates the DMA buffer pool, registers the USB bus, requests the
642 : : * IRQ line, and calls hcd_start method.
643 : : */
644 : 207 : retval = usb_add_hcd(hcd, otg_dev->os_dep.irq_num, IRQF_SHARED);
645 [ + - ]: 207 : if (retval < 0) {
646 : : goto error2;
647 : : }
648 : :
649 : 207 : dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
650 : 207 : return 0;
651 : :
652 : : error2:
653 : 0 : usb_put_hcd(hcd);
654 : : error1:
655 : 0 : return retval;
656 : : }
657 : :
658 : : /**
659 : : * Removes the HCD.
660 : : * Frees memory and resources associated with the HCD and deregisters the bus.
661 : : */
662 : 0 : void hcd_remove(dwc_bus_dev_t *_dev)
663 : : {
664 : : dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
665 : : dwc_otg_hcd_t *dwc_otg_hcd;
666 : : struct usb_hcd *hcd;
667 : :
668 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev);
669 : :
670 [ # # ]: 0 : if (!otg_dev) {
671 : : DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
672 : : return;
673 : : }
674 : :
675 : 0 : dwc_otg_hcd = otg_dev->hcd;
676 : :
677 [ # # ]: 0 : if (!dwc_otg_hcd) {
678 : : DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
679 : : return;
680 : : }
681 : :
682 : : hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
683 : :
684 [ # # ]: 0 : if (!hcd) {
685 : : DWC_DEBUGPL(DBG_ANY,
686 : : "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
687 : : __func__);
688 : : return;
689 : : }
690 : 0 : usb_remove_hcd(hcd);
691 : 0 : dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
692 : 0 : dwc_otg_hcd_remove(dwc_otg_hcd);
693 : 0 : usb_put_hcd(hcd);
694 : : }
695 : :
696 : : /* =========================================================================
697 : : * Linux HC Driver Functions
698 : : * ========================================================================= */
699 : :
700 : : /** Initializes the DWC_otg controller and its root hub and prepares it for host
701 : : * mode operation. Activates the root port. Returns 0 on success and a negative
702 : : * error code on failure. */
703 : 207 : int hcd_start(struct usb_hcd *hcd)
704 : : {
705 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
706 : : struct usb_bus *bus;
707 : :
708 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
709 : : bus = hcd_to_bus(hcd);
710 : :
711 : 207 : hcd->state = HC_STATE_RUNNING;
712 [ + - ]: 207 : if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
713 : : return 0;
714 : : }
715 : :
716 : : /* Initialize and connect root hub if one is not already attached */
717 [ + - ]: 207 : if (bus->root_hub) {
718 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
719 : : /* Inform the HUB driver to resume. */
720 : 207 : usb_hcd_resume_root_hub(hcd);
721 : : }
722 : :
723 : : return 0;
724 : : }
725 : :
726 : : /**
727 : : * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
728 : : * stopped.
729 : : */
730 : 0 : void hcd_stop(struct usb_hcd *hcd)
731 : : {
732 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
733 : :
734 : 0 : dwc_otg_hcd_stop(dwc_otg_hcd);
735 : 0 : }
736 : :
737 : : /** Returns the current frame number. */
738 : 0 : static int get_frame_number(struct usb_hcd *hcd)
739 : : {
740 : : hprt0_data_t hprt0;
741 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
742 : 0 : hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
743 [ # # ]: 0 : if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
744 : 0 : return dwc_otg_hcd_get_frame_number(dwc_otg_hcd) >> 3;
745 : : else
746 : 0 : return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
747 : : }
748 : :
749 : : #ifdef DEBUG
750 : : static void dump_urb_info(struct urb *urb, char *fn_name)
751 : : {
752 : : DWC_PRINTF("%s, urb %p\n", fn_name, urb);
753 : : DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
754 : : DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
755 : : (usb_pipein(urb->pipe) ? "IN" : "OUT"));
756 : : DWC_PRINTF(" Endpoint type: %s\n", ( {
757 : : char *pipetype;
758 : : switch (usb_pipetype(urb->pipe)) {
759 : : case PIPE_CONTROL:
760 : : pipetype = "CONTROL"; break; case PIPE_BULK:
761 : : pipetype = "BULK"; break; case PIPE_INTERRUPT:
762 : : pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
763 : : pipetype = "ISOCHRONOUS"; break; default:
764 : : pipetype = "UNKNOWN"; break;};
765 : : pipetype;}
766 : : )) ;
767 : : DWC_PRINTF(" Speed: %s\n", ( {
768 : : char *speed; switch (urb->dev->speed) {
769 : : case USB_SPEED_HIGH:
770 : : speed = "HIGH"; break; case USB_SPEED_FULL:
771 : : speed = "FULL"; break; case USB_SPEED_LOW:
772 : : speed = "LOW"; break; default:
773 : : speed = "UNKNOWN"; break;};
774 : : speed;}
775 : : )) ;
776 : : DWC_PRINTF(" Max packet size: %d\n",
777 : : usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
778 : : DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
779 : : DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
780 : : urb->transfer_buffer, (void *)urb->transfer_dma);
781 : : DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
782 : : urb->setup_packet, (void *)urb->setup_dma);
783 : : DWC_PRINTF(" Interval: %d\n", urb->interval);
784 : : if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
785 : : int i;
786 : : for (i = 0; i < urb->number_of_packets; i++) {
787 : : DWC_PRINTF(" ISO Desc %d:\n", i);
788 : : DWC_PRINTF(" offset: %d, length %d\n",
789 : : urb->iso_frame_desc[i].offset,
790 : : urb->iso_frame_desc[i].length);
791 : : }
792 : : }
793 : : }
794 : : #endif
795 : :
796 : : /** Starts processing a USB transfer request specified by a USB Request Block
797 : : * (URB). mem_flags indicates the type of memory allocation to use while
798 : : * processing this URB. */
799 : 134721 : static int dwc_otg_urb_enqueue(struct usb_hcd *hcd,
800 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
801 : : struct usb_host_endpoint *ep,
802 : : #endif
803 : : struct urb *urb, gfp_t mem_flags)
804 : : {
805 : : int retval = 0;
806 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
807 : 134721 : struct usb_host_endpoint *ep = urb->ep;
808 : : #endif
809 : : dwc_irqflags_t irqflags;
810 : 134721 : void **ref_ep_hcpriv = &ep->hcpriv;
811 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
812 : : dwc_otg_hcd_urb_t *dwc_otg_urb;
813 : : int i;
814 : : int alloc_bandwidth = 0;
815 : : uint8_t ep_type = 0;
816 : : uint32_t flags = 0;
817 : : void *buf;
818 : :
819 : : #ifdef DEBUG
820 : : if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
821 : : dump_urb_info(urb, "dwc_otg_urb_enqueue");
822 : : }
823 : : #endif
824 [ + + ]: 134721 : if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
825 : : || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
826 [ + + ]: 1256 : if (!dwc_otg_hcd_is_bandwidth_allocated
827 : : (dwc_otg_hcd, ref_ep_hcpriv)) {
828 : : alloc_bandwidth = 1;
829 : : }
830 : : }
831 : :
832 [ - + + - : 134721 : switch (usb_pipetype(urb->pipe)) {
+ ]
833 : : case PIPE_CONTROL:
834 : : ep_type = USB_ENDPOINT_XFER_CONTROL;
835 : : break;
836 : : case PIPE_ISOCHRONOUS:
837 : : ep_type = USB_ENDPOINT_XFER_ISOC;
838 : 0 : break;
839 : : case PIPE_BULK:
840 : : ep_type = USB_ENDPOINT_XFER_BULK;
841 : 32152 : break;
842 : : case PIPE_INTERRUPT:
843 : : ep_type = USB_ENDPOINT_XFER_INT;
844 : 1256 : break;
845 : : default:
846 : 0 : DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe));
847 : : }
848 : :
849 : : /* # of packets is often 0 - do we really need to call this then? */
850 : 134721 : dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
851 : : urb->number_of_packets,
852 : : mem_flags == GFP_ATOMIC ? 1 : 0);
853 : :
854 [ + + ]: 134722 : if(dwc_otg_urb == NULL)
855 : : return -ENOMEM;
856 : :
857 [ - + # # ]: 134717 : if (!dwc_otg_urb && urb->number_of_packets)
858 : : return -ENOMEM;
859 : :
860 : 404151 : dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
861 : 134717 : usb_pipeendpoint(urb->pipe), ep_type,
862 : : usb_pipein(urb->pipe),
863 : : usb_maxpacket(urb->dev, urb->pipe,
864 : 134717 : !(usb_pipein(urb->pipe))));
865 : :
866 : 134719 : buf = urb->transfer_buffer;
867 [ + + + + : 134719 : if (hcd_uses_dma(hcd) && !buf && urb->transfer_buffer_length) {
- + ]
868 : : /*
869 : : * Calculate virtual address from physical address,
870 : : * because some class driver may not fill transfer_buffer.
871 : : * In Buffer DMA mode virual address is used,
872 : : * when handling non DWORD aligned buffers.
873 : : */
874 : 0 : buf = (void *)__bus_to_virt((unsigned long)urb->transfer_dma);
875 [ # # ]: 0 : dev_warn_once(&urb->dev->dev,
876 : : "USB transfer_buffer was NULL, will use __bus_to_virt(%pad)=%p\n",
877 : : &urb->transfer_dma, buf);
878 : : }
879 : :
880 [ + + - + ]: 134722 : if (!buf && urb->transfer_buffer_length) {
881 : 0 : DWC_FREE(dwc_otg_urb);
882 : 0 : DWC_ERROR("transfer_buffer is NULL in PIO mode or both "
883 : : "transfer_buffer and transfer_dma are NULL in DMA mode\n");
884 : 0 : return -EINVAL;
885 : : }
886 : :
887 [ + - ]: 134722 : if (!(urb->transfer_flags & URB_NO_INTERRUPT))
888 : : flags |= URB_GIVEBACK_ASAP;
889 [ - + ]: 134722 : if (urb->transfer_flags & URB_ZERO_PACKET)
890 : 0 : flags |= URB_SEND_ZERO_PACKET;
891 : :
892 : 404166 : dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
893 : : urb->transfer_dma,
894 : : urb->transfer_buffer_length,
895 : 134722 : urb->setup_packet,
896 : 134722 : urb->setup_dma, flags, urb->interval);
897 : :
898 [ - + ]: 134717 : for (i = 0; i < urb->number_of_packets; ++i) {
899 : 0 : dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
900 : : urb->
901 : : iso_frame_desc[i].offset,
902 : : urb->
903 : : iso_frame_desc[i].length);
904 : : }
905 : :
906 : 134717 : DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
907 : 134722 : urb->hcpriv = dwc_otg_urb;
908 : : #if USB_URB_EP_LINKING
909 : 134722 : retval = usb_hcd_link_urb_to_ep(hcd, urb);
910 [ + - ]: 134722 : if (0 == retval)
911 : : #endif
912 : : {
913 : 134722 : retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
914 : : /*(dwc_otg_qh_t **)*/
915 : : ref_ep_hcpriv, 1);
916 [ + - ]: 134722 : if (0 == retval) {
917 [ + + ]: 134722 : if (alloc_bandwidth) {
918 : 2 : allocate_bus_bandwidth(hcd,
919 : 2 : dwc_otg_hcd_get_ep_bandwidth(
920 : : dwc_otg_hcd, *ref_ep_hcpriv),
921 : : urb);
922 : : }
923 : : } else {
924 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
925 : : #if USB_URB_EP_LINKING
926 : 0 : usb_hcd_unlink_urb_from_ep(hcd, urb);
927 : : #endif
928 : 0 : DWC_FREE(dwc_otg_urb);
929 : 0 : urb->hcpriv = NULL;
930 [ # # ]: 0 : if (retval == -DWC_E_NO_DEVICE)
931 : : retval = -ENODEV;
932 : : }
933 : : }
934 : : #if USB_URB_EP_LINKING
935 : : else
936 : : {
937 : 0 : DWC_FREE(dwc_otg_urb);
938 : 0 : urb->hcpriv = NULL;
939 : : }
940 : : #endif
941 : 134722 : DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
942 : 134722 : return retval;
943 : : }
944 : :
945 : : /** Aborts/cancels a USB transfer request. Always returns 0 to indicate
946 : : * success. */
947 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
948 : : static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
949 : : #else
950 : 7245 : static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
951 : : #endif
952 : : {
953 : : dwc_irqflags_t flags;
954 : : dwc_otg_hcd_t *dwc_otg_hcd;
955 : : int rc;
956 : :
957 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
958 : :
959 : : dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
960 : :
961 : : #ifdef DEBUG
962 : : if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
963 : : dump_urb_info(urb, "dwc_otg_urb_dequeue");
964 : : }
965 : : #endif
966 : :
967 : 7245 : DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
968 : 7245 : rc = usb_hcd_check_unlink_urb(hcd, urb, status);
969 [ + - ]: 7245 : if (0 == rc) {
970 [ + - ]: 7245 : if(urb->hcpriv != NULL) {
971 : 7245 : dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
972 : : (dwc_otg_hcd_urb_t *)urb->hcpriv);
973 : :
974 : 7245 : DWC_FREE(urb->hcpriv);
975 : 7245 : urb->hcpriv = NULL;
976 : : }
977 : : }
978 : :
979 [ + - ]: 7245 : if (0 == rc) {
980 : : /* Higher layer software sets URB status. */
981 : : #if USB_URB_EP_LINKING
982 : 7245 : usb_hcd_unlink_urb_from_ep(hcd, urb);
983 : : #endif
984 : 7245 : DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
985 : :
986 : :
987 : : #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
988 : : usb_hcd_giveback_urb(hcd, urb);
989 : : #else
990 : 7245 : usb_hcd_giveback_urb(hcd, urb, status);
991 : : #endif
992 : : if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
993 : : DWC_PRINTF("Called usb_hcd_giveback_urb() \n");
994 : : DWC_PRINTF(" 1urb->status = %d\n", urb->status);
995 : : }
996 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n");
997 : : } else {
998 : 0 : DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
999 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n",
1000 : : rc);
1001 : : }
1002 : :
1003 : 7245 : return rc;
1004 : : }
1005 : :
1006 : : /* Frees resources in the DWC_otg controller related to a given endpoint. Also
1007 : : * clears state in the HCD related to the endpoint. Any URBs for the endpoint
1008 : : * must already be dequeued. */
1009 : 2484 : static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1010 : : {
1011 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
1012 : :
1013 : : DWC_DEBUGPL(DBG_HCD,
1014 : : "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
1015 : : "endpoint=%d\n", ep->desc.bEndpointAddress,
1016 : : dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
1017 : 2484 : dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
1018 : 2484 : ep->hcpriv = NULL;
1019 : 2484 : }
1020 : :
1021 : : #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
1022 : : /* Resets endpoint specific parameter values, in current version used to reset
1023 : : * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
1024 : 3312 : static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1025 : : {
1026 : : dwc_irqflags_t flags;
1027 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
1028 : :
1029 : : DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
1030 : :
1031 : 3312 : DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
1032 [ - + ]: 3312 : if (ep->hcpriv) {
1033 : 0 : dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
1034 : : }
1035 : 3312 : DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
1036 : 3312 : }
1037 : : #endif
1038 : :
1039 : : /** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
1040 : : * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
1041 : : * interrupt.
1042 : : *
1043 : : * This function is called by the USB core when an interrupt occurs */
1044 : 13795455 : static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
1045 : : {
1046 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
1047 : 13795455 : int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
1048 : : if (retval != 0) {
1049 : : S3C2410X_CLEAR_EINTPEND();
1050 : : }
1051 : 13795449 : return IRQ_RETVAL(retval);
1052 : : }
1053 : :
1054 : : /** Creates Status Change bitmap for the root hub and root port. The bitmap is
1055 : : * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
1056 : : * is the status change indicator for the single root port. Returns 1 if either
1057 : : * change indicator is 1, otherwise returns 0. */
1058 : 89172 : int hub_status_data(struct usb_hcd *hcd, char *buf)
1059 : : {
1060 : : dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
1061 : :
1062 : 89172 : buf[0] = 0;
1063 : 89172 : buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
1064 : :
1065 : 89172 : return (buf[0] != 0);
1066 : : }
1067 : :
1068 : : /** Handles hub class-specific requests. */
1069 : 2898 : int hub_control(struct usb_hcd *hcd,
1070 : : u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
1071 : : {
1072 : : int retval;
1073 : :
1074 : 2898 : retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
1075 : : typeReq, wValue, wIndex, buf, wLength);
1076 : :
1077 [ - + ]: 2898 : switch (retval) {
1078 : : case -DWC_E_INVALID:
1079 : : retval = -EINVAL;
1080 : 0 : break;
1081 : : }
1082 : :
1083 : 2898 : return retval;
1084 : : }
1085 : :
1086 : : #endif /* DWC_DEVICE_ONLY */
|