LCOV - code coverage report
Current view: top level - drivers/usb/host/dwc_otg - dwc_otg_hcd_linux.c (source / functions) Hit Total Coverage
Test: Real Lines: 180 264 68.2 %
Date: 2020-10-17 15:46:16 Functions: 2 20 10.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           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                 :          3 :         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                 :          3 :         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                 :          3 :         struct usb_device *dev = urb->dev;
     181                 :          3 :         int ep_num = usb_pipeendpoint(urb->pipe);
     182                 :            : 
     183                 :          3 :         if (usb_pipein(urb->pipe))
     184                 :          3 :                 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                 :          3 : 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                 :          3 :    if (NULL == urb_handle)
     214                 :          0 :       DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG
     215                 :          3 :    if (NULL == urb->dev)
     216                 :          0 :       DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG
     217                 :          3 :    if (NULL == port_addr)
     218                 :          0 :       DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG
     219                 :            : #endif
     220                 :          3 :    if (urb->dev->tt) {
     221                 :          3 :         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                 :          3 :                 if (urb->dev->tt->hub == bus->root_hub)
     231                 :          1 :                         *hub_addr = 0;
     232                 :            :                 else
     233                 :          2 :                         *hub_addr = urb->dev->tt->hub->devnum;
     234                 :            :         }
     235                 :          3 :         *port_addr = urb->dev->ttport;
     236                 :            :    } else {
     237                 :          2 :         *hub_addr = 0;
     238                 :          2 :         *port_addr = urb->dev->ttport;
     239                 :            :    }
     240                 :          3 :    return 0;
     241                 :            : }
     242                 :            : 
     243                 :          3 : static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
     244                 :            : {
     245                 :            :         struct urb *urb = (struct urb *)urb_handle;
     246                 :          3 :         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                 :          3 :         hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
     270                 :          3 :         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
     271                 :          0 :                 hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
     272                 :            :         } else {
     273                 :          3 :                 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                 :          3 : 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                 :          3 :         new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t));
     302                 :          3 :         urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
     303                 :            :         /* Convert status value. */
     304                 :          3 :         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                 :          3 :                 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                 :          3 :                 if (status) {
     328                 :          0 :                         DWC_PRINTF("Uknown urb status %d\n", status);
     329                 :            : 
     330                 :            :                 }
     331                 :            :         }
     332                 :            : 
     333                 :          3 :         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                 :          3 :         urb->status = status;
     349                 :          3 :         urb->hcpriv = NULL;
     350                 :          3 :         if (!status) {
     351                 :          3 :                 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                 :          3 :         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                 :          3 :                 if (ep) {
     361                 :          3 :                         free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
     362                 :          3 :                                            dwc_otg_hcd_get_ep_bandwidth(hcd,
     363                 :            :                                                                         ep->hcpriv),
     364                 :            :                                            urb);
     365                 :            :                 }
     366                 :            :         }
     367                 :          3 :         DWC_FREE(dwc_otg_urb);
     368                 :          3 :         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                 :          3 :                 new_entry->urb = urb;
     383                 :            : #if USB_URB_EP_LINKING
     384                 :          3 :                 rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
     385                 :          3 :                 if(0 == rc) {
     386                 :          3 :                         usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
     387                 :            :                 }
     388                 :            : #endif
     389                 :          3 :                 if(0 == rc) {
     390                 :          3 :                         DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
     391                 :            :                                                 urb_tq_entries);
     392                 :          3 :                         DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
     393                 :            :                 }
     394                 :            :         }
     395                 :          3 :         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                 :          3 : static void hcd_init_fiq(void *cookie)
     443                 :            : {
     444                 :            :         dwc_otg_device_t *otg_dev = cookie;
     445                 :          3 :         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                 :          3 :         if (claim_fiq(&fh)) {
     454                 :          0 :                 DWC_ERROR("Can't claim FIQ");
     455                 :          0 :                 BUG();
     456                 :            :         }
     457                 :          3 :         DWC_WARN("FIQ on core %d", smp_processor_id());
     458                 :          3 :         DWC_WARN("FIQ ASM at %px length %d", &_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
     459                 :          3 :         set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
     460                 :          3 :         memset(&regs,0,sizeof(regs));
     461                 :            : 
     462                 :          3 :         regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state;
     463                 :          3 :         if (fiq_fsm_enable) {
     464                 :          2 :                 regs.ARM_r9 = dwc_otg_hcd->core_if->core_params->host_channels;
     465                 :            :                 //regs.ARM_r10 = dwc_otg_hcd->dma;
     466                 :          2 :                 regs.ARM_fp = (long) dwc_otg_fiq_fsm;
     467                 :            :         } else {
     468                 :          1 :                 regs.ARM_fp = (long) dwc_otg_fiq_nop;
     469                 :            :         }
     470                 :            : 
     471                 :          3 :         regs.ARM_sp = (long) dwc_otg_hcd->fiq_stack + (sizeof(struct fiq_stack) - 4);
     472                 :            : 
     473                 :            : //              __show_regs(&regs);
     474                 :            :         set_fiq_regs(&regs);
     475                 :            : #endif
     476                 :            : 
     477                 :          3 :         dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
     478                 :            :         //Set the mphi periph to the required registers
     479                 :          3 :         dwc_otg_hcd->fiq_state->mphi_regs.base    = otg_dev->os_dep.mphi_base;
     480                 :          3 :         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                 :          3 :                 dwc_otg_hcd->fiq_state->mphi_regs.ctrl =
     489                 :          3 :                         otg_dev->os_dep.mphi_base + 0x4c;
     490                 :          3 :                 dwc_otg_hcd->fiq_state->mphi_regs.outdda
     491                 :          3 :                         = otg_dev->os_dep.mphi_base + 0x28;
     492                 :          3 :                 dwc_otg_hcd->fiq_state->mphi_regs.outddb
     493                 :          3 :                         = otg_dev->os_dep.mphi_base + 0x2c;
     494                 :          3 :                 dwc_otg_hcd->fiq_state->mphi_regs.intstat
     495                 :          3 :                         = otg_dev->os_dep.mphi_base + 0x50;
     496                 :          3 :                 DWC_WARN("MPHI regs_base at %px",
     497                 :            :                          dwc_otg_hcd->fiq_state->mphi_regs.base);
     498                 :            : 
     499                 :            :                 //Enable mphi peripheral
     500                 :          3 :                 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                 :          3 :         irq = otg_dev->os_dep.fiq_num;
     528                 :            : #else
     529                 :            :         irq = INTERRUPT_VC_USB;
     530                 :            : #endif
     531                 :          3 :         if (irq < 0) {
     532                 :          0 :                 DWC_ERROR("Can't get FIQ irq");
     533                 :          3 :                 return;
     534                 :            :         }
     535                 :            :         /*
     536                 :            :          * We could take an interrupt immediately after enabling the FIQ.
     537                 :            :          * Ensure coherency of hcd->fiq_state.
     538                 :            :          */
     539                 :          3 :         smp_mb();
     540                 :          3 :         enable_fiq(irq);
     541                 :          3 :         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                 :          3 : 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                 :          3 :         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                 :          3 :         dma_set_mask(&_dev->dev, dmamask);
     570                 :          3 :         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                 :          3 :         hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
     584                 :          3 :         hcd->has_tt = 1;
     585                 :            : //      hcd->uses_new_polling = 1;
     586                 :            : //      hcd->poll_rh = 0;
     587                 :            : #endif
     588                 :          3 :         if (!hcd) {
     589                 :            :                 retval = -ENOMEM;
     590                 :            :                 goto error1;
     591                 :            :         }
     592                 :            : 
     593                 :          3 :         hcd->regs = otg_dev->os_dep.base;
     594                 :            : 
     595                 :            : 
     596                 :            :         /* Initialize the DWC OTG HCD. */
     597                 :          3 :         dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
     598                 :          3 :         if (!dwc_otg_hcd) {
     599                 :            :                 goto error2;
     600                 :            :         }
     601                 :          3 :         ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
     602                 :            :             dwc_otg_hcd;
     603                 :          3 :         otg_dev->hcd = dwc_otg_hcd;
     604                 :          3 :         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                 :          3 :         if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
     614                 :            :                 goto error2;
     615                 :            :         }
     616                 :            : 
     617                 :          3 :         if (fiq_enable) {
     618                 :          3 :                 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                 :          3 :                         smp_mb();
     624                 :          3 :                         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                 :          3 :         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                 :          3 :         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                 :          3 :         retval = usb_add_hcd(hcd, otg_dev->os_dep.irq_num, IRQF_SHARED);
     645                 :          3 :         if (retval < 0) {
     646                 :            :                 goto error2;
     647                 :            :         }
     648                 :            : 
     649                 :          3 :         dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
     650                 :          3 :         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                 :          3 : 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                 :          3 :         hcd->state = HC_STATE_RUNNING;
     712                 :          3 :         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                 :          3 :         if (bus->root_hub) {
     718                 :            :                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
     719                 :            :                 /* Inform the HUB driver to resume. */
     720                 :          3 :                 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                 :          3 : 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                 :          3 :         struct usb_host_endpoint *ep = urb->ep;
     808                 :            : #endif
     809                 :            :         dwc_irqflags_t irqflags;
     810                 :          3 :         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                 :          3 :         if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
     825                 :            :             || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
     826                 :          3 :                 if (!dwc_otg_hcd_is_bandwidth_allocated
     827                 :            :                     (dwc_otg_hcd, ref_ep_hcpriv)) {
     828                 :            :                         alloc_bandwidth = 1;
     829                 :            :                 }
     830                 :            :         }
     831                 :            : 
     832                 :          3 :         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                 :          3 :                 break;
     842                 :            :         case PIPE_INTERRUPT:
     843                 :            :                 ep_type = USB_ENDPOINT_XFER_INT;
     844                 :          3 :                 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                 :          3 :         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                 :          3 :         if(dwc_otg_urb == NULL)
     855                 :            :                 return -ENOMEM;
     856                 :            : 
     857                 :          3 :         if (!dwc_otg_urb && urb->number_of_packets)
     858                 :            :                 return -ENOMEM;
     859                 :            : 
     860                 :          3 :         dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
     861                 :          3 :                                      usb_pipeendpoint(urb->pipe), ep_type,
     862                 :            :                                      usb_pipein(urb->pipe),
     863                 :            :                                      usb_maxpacket(urb->dev, urb->pipe,
     864                 :          3 :                                                    !(usb_pipein(urb->pipe))));
     865                 :            : 
     866                 :          3 :         buf = urb->transfer_buffer;
     867                 :          3 :         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                 :          3 :         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                 :          3 :         if (!(urb->transfer_flags & URB_NO_INTERRUPT))
     888                 :            :                 flags |= URB_GIVEBACK_ASAP;
     889                 :          3 :         if (urb->transfer_flags & URB_ZERO_PACKET)
     890                 :          0 :                 flags |= URB_SEND_ZERO_PACKET;
     891                 :            : 
     892                 :          3 :         dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
     893                 :            :                                    urb->transfer_dma,
     894                 :            :                                    urb->transfer_buffer_length,
     895                 :          3 :                                    urb->setup_packet,
     896                 :          3 :                                    urb->setup_dma, flags, urb->interval);
     897                 :            : 
     898                 :          3 :         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                 :          3 :         DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
     907                 :          3 :         urb->hcpriv = dwc_otg_urb;
     908                 :            : #if USB_URB_EP_LINKING
     909                 :          3 :         retval = usb_hcd_link_urb_to_ep(hcd, urb);
     910                 :          3 :         if (0 == retval)
     911                 :            : #endif
     912                 :            :         {
     913                 :          3 :                 retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
     914                 :            :                                                 /*(dwc_otg_qh_t **)*/
     915                 :            :                                                 ref_ep_hcpriv, 1);
     916                 :          3 :                 if (0 == retval) {
     917                 :          3 :                         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                 :          3 :         DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
     942                 :          3 :         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                 :          3 : 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                 :          3 :         DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
     968                 :          3 :         rc = usb_hcd_check_unlink_urb(hcd, urb, status);
     969                 :          3 :         if (0 == rc) {
     970                 :          3 :                 if(urb->hcpriv != NULL) {
     971                 :          3 :                         dwc_otg_hcd_urb_dequeue(dwc_otg_hcd,
     972                 :            :                                             (dwc_otg_hcd_urb_t *)urb->hcpriv);
     973                 :            : 
     974                 :          3 :                         DWC_FREE(urb->hcpriv);
     975                 :          3 :                         urb->hcpriv = NULL;
     976                 :            :                 }
     977                 :            :         }
     978                 :            : 
     979                 :          3 :         if (0 == rc) {
     980                 :            :                 /* Higher layer software sets URB status. */
     981                 :            : #if USB_URB_EP_LINKING
     982                 :          3 :                 usb_hcd_unlink_urb_from_ep(hcd, urb);
     983                 :            : #endif
     984                 :          3 :                 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                 :          3 :                 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                 :          3 :         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                 :          3 : 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                 :          3 :         dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
    1018                 :          3 :         ep->hcpriv = NULL;
    1019                 :          3 : }
    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                 :          3 : 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                 :          3 :         DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
    1032                 :          3 :         if (ep->hcpriv) {
    1033                 :          0 :                 dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
    1034                 :            :         }
    1035                 :          3 :         DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
    1036                 :          3 : }
    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                 :          3 : 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                 :          3 :         int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
    1048                 :            :         if (retval != 0) {
    1049                 :            :                 S3C2410X_CLEAR_EINTPEND();
    1050                 :            :         }
    1051                 :          3 :         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                 :          3 : 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                 :          3 :         buf[0] = 0;
    1063                 :          3 :         buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
    1064                 :            : 
    1065                 :          3 :         return (buf[0] != 0);
    1066                 :            : }
    1067                 :            : 
    1068                 :            : /** Handles hub class-specific requests. */
    1069                 :          3 : int hub_control(struct usb_hcd *hcd,
    1070                 :            :                 u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
    1071                 :            : {
    1072                 :            :         int retval;
    1073                 :            : 
    1074                 :          3 :         retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
    1075                 :            :                                          typeReq, wValue, wIndex, buf, wLength);
    1076                 :            : 
    1077                 :          3 :         switch (retval) {
    1078                 :            :         case -DWC_E_INVALID:
    1079                 :            :                 retval = -EINVAL;
    1080                 :          0 :                 break;
    1081                 :            :         }
    1082                 :            : 
    1083                 :          3 :         return retval;
    1084                 :            : }
    1085                 :            : 
    1086                 :            : #endif /* DWC_DEVICE_ONLY */
    

Generated by: LCOV version 1.14