Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

dwc_otg_pcd_linux.c

Go to the documentation of this file.
00001  /* ==========================================================================
00002   * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
00003   * $Revision: #19 $
00004   * $Date: 2011/10/26 $
00005   * $Change: 1873028 $
00006   *
00007   * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
00008   * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
00009   * otherwise expressly agreed to in writing between Synopsys and you.
00010   *
00011   * The Software IS NOT an item of Licensed Software or Licensed Product under
00012   * any End User Software License Agreement or Agreement for Licensed Product
00013   * with Synopsys or any supplement thereto. You are permitted to use and
00014   * redistribute this Software in source and binary forms, with or without
00015   * modification, provided that redistributions of source code must retain this
00016   * notice. You may not view, use, disclose, copy or distribute this file or
00017   * any information contained herein except pursuant to this license grant from
00018   * Synopsys. If you do not agree with this notice, including the disclaimer
00019   * below, then you are not authorized to use the Software.
00020   *
00021   * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
00022   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024   * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
00025   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00027   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00031   * DAMAGE.
00032   * ========================================================================== */
00033 #ifndef DWC_HOST_ONLY
00034 
00056 #include "dwc_otg_os_dep.h"
00057 #include "dwc_otg_pcd_if.h"
00058 #include "dwc_otg_pcd.h"
00059 #include "dwc_otg_driver.h"
00060 #include "dwc_otg_dbg.h"
00061 
00062 static struct gadget_wrapper {
00063         dwc_otg_pcd_t *pcd;
00064 
00065         struct usb_gadget gadget;
00066         struct usb_gadget_driver *driver;
00067 
00068         struct usb_ep ep0;
00069         struct usb_ep in_ep[16];
00070         struct usb_ep out_ep[16];
00071 
00072 } *gadget_wrapper;
00073 
00074 /* Display the contents of the buffer */
00075 extern void dump_msg(const u8 * buf, unsigned int length);
00080 static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
00081 {
00082         int i;
00083         if (pcd->ep0.priv == handle) {
00084                 return &pcd->ep0;
00085         }
00086 
00087         for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
00088                 if (pcd->in_ep[i].priv == handle)
00089                         return &pcd->in_ep[i];
00090                 if (pcd->out_ep[i].priv == handle)
00091                         return &pcd->out_ep[i];
00092         }
00093 
00094         return NULL;
00095 }
00096 
00097 /* USB Endpoint Operations */
00098 /*
00099  * The following sections briefly describe the behavior of the Gadget
00100  * API endpoint operations implemented in the DWC_otg driver
00101  * software. Detailed descriptions of the generic behavior of each of
00102  * these functions can be found in the Linux header file
00103  * include/linux/usb_gadget.h.
00104  *
00105  * The Gadget API provides wrapper functions for each of the function
00106  * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
00107  * function, which then calls the underlying PCD function. The
00108  * following sections are named according to the wrapper
00109  * functions. Within each section, the corresponding DWC_otg PCD
00110  * function name is specified.
00111  *
00112  */
00113 
00121 static int ep_enable(struct usb_ep *usb_ep,
00122                      const struct usb_endpoint_descriptor *ep_desc)
00123 {
00124         int retval;
00125 
00126         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
00127 
00128         if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
00129                 DWC_WARN("%s, bad ep or descriptor\n", __func__);
00130                 return -EINVAL;
00131         }
00132         if (usb_ep == &gadget_wrapper->ep0) {
00133                 DWC_WARN("%s, bad ep(0)\n", __func__);
00134                 return -EINVAL;
00135         }
00136 
00137         /* Check FIFO size? */
00138         if (!ep_desc->wMaxPacketSize) {
00139                 DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
00140                 return -ERANGE;
00141         }
00142 
00143         if (!gadget_wrapper->driver ||
00144             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00145                 DWC_WARN("%s, bogus device state\n", __func__);
00146                 return -ESHUTDOWN;
00147         }
00148 
00149         /* Delete after check - MAS */
00150 #if 0
00151         nat = (uint32_t) ep_desc->wMaxPacketSize;
00152         printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat);
00153         nat = (nat >> 11) & 0x03;
00154         printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat);
00155 #endif
00156         retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
00157                                        (const uint8_t *)ep_desc,
00158                                        (void *)usb_ep);
00159         if (retval) {
00160                 DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
00161                 return -EINVAL;
00162         }
00163 
00164         usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
00165 
00166         return 0;
00167 }
00168 
00177 static int ep_disable(struct usb_ep *usb_ep)
00178 {
00179         int retval;
00180 
00181         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
00182         if (!usb_ep) {
00183                 DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
00184                             usb_ep ? usb_ep->name : NULL);
00185                 return -EINVAL;
00186         }
00187 
00188         retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
00189         if (retval) {
00190                 retval = -EINVAL;
00191         }
00192 
00193         return retval;
00194 }
00195 
00203 static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
00204                                                      gfp_t gfp_flags)
00205 {
00206         struct usb_request *usb_req;
00207 
00208         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
00209         if (0 == ep) {
00210                 DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
00211                 return 0;
00212         }
00213         usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
00214         if (0 == usb_req) {
00215                 DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
00216                 return 0;
00217         }
00218         memset(usb_req, 0, sizeof(*usb_req));
00219         usb_req->dma = DWC_DMA_ADDR_INVALID;
00220 
00221         return usb_req;
00222 }
00223 
00230 static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
00231 {
00232         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
00233 
00234         if (0 == ep || 0 == req) {
00235                 DWC_WARN("%s() %s\n", __func__,
00236                          "Invalid ep or req argument!\n");
00237                 return;
00238         }
00239 
00240         kfree(req);
00241 }
00242 
00243 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00244 
00254 static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
00255                                       dma_addr_t * dma, gfp_t gfp_flags)
00256 {
00257         void *buf;
00258         dwc_otg_pcd_t *pcd = 0;
00259 
00260         pcd = gadget_wrapper->pcd;
00261 
00262         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
00263                     dma, gfp_flags);
00264 
00265         /* Check dword alignment */
00266         if ((bytes & 0x3UL) != 0) {
00267                 DWC_WARN("%s() Buffer size is not a multiple of"
00268                          "DWORD size (%d)", __func__, bytes);
00269         }
00270 
00271         buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
00272 
00273         /* Check dword alignment */
00274         if (((int)buf & 0x3UL) != 0) {
00275                 DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
00276                          __func__, buf);
00277         }
00278 
00279         return buf;
00280 }
00281 
00290 static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
00291                                     dma_addr_t dma, unsigned bytes)
00292 {
00293         dwc_otg_pcd_t *pcd = 0;
00294 
00295         pcd = gadget_wrapper->pcd;
00296 
00297         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
00298 
00299         dma_free_coherent(NULL, bytes, buf, dma);
00300 }
00301 #endif
00302 
00317 static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
00318                     gfp_t gfp_flags)
00319 {
00320         dwc_otg_pcd_t *pcd;
00321         struct dwc_otg_pcd_ep *ep = NULL;
00322         int retval = 0, is_isoc_ep = 0;
00323         dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID;
00324 
00325         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
00326                     __func__, usb_ep, usb_req, gfp_flags);
00327 
00328         if (!usb_req || !usb_req->complete || !usb_req->buf) {
00329                 DWC_WARN("bad params\n");
00330                 return -EINVAL;
00331         }
00332 
00333         if (!usb_ep) {
00334                 DWC_WARN("bad ep\n");
00335                 return -EINVAL;
00336         }
00337 
00338         pcd = gadget_wrapper->pcd;
00339         if (!gadget_wrapper->driver ||
00340             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00341                 DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
00342                             gadget_wrapper->gadget.speed);
00343                 DWC_WARN("bogus device state\n");
00344                 return -ESHUTDOWN;
00345         }
00346 
00347         DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
00348                     usb_ep->name, usb_req, usb_req->length, usb_req->buf);
00349 
00350         usb_req->status = -EINPROGRESS;
00351         usb_req->actual = 0;
00352 
00353         ep = ep_from_handle(pcd, usb_ep);
00354         if (ep == NULL)
00355                 is_isoc_ep = 0;
00356         else
00357                 is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0;
00358 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00359         dma_addr = usb_req->dma;
00360 #else
00361         if (GET_CORE_IF(pcd)->dma_enable) {
00362                 struct pci_dev *dev = gadget_wrapper->pcd->otg_dev->os_dep.pcidev;
00363                 if (usb_req->length != 0 && usb_req->dma == DWC_DMA_ADDR_INVALID) {
00364                         dma_addr = pci_map_single(dev, usb_req->buf, usb_req->length, 
00365                                         ep->dwc_ep.is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
00366                 }
00367         }
00368 #endif
00369 
00370 #ifdef DWC_UTE_PER_IO
00371         if (is_isoc_ep == 1) {
00372                 retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
00373                         usb_req->length, usb_req->zero, usb_req,
00374                         gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req);
00375                 if (retval)
00376                         return -EINVAL;
00377 
00378                 return 0;
00379         }
00380 #endif
00381         retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr,
00382                                       usb_req->length, usb_req->zero, usb_req,
00383                                       gfp_flags == GFP_ATOMIC ? 1 : 0);
00384         if (retval) {
00385                 return -EINVAL;
00386         }
00387 
00388         return 0;
00389 }
00390 
00394 static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
00395 {
00396         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
00397 
00398         if (!usb_ep || !usb_req) {
00399                 DWC_WARN("bad argument\n");
00400                 return -EINVAL;
00401         }
00402         if (!gadget_wrapper->driver ||
00403             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00404                 DWC_WARN("bogus device state\n");
00405                 return -ESHUTDOWN;
00406         }
00407         if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
00408                 return -EINVAL;
00409         }
00410 
00411         return 0;
00412 }
00413 
00430 static int ep_halt(struct usb_ep *usb_ep, int value)
00431 {
00432         int retval = 0;
00433 
00434         DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
00435 
00436         if (!usb_ep) {
00437                 DWC_WARN("bad ep\n");
00438                 return -EINVAL;
00439         }
00440 
00441         retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
00442         if (retval == -DWC_E_AGAIN) {
00443                 return -EAGAIN;
00444         } else if (retval) {
00445                 retval = -EINVAL;
00446         }
00447 
00448         return retval;
00449 }
00450 
00451 #ifdef DWC_EN_ISOC
00452 
00461 static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
00462                         gfp_t gfp_flags)
00463 {
00464         int retval = 0;
00465 
00466         if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
00467                 DWC_WARN("bad params\n");
00468                 return -EINVAL;
00469         }
00470 
00471         if (!usb_ep) {
00472                 DWC_PRINTF("bad params\n");
00473                 return -EINVAL;
00474         }
00475 
00476         req->status = -EINPROGRESS;
00477 
00478         retval =
00479             dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
00480                                      req->buf1, req->dma0, req->dma1,
00481                                      req->sync_frame, req->data_pattern_frame,
00482                                      req->data_per_frame,
00483                                      req->flags & USB_REQ_ISO_ASAP ? -1 : req->
00484                                      start_frame, req->buf_proc_intrvl, req,
00485                                      gfp_flags == GFP_ATOMIC ? 1 : 0);
00486 
00487         if (retval) {
00488                 return -EINVAL;
00489         }
00490 
00491         return retval;
00492 }
00493 
00497 static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
00498 {
00499         int retval = 0;
00500         if (!usb_ep) {
00501                 DWC_WARN("bad ep\n");
00502         }
00503 
00504         if (!gadget_wrapper->driver ||
00505             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00506                 DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
00507                             gadget_wrapper->gadget.speed);
00508                 DWC_WARN("bogus device state\n");
00509         }
00510 
00511         dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
00512         if (retval) {
00513                 retval = -EINVAL;
00514         }
00515 
00516         return retval;
00517 }
00518 
00519 static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
00520                                                  int packets, gfp_t gfp_flags)
00521 {
00522         struct usb_iso_request *pReq = NULL;
00523         uint32_t req_size;
00524 
00525         req_size = sizeof(struct usb_iso_request);
00526         req_size +=
00527             (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
00528 
00529         pReq = kmalloc(req_size, gfp_flags);
00530         if (!pReq) {
00531                 DWC_WARN("Can't allocate Iso Request\n");
00532                 return 0;
00533         }
00534         pReq->iso_packet_desc0 = (void *)(pReq + 1);
00535 
00536         pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
00537 
00538         return pReq;
00539 }
00540 
00541 static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
00542 {
00543         kfree(req);
00544 }
00545 
00546 static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
00547         .ep_ops = {
00548                    .enable = ep_enable,
00549                    .disable = ep_disable,
00550 
00551                    .alloc_request = dwc_otg_pcd_alloc_request,
00552                    .free_request = dwc_otg_pcd_free_request,
00553 
00554 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00555                    .alloc_buffer = dwc_otg_pcd_alloc_buffer,
00556                    .free_buffer = dwc_otg_pcd_free_buffer,
00557 #endif
00558 
00559                    .queue = ep_queue,
00560                    .dequeue = ep_dequeue,
00561 
00562                    .set_halt = ep_halt,
00563                    .fifo_status = 0,
00564                    .fifo_flush = 0,
00565                    },
00566         .iso_ep_start = iso_ep_start,
00567         .iso_ep_stop = iso_ep_stop,
00568         .alloc_iso_request = alloc_iso_request,
00569         .free_iso_request = free_iso_request,
00570 };
00571 
00572 #else
00573 
00574 static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
00575         .enable = ep_enable,
00576         .disable = ep_disable,
00577 
00578         .alloc_request = dwc_otg_pcd_alloc_request,
00579         .free_request = dwc_otg_pcd_free_request,
00580 
00581 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00582         .alloc_buffer = dwc_otg_pcd_alloc_buffer,
00583         .free_buffer = dwc_otg_pcd_free_buffer,
00584 #endif
00585 
00586         .queue = ep_queue,
00587         .dequeue = ep_dequeue,
00588 
00589         .set_halt = ep_halt,
00590         .fifo_status = 0,
00591         .fifo_flush = 0,
00592 
00593 };
00594 
00595 #endif /* _EN_ISOC_ */
00596 /*      Gadget Operations */
00615 static int get_frame_number(struct usb_gadget *gadget)
00616 {
00617         struct gadget_wrapper *d;
00618 
00619         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
00620 
00621         if (gadget == 0) {
00622                 return -ENODEV;
00623         }
00624 
00625         d = container_of(gadget, struct gadget_wrapper, gadget);
00626         return dwc_otg_pcd_get_frame_number(d->pcd);
00627 }
00628 
00629 #ifdef CONFIG_USB_DWC_OTG_LPM
00630 static int test_lpm_enabled(struct usb_gadget *gadget)
00631 {
00632         struct gadget_wrapper *d;
00633 
00634         d = container_of(gadget, struct gadget_wrapper, gadget);
00635 
00636         return dwc_otg_pcd_is_lpm_enabled(d->pcd);
00637 }
00638 #endif
00639 
00646 static int wakeup(struct usb_gadget *gadget)
00647 {
00648         struct gadget_wrapper *d;
00649 
00650         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
00651 
00652         if (gadget == 0) {
00653                 return -ENODEV;
00654         } else {
00655                 d = container_of(gadget, struct gadget_wrapper, gadget);
00656         }
00657         dwc_otg_pcd_wakeup(d->pcd);
00658         return 0;
00659 }
00660 
00661 static const struct usb_gadget_ops dwc_otg_pcd_ops = {
00662         .get_frame = get_frame_number,
00663         .wakeup = wakeup,
00664 #ifdef CONFIG_USB_DWC_OTG_LPM
00665         .lpm_support = test_lpm_enabled,
00666 #endif
00667         // current versions must always be self-powered
00668 };
00669 
00670 static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
00671 {
00672         int retval = -DWC_E_NOT_SUPPORTED;
00673         if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
00674                 retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
00675                                                        (struct usb_ctrlrequest
00676                                                         *)bytes);
00677         }
00678 
00679         if (retval == -ENOTSUPP) {
00680                 retval = -DWC_E_NOT_SUPPORTED;
00681         } else if (retval < 0) {
00682                 retval = -DWC_E_INVALID;
00683         }
00684 
00685         return retval;
00686 }
00687 
00688 #ifdef DWC_EN_ISOC
00689 static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
00690                           void *req_handle, int proc_buf_num)
00691 {
00692         int i, packet_count;
00693         struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
00694         struct usb_iso_request *iso_req = req_handle;
00695 
00696         if (proc_buf_num) {
00697                 iso_packet = iso_req->iso_packet_desc1;
00698         } else {
00699                 iso_packet = iso_req->iso_packet_desc0;
00700         }
00701         packet_count =
00702             dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
00703         for (i = 0; i < packet_count; ++i) {
00704                 int status;
00705                 int actual;
00706                 int offset;
00707                 dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
00708                                                   i, &status, &actual, &offset);
00709                 switch (status) {
00710                 case -DWC_E_NO_DATA:
00711                         status = -ENODATA;
00712                         break;
00713                 default:
00714                         if (status) {
00715                                 DWC_PRINTF("unknown status in isoc packet\n");
00716                         }
00717 
00718                 }
00719                 iso_packet[i].status = status;
00720                 iso_packet[i].offset = offset;
00721                 iso_packet[i].actual_length = actual;
00722         }
00723 
00724         iso_req->status = 0;
00725         iso_req->process_buffer(ep_handle, iso_req);
00726 
00727         return 0;
00728 }
00729 #endif /* DWC_EN_ISOC */
00730 
00731 #ifdef DWC_UTE_PER_IO
00732 
00744 static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
00745                            void *req_handle, int32_t status, void *ereq_port)
00746 {
00747         struct dwc_ute_iso_req_ext *ereqorg = NULL;
00748         struct dwc_iso_xreq_port *ereqport = NULL;
00749         struct dwc_ute_iso_packet_descriptor *desc_org = NULL;
00750         int i;
00751         struct usb_request *req;
00752         //struct dwc_ute_iso_packet_descriptor *
00753         //int status = 0;
00754 
00755         req = (struct usb_request *)req_handle;
00756         ereqorg = &req->ext_req;
00757         ereqport = (struct dwc_iso_xreq_port *)ereq_port;
00758         desc_org = ereqorg->per_io_frame_descs;
00759 
00760         if (req && req->complete) {
00761                 /* Copy the request data from the portable logic to our request */
00762                 for (i = 0; i < ereqport->pio_pkt_count; i++) {
00763                         desc_org[i].actual_length =
00764                             ereqport->per_io_frame_descs[i].actual_length;
00765                         desc_org[i].status =
00766                             ereqport->per_io_frame_descs[i].status;
00767                 }
00768 
00769                 switch (status) {
00770                 case -DWC_E_SHUTDOWN:
00771                         req->status = -ESHUTDOWN;
00772                         break;
00773                 case -DWC_E_RESTART:
00774                         req->status = -ECONNRESET;
00775                         break;
00776                 case -DWC_E_INVALID:
00777                         req->status = -EINVAL;
00778                         break;
00779                 case -DWC_E_TIMEOUT:
00780                         req->status = -ETIMEDOUT;
00781                         break;
00782                 default:
00783                         req->status = status;
00784                 }
00785 
00786                 /* And call the gadget's completion */
00787                 req->complete(ep_handle, req);
00788         }
00789 
00790         return 0;
00791 }
00792 #endif /* DWC_UTE_PER_IO */
00793 static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
00794                      void *req_handle, int32_t status, uint32_t actual)
00795 {
00796         struct usb_request *req = (struct usb_request *)req_handle;
00797 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
00798         struct dwc_otg_pcd_ep *ep = NULL;
00799 #endif
00800 #ifdef PCI_INTERFACE
00801         struct pci_dev *dev = NULL;
00802 #endif
00803 
00804         if (req && req->complete) {
00805                 switch (status) {
00806                 case -DWC_E_SHUTDOWN:
00807                         req->status = -ESHUTDOWN;
00808                         break;
00809                 case -DWC_E_RESTART:
00810                         req->status = -ECONNRESET;
00811                         break;
00812                 case -DWC_E_INVALID:
00813                         req->status = -EINVAL;
00814                         break;
00815                 case -DWC_E_TIMEOUT:
00816                         req->status = -ETIMEDOUT;
00817                         break;
00818                 default:
00819                         req->status = status;
00820 
00821                 }
00822 
00823                 req->actual = actual;
00824                 DWC_SPINUNLOCK(pcd->lock);
00825                 req->complete(ep_handle, req);
00826                 DWC_SPINLOCK(pcd->lock);
00827         }
00828 #ifdef PCI_INTERFACE
00829         dev = gadget_wrapper->pcd->otg_dev->os_dep.pcidev;
00830         ep = ep_from_handle(pcd, ep_handle);
00831         if (GET_CORE_IF(pcd)->dma_enable) {
00832                 if (req->length != 0)
00833                         pci_unmap_single(dev, req->dma, req->length,
00834                                          ep->dwc_ep.
00835                                          is_in ? PCI_DMA_TODEVICE :
00836                                          PCI_DMA_FROMDEVICE);
00837         }
00838 #endif
00839 
00840         return 0;
00841 }
00842 
00843 static int _connect(dwc_otg_pcd_t * pcd, int speed)
00844 {
00845         gadget_wrapper->gadget.speed = speed;
00846         return 0;
00847 }
00848 
00849 static int _disconnect(dwc_otg_pcd_t * pcd)
00850 {
00851         if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
00852                 gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
00853         }
00854         return 0;
00855 }
00856 
00857 static int _resume(dwc_otg_pcd_t * pcd)
00858 {
00859         if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
00860                 gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
00861         }
00862 
00863         return 0;
00864 }
00865 
00866 static int _suspend(dwc_otg_pcd_t * pcd)
00867 {
00868         if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
00869                 gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
00870         }
00871         return 0;
00872 }
00873 
00877 static int _hnp_changed(dwc_otg_pcd_t * pcd)
00878 {
00879 
00880         if (!gadget_wrapper->gadget.is_otg)
00881                 return 0;
00882 
00883         gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
00884         gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
00885         gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
00886         return 0;
00887 }
00888 
00889 static int _reset(dwc_otg_pcd_t * pcd)
00890 {
00891         return 0;
00892 }
00893 
00894 #ifdef DWC_UTE_CFI
00895 static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
00896 {
00897         int retval = -DWC_E_INVALID;
00898         if (gadget_wrapper->driver->cfi_feature_setup) {
00899                 retval =
00900                     gadget_wrapper->driver->
00901                     cfi_feature_setup(&gadget_wrapper->gadget,
00902                                       (struct cfi_usb_ctrlrequest *)cfi_req);
00903         }
00904 
00905         return retval;
00906 }
00907 #endif
00908 
00909 static const struct dwc_otg_pcd_function_ops fops = {
00910         .complete = _complete,
00911 #ifdef DWC_EN_ISOC
00912         .isoc_complete = _isoc_complete,
00913 #endif
00914         .setup = _setup,
00915         .disconnect = _disconnect,
00916         .connect = _connect,
00917         .resume = _resume,
00918         .suspend = _suspend,
00919         .hnp_changed = _hnp_changed,
00920         .reset = _reset,
00921 #ifdef DWC_UTE_CFI
00922         .cfi_setup = _cfi_setup,
00923 #endif
00924 #ifdef DWC_UTE_PER_IO
00925         .xisoc_complete = _xisoc_complete,
00926 #endif
00927 };
00928 
00932 static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
00933 {
00934         dwc_otg_pcd_t *pcd = dev;
00935         int32_t retval = IRQ_NONE;
00936 
00937         retval = dwc_otg_pcd_handle_intr(pcd);
00938         if (retval != 0) {
00939                 S3C2410X_CLEAR_EINTPEND();
00940         }
00941         return IRQ_RETVAL(retval);
00942 }
00943 
00950 void gadget_add_eps(struct gadget_wrapper *d)
00951 {
00952         static const char *names[] = {
00953 
00954                 "ep0",
00955                 "ep1in",
00956                 "ep2in",
00957                 "ep3in",
00958                 "ep4in",
00959                 "ep5in",
00960                 "ep6in",
00961                 "ep7in",
00962                 "ep8in",
00963                 "ep9in",
00964                 "ep10in",
00965                 "ep11in",
00966                 "ep12in",
00967                 "ep13in",
00968                 "ep14in",
00969                 "ep15in",
00970                 "ep1out",
00971                 "ep2out",
00972                 "ep3out",
00973                 "ep4out",
00974                 "ep5out",
00975                 "ep6out",
00976                 "ep7out",
00977                 "ep8out",
00978                 "ep9out",
00979                 "ep10out",
00980                 "ep11out",
00981                 "ep12out",
00982                 "ep13out",
00983                 "ep14out",
00984                 "ep15out"
00985         };
00986 
00987         int i;
00988         struct usb_ep *ep;
00989         int8_t dev_endpoints;
00990 
00991         DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
00992 
00993         INIT_LIST_HEAD(&d->gadget.ep_list);
00994         d->gadget.ep0 = &d->ep0;
00995         d->gadget.speed = USB_SPEED_UNKNOWN;
00996 
00997         INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
00998 
01002         ep = &d->ep0;
01003 
01004         /* Init the usb_ep structure. */
01005         ep->name = names[0];
01006         ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
01007 
01012         ep->maxpacket = MAX_PACKET_SIZE;
01013         dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
01014 
01015         list_add_tail(&ep->ep_list, &d->gadget.ep_list);
01016 
01020         dev_endpoints = d->pcd->core_if->dev_if->num_in_eps;
01021 
01022         for (i = 0; i < dev_endpoints; i++) {
01023                 ep = &d->in_ep[i];
01024 
01025                 /* Init the usb_ep structure. */
01026                 ep->name = names[d->pcd->in_ep[i].dwc_ep.num];
01027                 ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
01028 
01033                 ep->maxpacket = MAX_PACKET_SIZE;
01034                 list_add_tail(&ep->ep_list, &d->gadget.ep_list);
01035         }
01036 
01037         dev_endpoints = d->pcd->core_if->dev_if->num_out_eps;
01038 
01039         for (i = 0; i < dev_endpoints; i++) {
01040                 ep = &d->out_ep[i];
01041 
01042                 /* Init the usb_ep structure. */
01043                 ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num];
01044                 ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
01045 
01050                 ep->maxpacket = MAX_PACKET_SIZE;
01051 
01052                 list_add_tail(&ep->ep_list, &d->gadget.ep_list);
01053         }
01054 
01055         /* remove ep0 from the list.  There is a ep0 pointer. */
01056         list_del_init(&d->ep0.ep_list);
01057 
01058         d->ep0.maxpacket = MAX_EP0_SIZE;
01059 }
01060 
01067 static void dwc_otg_pcd_gadget_release(struct device *dev)
01068 {
01069         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
01070 }
01071 
01072 static struct gadget_wrapper *alloc_wrapper(
01073 #ifdef LM_INTERFACE
01074         struct lm_device *_dev
01075 #elif  defined(PCI_INTERFACE)
01076         struct pci_dev *_dev
01077 #endif
01078     )
01079 {
01080         static char pcd_name[] = "dwc_otg_pcd";
01081 #ifdef LM_INTERFACE
01082         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
01083 #elif defined(PCI_INTERFACE)
01084         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
01085 #endif
01086 
01087         struct gadget_wrapper *d;
01088         int retval;
01089 
01090         d = DWC_ALLOC(sizeof(*d));
01091         if (d == NULL) {
01092                 return NULL;
01093         }
01094 
01095         memset(d, 0, sizeof(*d));
01096 
01097         d->gadget.name = pcd_name;
01098         d->pcd = otg_dev->pcd;
01099 
01100 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
01101         strcpy(d->gadget.dev.bus_id, "gadget");
01102 #else
01103         dev_set_name(&d->gadget.dev, "%s", "gadget");
01104 #endif
01105 
01106         d->gadget.dev.parent = &_dev->dev;
01107         d->gadget.dev.release = dwc_otg_pcd_gadget_release;
01108         d->gadget.ops = &dwc_otg_pcd_ops;
01109         d->gadget.is_dualspeed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd);
01110         d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
01111 
01112         d->driver = 0;
01113         /* Register the gadget device */
01114         retval = device_register(&d->gadget.dev);
01115         if (retval != 0) {
01116                 DWC_ERROR("device_register failed\n");
01117                 DWC_FREE(d);
01118                 return NULL;
01119         }
01120 
01121         return d;
01122 }
01123 
01124 static void free_wrapper(struct gadget_wrapper *d)
01125 {
01126         if (d->driver) {
01127                 /* should have been done already by driver model core */
01128                 DWC_WARN("driver '%s' is still registered\n",
01129                          d->driver->driver.name);
01130                 usb_gadget_unregister_driver(d->driver);
01131         }
01132 
01133         device_unregister(&d->gadget.dev);
01134         DWC_FREE(d);
01135 }
01136 
01141 int pcd_init(
01142 #ifdef LM_INTERFACE
01143         struct lm_device *_dev
01144 #elif  defined(PCI_INTERFACE)
01145         struct pci_dev *_dev
01146 #endif
01147     )
01148 {
01149 #ifdef LM_INTERFACE
01150         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
01151 #elif  defined(PCI_INTERFACE)
01152         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
01153 #endif
01154 
01155         int retval = 0;
01156 
01157         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
01158 
01159         otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
01160 
01161         if (!otg_dev->pcd) {
01162                 DWC_ERROR("dwc_otg_pcd_init failed\n");
01163                 return -ENOMEM;
01164         }
01165 
01166         otg_dev->pcd->otg_dev = otg_dev;
01167         gadget_wrapper = alloc_wrapper(_dev);
01168 
01169         /*
01170          * Initialize EP structures
01171          */
01172         gadget_add_eps(gadget_wrapper);
01173         /*
01174          * Setup interupt handler
01175          */
01176         DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _dev->irq);
01177         retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
01178                              IRQF_SHARED | IRQF_DISABLED,
01179                              gadget_wrapper->gadget.name, otg_dev->pcd);
01180         if (retval != 0) {
01181                 DWC_ERROR("request of irq%d failed\n", _dev->irq);
01182                 free_wrapper(gadget_wrapper);
01183                 return -EBUSY;
01184         }
01185 
01186         dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
01187 
01188         return retval;
01189 }
01190 
01194 void pcd_remove(
01195 #ifdef LM_INTERFACE
01196         struct lm_device *_dev
01197 #elif  defined(PCI_INTERFACE)
01198         struct pci_dev *_dev
01199 #endif
01200     )
01201 {
01202 #ifdef LM_INTERFACE
01203         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
01204 #elif  defined(PCI_INTERFACE)
01205         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
01206 #endif
01207         dwc_otg_pcd_t *pcd = otg_dev->pcd;
01208 
01209         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
01210 
01211         /*
01212          * Free the IRQ
01213          */
01214         free_irq(_dev->irq, pcd);
01215         dwc_otg_pcd_remove(otg_dev->pcd);
01216         free_wrapper(gadget_wrapper);
01217         otg_dev->pcd = 0;
01218 }
01219 
01231 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
01232 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
01233 #else
01234 int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
01235                 int (*bind)(struct usb_gadget *))
01236 #endif
01237 {
01238         int retval;
01239 
01240         DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
01241                     driver->driver.name);
01242 
01243         if (!driver || driver->speed == USB_SPEED_UNKNOWN ||
01244 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
01245             !driver->bind ||
01246 #else
01247                 !bind ||
01248 #endif
01249             !driver->unbind || !driver->disconnect || !driver->setup) {
01250                 DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
01251                 return -EINVAL;
01252         }
01253         if (gadget_wrapper == 0) {
01254                 DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
01255                 return -ENODEV;
01256         }
01257         if (gadget_wrapper->driver != 0) {
01258                 DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
01259                 return -EBUSY;
01260         }
01261 
01262         /* hook up the driver */
01263         gadget_wrapper->driver = driver;
01264         gadget_wrapper->gadget.dev.driver = &driver->driver;
01265 
01266         DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
01267 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
01268         retval = driver->bind(&gadget_wrapper->gadget);
01269 #else
01270         retval = bind(&gadget_wrapper->gadget);
01271 #endif
01272         if (retval) {
01273                 DWC_ERROR("bind to driver %s --> error %d\n",
01274                           driver->driver.name, retval);
01275                 gadget_wrapper->driver = 0;
01276                 gadget_wrapper->gadget.dev.driver = 0;
01277                 return retval;
01278         }
01279         DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
01280                     driver->driver.name);
01281         return 0;
01282 }
01283 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
01284 EXPORT_SYMBOL(usb_gadget_register_driver);
01285 #else
01286 EXPORT_SYMBOL(usb_gadget_probe_driver);
01287 #endif
01288 
01294 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
01295 {
01296         //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
01297 
01298         if (gadget_wrapper == 0) {
01299                 DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
01300                             -ENODEV);
01301                 return -ENODEV;
01302         }
01303         if (driver == 0 || driver != gadget_wrapper->driver) {
01304                 DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
01305                             -EINVAL);
01306                 return -EINVAL;
01307         }
01308 
01309         driver->unbind(&gadget_wrapper->gadget);
01310         gadget_wrapper->driver = 0;
01311 
01312         DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
01313         return 0;
01314 }
01315 
01316 EXPORT_SYMBOL(usb_gadget_unregister_driver);
01317 
01318 #endif /* DWC_HOST_ONLY */

Generated on Thu Oct 27 03:56:38 2011 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.3.9.1