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: #7 $
00004   * $Date: 2009/04/03 $
00005   * $Change: 1225160 $
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 <linux/kernel.h>
00057 #include <linux/module.h>
00058 #include <linux/moduleparam.h>
00059 #include <linux/init.h>
00060 #include <linux/device.h>
00061 #include <linux/errno.h>
00062 #include <linux/list.h>
00063 #include <linux/interrupt.h>
00064 #include <linux/string.h>
00065 #include <linux/dma-mapping.h>
00066 #include <linux/version.h>
00067 
00068 #ifdef LM_INTERFACE
00069 # include <asm/arch/regs-irq.h>
00070 # include <asm/arch/lm.h>
00071 # include <asm/arch/irqs.h>
00072 #endif
00073 
00074 #include <asm/io.h>
00075 # include <linux/usb_ch9.h>
00076 #include <linux/usb_gadget.h>
00077 
00078 #include "dwc_otg_pcd_if.h"
00079 #include "dwc_otg_driver.h"
00080 #include "dwc_otg_dbg.h"
00081 
00082 static struct gadget_wrapper {
00083         dwc_otg_pcd_t *pcd;
00084 
00085         struct usb_gadget gadget;
00086         struct usb_gadget_driver *driver;
00087 
00088         struct usb_ep ep0;
00089         struct usb_ep in_ep[16];
00090         struct usb_ep out_ep[16];
00091 
00092 } *gadget_wrapper;
00093 
00094 /* Display the contents of the buffer */
00095 extern void dump_msg(const u8 * buf, unsigned int length);
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         retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
00150                                        (const uint8_t *)ep_desc,
00151                                        (void *)usb_ep);
00152         if (retval) {
00153                 DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
00154                 return -EINVAL;
00155         }
00156 
00157         usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
00158 
00159         return 0;
00160 }
00161 
00170 static int ep_disable(struct usb_ep *usb_ep)
00171 {
00172         int retval;
00173 
00174         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
00175         if (!usb_ep) {
00176                 DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
00177                             usb_ep ? usb_ep->name : NULL);
00178                 return -EINVAL;
00179         }
00180 
00181         retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
00182         if (retval) {
00183                 retval = -EINVAL;
00184         }
00185 
00186         return retval;
00187 }
00188 
00196 static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
00197                                                      gfp_t gfp_flags)
00198 {
00199         struct usb_request *usb_req;
00200 
00201         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
00202         if (0 == ep) {
00203                 DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
00204                 return 0;
00205         }
00206         usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
00207         if (0 == usb_req) {
00208                 DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
00209                 return 0;
00210         }
00211         memset(usb_req, 0, sizeof(*usb_req));
00212         usb_req->dma = DWC_INVALID_DMA_ADDR;
00213 
00214         return usb_req;
00215 }
00216 
00223 static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
00224 {
00225         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
00226 
00227         if (0 == ep || 0 == req) {
00228                 DWC_WARN("%s() %s\n", __func__,
00229                          "Invalid ep or req argument!\n");
00230                 return;
00231         }
00232 
00233         kfree(req);
00234 }
00235 
00246 static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
00247                                       dma_addr_t * dma, gfp_t gfp_flags)
00248 {
00249         void *buf;
00250         dwc_otg_pcd_t *pcd = 0;
00251 
00252         pcd = gadget_wrapper->pcd;
00253 
00254         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
00255                     dma, gfp_flags);
00256 
00257         /* Check dword alignment */
00258         if ((bytes & 0x3UL) != 0) {
00259                 DWC_WARN("%s() Buffer size is not a multiple of"
00260                          "DWORD size (%d)", __func__, bytes);
00261         }
00262 
00263         buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
00264 
00265         /* Check dword alignment */
00266         if (((int)buf & 0x3UL) != 0) {
00267                 DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
00268                          __func__, buf);
00269         }
00270 
00271         return buf;
00272 }
00273 
00282 static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
00283                                     dma_addr_t dma, unsigned bytes)
00284 {
00285         dwc_otg_pcd_t *pcd = 0;
00286 
00287         pcd = gadget_wrapper->pcd;
00288 
00289         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
00290 
00291         dma_free_coherent(NULL, bytes, buf, dma);
00292 }
00293 
00308 static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
00309                     gfp_t gfp_flags)
00310 {
00311         dwc_otg_pcd_t *pcd;
00312         int retval;
00313 
00314         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
00315                     __func__, usb_ep, usb_req, gfp_flags);
00316 
00317         if (!usb_req || !usb_req->complete || !usb_req->buf) {
00318                 DWC_WARN("bad params\n");
00319                 return -EINVAL;
00320         }
00321 
00322         if (!usb_ep) {
00323                 DWC_WARN("bad ep\n");
00324                 return -EINVAL;
00325         }
00326 
00327         pcd = gadget_wrapper->pcd;
00328         if (!gadget_wrapper->driver ||
00329             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00330                 DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
00331                             gadget_wrapper->gadget.speed);
00332                 DWC_WARN("bogus device state\n");
00333                 return -ESHUTDOWN;
00334         }
00335 
00336         DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
00337                     usb_ep->name, usb_req, usb_req->length, usb_req->buf);
00338 
00339         usb_req->status = -EINPROGRESS;
00340         usb_req->actual = 0;
00341 
00342         retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma,
00343                                       usb_req->length, usb_req->zero, usb_req,
00344                                       gfp_flags == GFP_ATOMIC ? 1 : 0);
00345         if (retval) {
00346                 return -EINVAL;
00347         }
00348 
00349         return 0;
00350 }
00351 
00355 static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
00356 {
00357         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
00358 
00359         if (!usb_ep || !usb_req) {
00360                 DWC_WARN("bad argument\n");
00361                 return -EINVAL;
00362         }
00363         if (!gadget_wrapper->driver ||
00364             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00365                 DWC_WARN("bogus device state\n");
00366                 return -ESHUTDOWN;
00367         }
00368         if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
00369                 return -EINVAL;
00370         }
00371 
00372         return 0;
00373 }
00374 
00391 static int ep_halt(struct usb_ep *usb_ep, int value)
00392 {
00393         int retval = 0;
00394 
00395         DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
00396 
00397         if (!usb_ep) {
00398                 DWC_WARN("bad ep\n");
00399                 return -EINVAL;
00400         }
00401 
00402         retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
00403         if (retval == -DWC_E_AGAIN) {
00404                 return -EAGAIN;
00405         } else if (retval) {
00406                 retval = -EINVAL;
00407         }
00408 
00409         return retval;
00410 }
00411 
00412 #ifdef DWC_EN_ISOC
00413 
00422 static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
00423                         gfp_t gfp_flags)
00424 {
00425         int retval = 0;
00426 
00427         if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
00428                 DWC_WARN("bad params\n");
00429                 return -EINVAL;
00430         }
00431 
00432         if (!usb_ep) {
00433                 DWC_PRINTF("bad params\n");
00434                 return -EINVAL;
00435         }
00436 
00437         req->status = -EINPROGRESS;
00438 
00439         retval =
00440             dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
00441                                      req->buf1, req->dma0, req->dma1,
00442                                      req->sync_frame, req->data_pattern_frame,
00443                                      req->data_per_frame,
00444                                      req->flags & USB_REQ_ISO_ASAP ? -1 : req->
00445                                      start_frame, req->buf_proc_intrvl, req,
00446                                      gfp_flags == GFP_ATOMIC ? 1 : 0);
00447 
00448         if (retval) {
00449                 return -EINVAL;
00450         }
00451 
00452         return retval;
00453 }
00454 
00458 static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
00459 {
00460         int retval = 0;
00461         if (!usb_ep) {
00462                 DWC_WARN("bad ep\n");
00463         }
00464 
00465         if (!gadget_wrapper->driver ||
00466             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
00467                 DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
00468                             gadget_wrapper->gadget.speed);
00469                 DWC_WARN("bogus device state\n");
00470         }
00471 
00472         dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
00473         if (retval) {
00474                 retval = -EINVAL;
00475         }
00476 
00477         return retval;
00478 }
00479 
00480 static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
00481                                                  int packets, gfp_t gfp_flags)
00482 {
00483         struct usb_iso_request *pReq = NULL;
00484         uint32_t req_size;
00485 
00486         req_size = sizeof(struct usb_iso_request);
00487         req_size +=
00488             (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
00489 
00490         pReq = kmalloc(req_size, gfp_flags);
00491         if (!pReq) {
00492                 DWC_WARN("Can't allocate Iso Request\n");
00493                 return 0;
00494         }
00495         pReq->iso_packet_desc0 = (void *)(pReq + 1);
00496 
00497         pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
00498 
00499         return pReq;
00500 }
00501 
00502 static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
00503 {
00504         kfree(req);
00505 }
00506 
00507 static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
00508         .ep_ops = {
00509                    .enable = ep_enable,
00510                    .disable = ep_disable,
00511 
00512                    .alloc_request = dwc_otg_pcd_alloc_request,
00513                    .free_request = dwc_otg_pcd_free_request,
00514 
00515                    .alloc_buffer = dwc_otg_pcd_alloc_buffer,
00516                    .free_buffer = dwc_otg_pcd_free_buffer,
00517 
00518                    .queue = ep_queue,
00519                    .dequeue = ep_dequeue,
00520 
00521                    .set_halt = ep_halt,
00522                    .fifo_status = 0,
00523                    .fifo_flush = 0,
00524                    },
00525         .iso_ep_start = iso_ep_start,
00526         .iso_ep_stop = iso_ep_stop,
00527         .alloc_iso_request = alloc_iso_request,
00528         .free_iso_request = free_iso_request,
00529 };
00530 
00531 #else
00532 
00533 static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
00534         .enable = ep_enable,
00535         .disable = ep_disable,
00536 
00537         .alloc_request = dwc_otg_pcd_alloc_request,
00538         .free_request = dwc_otg_pcd_free_request,
00539 
00540         .alloc_buffer = dwc_otg_pcd_alloc_buffer,
00541         .free_buffer = dwc_otg_pcd_free_buffer,
00542 
00543         .queue = ep_queue,
00544         .dequeue = ep_dequeue,
00545 
00546         .set_halt = ep_halt,
00547         .fifo_status = 0,
00548         .fifo_flush = 0,
00549 
00550 };
00551 
00552 #endif                          /* _EN_ISOC_ */
00553 /*      Gadget Operations */
00572 static int get_frame_number(struct usb_gadget *gadget)
00573 {
00574         struct gadget_wrapper *d;
00575 
00576         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
00577 
00578         if (gadget == 0) {
00579                 return -ENODEV;
00580         }
00581 
00582         d = container_of(gadget, struct gadget_wrapper, gadget);
00583         return dwc_otg_pcd_get_frame_number(d->pcd);
00584 }
00585 
00586 #ifdef CONFIG_USB_DWC_OTG_LPM
00587 static int test_lpm_enabled(struct usb_gadget *gadget)
00588 {
00589         struct gadget_wrapper *d;
00590 
00591         d = container_of(gadget, struct gadget_wrapper, gadget);
00592 
00593         return dwc_otg_pcd_is_lpm_enabled(d->pcd);
00594 }
00595 #endif
00596 
00603 static int wakeup(struct usb_gadget *gadget)
00604 {
00605         struct gadget_wrapper *d;
00606 
00607         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
00608 
00609         if (gadget == 0) {
00610                 return -ENODEV;
00611         } else {
00612                 d = container_of(gadget, struct gadget_wrapper, gadget);
00613         }
00614         dwc_otg_pcd_wakeup(d->pcd);
00615         return 0;
00616 }
00617 
00618 static const struct usb_gadget_ops dwc_otg_pcd_ops = {
00619         .get_frame = get_frame_number,
00620         .wakeup = wakeup,
00621 #ifdef CONFIG_USB_DWC_OTG_LPM
00622         .lpm_support = test_lpm_enabled,
00623 #endif
00624         // current versions must always be self-powered
00625 };
00626 
00627 static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
00628 {
00629         int retval = -DWC_E_NOT_SUPPORTED;
00630         if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
00631                 retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
00632                                                        (struct usb_ctrlrequest
00633                                                         *)bytes);
00634         }
00635 
00636         if (retval == -ENOTSUPP) {
00637                 retval = -DWC_E_NOT_SUPPORTED;
00638         } else if (retval < 0) {
00639                 retval = -DWC_E_INVALID;
00640         }
00641 
00642         return retval;
00643 }
00644 
00645 #ifdef DWC_EN_ISOC
00646 static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
00647                           void *req_handle, int proc_buf_num)
00648 {
00649         int i, packet_count;
00650         struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
00651         struct usb_iso_request *iso_req = req_handle;
00652 
00653         if (proc_buf_num) {
00654                 iso_packet = iso_req->iso_packet_desc1;
00655         } else {
00656                 iso_packet = iso_req->iso_packet_desc0;
00657         }
00658         packet_count =
00659             dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
00660         for (i = 0; i < packet_count; ++i) {
00661                 int status;
00662                 int actual;
00663                 int offset;
00664                 dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
00665                                                   i, &status, &actual, &offset);
00666                 switch (status) {
00667                 case -DWC_E_NO_DATA:
00668                         status = -ENODATA;
00669                         break;
00670                 default:
00671                         if (status) {
00672                                 DWC_PRINTF("unknown status in isoc packet\n");
00673                         }
00674 
00675                 }
00676                 iso_packet[i].status = status;
00677                 iso_packet[i].offset = offset;
00678                 iso_packet[i].actual_length = actual;
00679         }
00680 
00681         iso_req->status = 0;
00682         iso_req->process_buffer(ep_handle, iso_req);
00683 
00684         return 0;
00685 }
00686 #endif                          /* DWC_EN_ISOC */
00687 
00688 static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
00689                      void *req_handle, int32_t status, uint32_t actual)
00690 {
00691         struct usb_request *req = (struct usb_request *)req_handle;
00692 
00693         if (req && req->complete) {
00694                 switch (status) {
00695                 case -DWC_E_SHUTDOWN:
00696                         req->status = -ESHUTDOWN;
00697                         break;
00698                 case -DWC_E_RESTART:
00699                         req->status = -ECONNRESET;
00700                         break;
00701                 case -DWC_E_INVALID:
00702                         req->status = -EINVAL;
00703                         break;
00704                 case -DWC_E_TIMEOUT:
00705                         req->status = -ETIMEDOUT;
00706                         break;
00707                 default:
00708                         req->status = status;
00709 
00710                 }
00711                 req->actual = actual;
00712                 req->complete(ep_handle, req);
00713         }
00714 
00715         return 0;
00716 }
00717 
00718 static int _connect(dwc_otg_pcd_t * pcd, int speed)
00719 {
00720         gadget_wrapper->gadget.speed = speed;
00721         return 0;
00722 }
00723 
00724 static int _disconnect(dwc_otg_pcd_t * pcd)
00725 {
00726         if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
00727                 gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
00728         }
00729         return 0;
00730 }
00731 
00732 static int _resume(dwc_otg_pcd_t * pcd)
00733 {
00734         if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
00735                 gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
00736         }
00737 
00738         return 0;
00739 }
00740 
00741 static int _suspend(dwc_otg_pcd_t * pcd)
00742 {
00743         if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
00744                 gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
00745         }
00746         return 0;
00747 }
00748 
00752 static int _hnp_changed(dwc_otg_pcd_t * pcd)
00753 {
00754 
00755         if (!gadget_wrapper->gadget.is_otg)
00756                 return 0;
00757 
00758         gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
00759         gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
00760         gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
00761         return 0;
00762 }
00763 
00764 static int _reset(dwc_otg_pcd_t * pcd)
00765 {
00766         return 0;
00767 }
00768 
00769 #ifdef DWC_UTE_CFI
00770 static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
00771 {
00772         int retval = -DWC_E_INVALID;
00773         if (gadget_wrapper->driver->cfi_feature_setup) {
00774                 retval =
00775                     gadget_wrapper->driver->cfi_feature_setup(&gadget_wrapper->
00776                                                               gadget,
00777                                                               (struct
00778                                                                cfi_usb_ctrlrequest
00779                                                                *)cfi_req);
00780         }
00781 
00782         return retval;
00783 }
00784 #endif
00785 
00786 static const struct dwc_otg_pcd_function_ops fops = {
00787         .complete = _complete,
00788 #ifdef DWC_EN_ISOC
00789         .isoc_complete = _isoc_complete,
00790 #endif
00791         .setup = _setup,
00792         .disconnect = _disconnect,
00793         .connect = _connect,
00794         .resume = _resume,
00795         .suspend = _suspend,
00796         .hnp_changed = _hnp_changed,
00797         .reset = _reset,
00798 #ifdef DWC_UTE_CFI
00799         .cfi_setup = _cfi_setup,
00800 #endif
00801 };
00802 
00806 static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
00807 {
00808         dwc_otg_pcd_t *pcd = dev;
00809         int32_t retval = IRQ_NONE;
00810 
00811         retval = dwc_otg_pcd_handle_intr(pcd);
00812         if (retval != 0) {
00813                 S3C2410X_CLEAR_EINTPEND();
00814         }
00815         return IRQ_RETVAL(retval);
00816 }
00817 
00824 void gadget_add_eps(struct gadget_wrapper *d)
00825 {
00826         static const char *names[] = {
00827 
00828                 "ep0",
00829                 "ep1in",
00830                 "ep2in",
00831                 "ep3in",
00832                 "ep4in",
00833                 "ep5in",
00834                 "ep6in",
00835                 "ep7in",
00836                 "ep8in",
00837                 "ep9in",
00838                 "ep10in",
00839                 "ep11in",
00840                 "ep12in",
00841                 "ep13in",
00842                 "ep14in",
00843                 "ep15in",
00844                 "ep1out",
00845                 "ep2out",
00846                 "ep3out",
00847                 "ep4out",
00848                 "ep5out",
00849                 "ep6out",
00850                 "ep7out",
00851                 "ep8out",
00852                 "ep9out",
00853                 "ep10out",
00854                 "ep11out",
00855                 "ep12out",
00856                 "ep13out",
00857                 "ep14out",
00858                 "ep15out"
00859         };
00860 
00861         int i;
00862         struct usb_ep *ep;
00863 
00864         DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
00865 
00866         INIT_LIST_HEAD(&d->gadget.ep_list);
00867         d->gadget.ep0 = &d->ep0;
00868         d->gadget.speed = USB_SPEED_UNKNOWN;
00869 
00870         INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
00871 
00875         ep = &d->ep0;
00876 
00877         /* Init the usb_ep structure. */
00878         ep->name = names[0];
00879         ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
00880 
00885         ep->maxpacket = MAX_PACKET_SIZE;
00886         dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
00887 
00888         list_add_tail(&ep->ep_list, &d->gadget.ep_list);
00889 
00894         for (i = 0; i < 15; i++) {
00895                 ep = &d->in_ep[i];
00896 
00897                 /* Init the usb_ep structure. */
00898                 ep->name = names[i + 1];
00899                 ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
00900 
00905                 ep->maxpacket = MAX_PACKET_SIZE;
00906                 list_add_tail(&ep->ep_list, &d->gadget.ep_list);
00907         }
00908 
00909         for (i = 0; i < 15; i++) {
00910                 ep = &d->out_ep[i];
00911 
00912                 /* Init the usb_ep structure. */
00913                 ep->name = names[15 + i + 1];
00914                 ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
00915 
00920                 ep->maxpacket = MAX_PACKET_SIZE;
00921 
00922                 list_add_tail(&ep->ep_list, &d->gadget.ep_list);
00923         }
00924 
00925         /* remove ep0 from the list.  There is a ep0 pointer. */
00926         list_del_init(&d->ep0.ep_list);
00927 
00928         d->ep0.maxpacket = MAX_EP0_SIZE;
00929 }
00930 
00937 static void dwc_otg_pcd_gadget_release(struct device *dev)
00938 {
00939         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
00940 }
00941 
00942 static struct gadget_wrapper *alloc_wrapper(
00943 #ifdef LM_INTERFACE
00944         struct lm_device *_dev
00945 #elif  PCI_INTERFACE
00946         struct pci_dev *_dev
00947 #endif
00948         )
00949 {
00950         static char pcd_name[] = "dwc_otg_pcd";
00951 #ifdef LM_INTERFACE
00952         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
00953 #elif PCI_INTERFACE
00954         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
00955 #endif
00956 
00957         struct gadget_wrapper *d;
00958         int retval;
00959 
00960         d = dwc_alloc(sizeof(*d));
00961         if (d == NULL) {
00962                 return NULL;
00963         }
00964 
00965         memset(d, 0, sizeof(*d));
00966 
00967         d->gadget.name = pcd_name;
00968         d->pcd = otg_dev->pcd;
00969         strcpy(d->gadget.dev.bus_id, "gadget");
00970 
00971         d->gadget.dev.parent = &_dev->dev;
00972         d->gadget.dev.release = dwc_otg_pcd_gadget_release;
00973         d->gadget.ops = &dwc_otg_pcd_ops;
00974         d->gadget.is_dualspeed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd);
00975         d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
00976 
00977         d->driver = 0;
00978         /* Register the gadget device */
00979         retval = device_register(&d->gadget.dev);
00980         if (retval != 0) {
00981                 DWC_ERROR("device_register failed\n");
00982                 dwc_free(d);
00983                 return NULL;
00984         }
00985 
00986         return d;
00987 }
00988 
00989 static void free_wrapper(struct gadget_wrapper *d)
00990 {
00991         if (d->driver) {
00992                 /* should have been done already by driver model core */
00993                 DWC_WARN("driver '%s' is still registered\n",
00994                          d->driver->driver.name);
00995                 usb_gadget_unregister_driver(d->driver);
00996         }
00997 
00998         device_unregister(&d->gadget.dev);
00999         dwc_free(d);
01000 }
01001 
01006 int pcd_init(
01007 #ifdef LM_INTERFACE
01008         struct lm_device *_dev
01009 #elif  PCI_INTERFACE
01010         struct pci_dev *_dev
01011 #endif
01012         )
01013 
01014 {
01015 #ifdef LM_INTERFACE
01016         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
01017 #elif  PCI_INTERFACE
01018         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
01019 #endif
01020 
01021         int retval = 0;
01022 
01023         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
01024 
01025         otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
01026 
01027         if (!otg_dev->pcd) {
01028                 DWC_ERROR("dwc_otg_pcd_init failed\n");
01029                 return -ENOMEM;
01030         }
01031 
01032         gadget_wrapper = alloc_wrapper(_dev);
01033 
01034         /*
01035          * Initialize EP structures
01036          */
01037         gadget_add_eps(gadget_wrapper);
01038 
01039         /*
01040          * Setup interupt handler
01041          */
01042         DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _dev->irq);
01043         retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
01044                              SA_SHIRQ, gadget_wrapper->gadget.name,
01045                              otg_dev->pcd);
01046         if (retval != 0) {
01047                 DWC_ERROR("request of irq%d failed\n", _dev->irq);
01048                 free_wrapper(gadget_wrapper);
01049                 return -EBUSY;
01050         }
01051 
01052         dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
01053 
01054         return retval;
01055 }
01056 
01060 void pcd_remove(
01061 #ifdef LM_INTERFACE
01062         struct lm_device *_dev
01063 #elif  PCI_INTERFACE
01064         struct pci_dev *_dev
01065 #endif
01066         )
01067 {
01068 #ifdef LM_INTERFACE
01069         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
01070 #elif  PCI_INTERFACE
01071         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
01072 #endif
01073         dwc_otg_pcd_t *pcd = otg_dev->pcd;
01074 
01075         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
01076 
01077         /*
01078          * Free the IRQ
01079          */
01080         free_irq(_dev->irq, pcd);
01081         dwc_otg_pcd_remove(otg_dev->pcd);
01082         free_wrapper(gadget_wrapper);
01083         otg_dev->pcd = 0;
01084 }
01085 
01096 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
01097 {
01098         int retval;
01099 
01100         DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
01101                     driver->driver.name);
01102 
01103         if (!driver || driver->speed == USB_SPEED_UNKNOWN ||
01104             !driver->bind ||
01105             !driver->unbind || !driver->disconnect || !driver->setup) {
01106                 DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
01107                 return -EINVAL;
01108         }
01109         if (gadget_wrapper == 0) {
01110                 DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
01111                 return -ENODEV;
01112         }
01113         if (gadget_wrapper->driver != 0) {
01114                 DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
01115                 return -EBUSY;
01116         }
01117 
01118         /* hook up the driver */
01119         gadget_wrapper->driver = driver;
01120         gadget_wrapper->gadget.dev.driver = &driver->driver;
01121 
01122         DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
01123         retval = driver->bind(&gadget_wrapper->gadget);
01124         if (retval) {
01125                 DWC_ERROR("bind to driver %s --> error %d\n",
01126                           driver->driver.name, retval);
01127                 gadget_wrapper->driver = 0;
01128                 gadget_wrapper->gadget.dev.driver = 0;
01129                 return retval;
01130         }
01131         DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
01132                     driver->driver.name);
01133         return 0;
01134 }
01135 
01136 EXPORT_SYMBOL(usb_gadget_register_driver);
01137 
01143 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
01144 {
01145         //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
01146 
01147         if (gadget_wrapper == 0) {
01148                 DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
01149                             -ENODEV);
01150                 return -ENODEV;
01151         }
01152         if (driver == 0 || driver != gadget_wrapper->driver) {
01153                 DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
01154                             -EINVAL);
01155                 return -EINVAL;
01156         }
01157 
01158         driver->unbind(&gadget_wrapper->gadget);
01159         gadget_wrapper->driver = 0;
01160 
01161         DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
01162         return 0;
01163 }
01164 
01165 EXPORT_SYMBOL(usb_gadget_unregister_driver);
01166 
01167 #endif                          /* DWC_HOST_ONLY */

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  doxygen 1.4.7