LCOV - code coverage report
Current view: top level - drivers/usb/host/dwc_otg - dwc_otg_pcd_linux.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 53 225 23.6 %
Date: 2020-09-30 20:25:40 Functions: 4 24 16.7 %
Branches: 9 141 6.4 %

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

Generated by: LCOV version 1.14