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

dwc_otg_hcd_linux.c

Go to the documentation of this file.
00001 /* ==========================================================================
00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
00003  * $Revision: #20 $
00004  * $Date: 2011/10/26 $
00005  * $Change: 1872981 $
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_DEVICE_ONLY
00034 
00041 #include <linux/kernel.h>
00042 #include <linux/module.h>
00043 #include <linux/moduleparam.h>
00044 #include <linux/init.h>
00045 #include <linux/device.h>
00046 #include <linux/errno.h>
00047 #include <linux/list.h>
00048 #include <linux/interrupt.h>
00049 #include <linux/string.h>
00050 #include <linux/dma-mapping.h>
00051 #include <linux/version.h>
00052 #include <asm/io.h>
00053 #include <linux/usb.h>
00054 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
00055 #include <../drivers/usb/core/hcd.h>
00056 #else
00057 #include <linux/usb/hcd.h>
00058 #endif
00059 
00060 #include "dwc_otg_hcd_if.h"
00061 #include "dwc_otg_dbg.h"
00062 #include "dwc_otg_driver.h"
00063 #include "dwc_otg_hcd.h"
00068 #define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
00069                                                      ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
00070 
00071 static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
00072 
00075 static int urb_enqueue(struct usb_hcd *hcd,
00076 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00077                        struct usb_host_endpoint *ep,
00078 #endif
00079                        struct urb *urb, gfp_t mem_flags);
00080 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00081 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
00082 #else
00083 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
00084 #endif
00085 
00086 static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
00087 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
00088 static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
00089 #endif
00090 static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
00091 extern int hcd_start(struct usb_hcd *hcd);
00092 extern void hcd_stop(struct usb_hcd *hcd);
00093 static int get_frame_number(struct usb_hcd *hcd);
00094 extern int hub_status_data(struct usb_hcd *hcd, char *buf);
00095 extern int hub_control(struct usb_hcd *hcd,
00096                        u16 typeReq,
00097                        u16 wValue, u16 wIndex, char *buf, u16 wLength);
00098 
00099 struct wrapper_priv_data {
00100         dwc_otg_hcd_t *dwc_otg_hcd;
00101 };
00102 
00105 static struct hc_driver dwc_otg_hc_driver = {
00106 
00107         .description = dwc_otg_hcd_name,
00108         .product_desc = "DWC OTG Controller",
00109         .hcd_priv_size = sizeof(struct wrapper_priv_data),
00110 
00111         .irq = dwc_otg_hcd_irq,
00112 
00113         .flags = HCD_MEMORY | HCD_USB2,
00114 
00115         //.reset =              
00116         .start = hcd_start,
00117         //.suspend =            
00118         //.resume =             
00119         .stop = hcd_stop,
00120 
00121         .urb_enqueue = urb_enqueue,
00122         .urb_dequeue = urb_dequeue,
00123         .endpoint_disable = endpoint_disable,
00124 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
00125         .endpoint_reset = endpoint_reset,
00126 #endif
00127         .get_frame_number = get_frame_number,
00128 
00129         .hub_status_data = hub_status_data,
00130         .hub_control = hub_control,
00131         //.bus_suspend =                
00132         //.bus_resume =         
00133 };
00134 
00136 static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
00137 {
00138         struct wrapper_priv_data *p;
00139         p = (struct wrapper_priv_data *)(hcd->hcd_priv);
00140         return p->dwc_otg_hcd;
00141 }
00142 
00144 static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
00145 {
00146         return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
00147 }
00148 
00150 inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
00151 {
00152         struct usb_device *dev = urb->dev;
00153         int ep_num = usb_pipeendpoint(urb->pipe);
00154 
00155         if (usb_pipein(urb->pipe))
00156                 return dev->ep_in[ep_num];
00157         else
00158                 return dev->ep_out[ep_num];
00159 }
00160 
00161 static int _disconnect(dwc_otg_hcd_t * hcd)
00162 {
00163         struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
00164 
00165         usb_hcd->self.is_b_host = 0;
00166         return 0;
00167 }
00168 
00169 static int _start(dwc_otg_hcd_t * hcd)
00170 {
00171         struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
00172 
00173         usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
00174         hcd_start(usb_hcd);
00175 
00176         return 0;
00177 }
00178 
00179 static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
00180                      uint32_t * port_addr)
00181 {
00182         struct urb *urb = (struct urb *)urb_handle;
00183         if (urb->dev->tt) {
00184                 *hub_addr = urb->dev->tt->hub->devnum;
00185         } else {
00186                 *hub_addr = 0;
00187         }
00188         *port_addr = urb->dev->ttport;
00189         return 0;
00190 }
00191 
00192 static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
00193 {
00194         struct urb *urb = (struct urb *)urb_handle;
00195         return urb->dev->speed;
00196 }
00197 
00198 static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
00199 {
00200         struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
00201         return usb_hcd->self.b_hnp_enable;
00202 }
00203 
00204 static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
00205                                    struct urb *urb)
00206 {
00207         hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
00208         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
00209                 hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
00210         } else {
00211                 hcd_to_bus(hcd)->bandwidth_int_reqs++;
00212         }
00213 }
00214 
00215 static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
00216                                struct urb *urb)
00217 {
00218         hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
00219         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
00220                 hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
00221         } else {
00222                 hcd_to_bus(hcd)->bandwidth_int_reqs--;
00223         }
00224 }
00225 
00230 static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
00231                      dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
00232 {
00233         struct urb *urb = (struct urb *)urb_handle;
00234 #ifdef DEBUG
00235         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
00236                 DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
00237                            __func__, urb, usb_pipedevice(urb->pipe),
00238                            usb_pipeendpoint(urb->pipe),
00239                            usb_pipein(urb->pipe) ? "IN" : "OUT", status);
00240                 if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
00241                         int i;
00242                         for (i = 0; i < urb->number_of_packets; i++) {
00243                                 DWC_PRINTF("  ISO Desc %d status: %d\n",
00244                                            i, urb->iso_frame_desc[i].status);
00245                         }
00246                 }
00247         }
00248 #endif
00249 
00250         urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
00251         /* Convert status value. */
00252         switch (status) {
00253         case -DWC_E_PROTOCOL:
00254                 status = -EPROTO;
00255                 break;
00256         case -DWC_E_IN_PROGRESS:
00257                 status = -EINPROGRESS;
00258                 break;
00259         case -DWC_E_PIPE:
00260                 status = -EPIPE;
00261                 break;
00262         case -DWC_E_IO:
00263                 status = -EIO;
00264                 break;
00265         case -DWC_E_TIMEOUT:
00266                 status = -ETIMEDOUT;
00267                 break;
00268         case -DWC_E_OVERFLOW:
00269                 status = -EOVERFLOW;
00270                 break;
00271         default:
00272                 if (status) {
00273                         DWC_PRINTF("Uknown urb status %d\n", status);
00274 
00275                 }
00276         }
00277 
00278         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
00279                 int i;
00280 
00281                 urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
00282                 for (i = 0; i < urb->number_of_packets; ++i) {
00283                         urb->iso_frame_desc[i].actual_length =
00284                             dwc_otg_hcd_urb_get_iso_desc_actual_length
00285                             (dwc_otg_urb, i);
00286                         urb->iso_frame_desc[i].status =
00287                             dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
00288                 }
00289         }
00290 
00291         urb->status = status;
00292         urb->hcpriv = NULL;
00293         if (!status) {
00294                 if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
00295                     (urb->actual_length < urb->transfer_buffer_length)) {
00296                         urb->status = -EREMOTEIO;
00297                 }
00298         }
00299 
00300         if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
00301             (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
00302                 struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
00303                 if (ep) {
00304                         free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
00305                                            dwc_otg_hcd_get_ep_bandwidth(hcd,
00306                                                                         ep->hcpriv),
00307                                            urb);
00308                 }
00309         }
00310 
00311         DWC_FREE(dwc_otg_urb);
00312 
00313         DWC_SPINUNLOCK(hcd->lock);
00314 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00315         usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
00316 #else
00317         usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
00318 #endif
00319         DWC_SPINLOCK(hcd->lock);
00320 
00321         return 0;
00322 }
00323 
00324 static struct dwc_otg_hcd_function_ops hcd_fops = {
00325         .start = _start,
00326         .disconnect = _disconnect,
00327         .hub_info = _hub_info,
00328         .speed = _speed,
00329         .complete = _complete,
00330         .get_b_hnp_enable = _get_b_hnp_enable,
00331 };
00332 
00339 int hcd_init(
00340 #ifdef LM_INTERFACE
00341                     struct lm_device *_dev
00342 #elif  defined(PCI_INTERFACE)
00343                     struct pci_dev *_dev
00344 #endif
00345     )
00346 {
00347         struct usb_hcd *hcd = NULL;
00348         dwc_otg_hcd_t *dwc_otg_hcd = NULL;
00349 #ifdef LM_INTERFACE
00350         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
00351 #elif  defined(PCI_INTERFACE)
00352         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
00353 #endif
00354 
00355         int retval = 0;
00356 
00357         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
00358 
00359         /* Set device flags indicating whether the HCD supports DMA. */
00360         if (dwc_otg_is_dma_enable(otg_dev->core_if)) {
00361 #ifdef LM_INTERFACE
00362                 _dev->dev.dma_mask = (void *)~0;
00363                 _dev->dev.coherent_dma_mask = ~0;
00364 #elif  defined(PCI_INTERFACE)
00365                 pci_set_dma_mask(_dev, DMA_32BIT_MASK);
00366                 pci_set_consistent_dma_mask(_dev, DMA_32BIT_MASK);
00367 #endif
00368 
00369         } else {
00370 #ifdef LM_INTERFACE
00371                 _dev->dev.dma_mask = (void *)0;
00372                 _dev->dev.coherent_dma_mask = 0;
00373 #elif  defined(PCI_INTERFACE)
00374                 pci_set_dma_mask(_dev, 0);
00375                 pci_set_consistent_dma_mask(_dev, 0);
00376 #endif
00377         }
00378 
00379         /*
00380          * Allocate memory for the base HCD plus the DWC OTG HCD.
00381          * Initialize the base HCD.
00382          */
00383 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
00384         hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
00385 #else
00386         hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
00387         hcd->has_tt = 1;
00388 //      hcd->uses_new_polling = 1;
00389 //      hcd->poll_rh = 0;
00390 #endif
00391         if (!hcd) {
00392                 retval = -ENOMEM;
00393                 goto error1;
00394         }
00395 
00396         hcd->regs = otg_dev->os_dep.base;
00397 
00398         /* Initialize the DWC OTG HCD. */
00399         dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
00400         if (!dwc_otg_hcd) {
00401                 goto error2;
00402         }
00403         ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
00404             dwc_otg_hcd;
00405         otg_dev->hcd = dwc_otg_hcd;
00406 
00407         if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
00408                 goto error2;
00409         }
00410 
00411         otg_dev->hcd->otg_dev = otg_dev;
00412         hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
00413 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
00414         hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
00415         /* Don't support SG list at this point */
00416         hcd->self.sg_tablesize = 0;
00417 #endif
00418         /*
00419          * Finish generic HCD initialization and start the HCD. This function
00420          * allocates the DMA buffer pool, registers the USB bus, requests the
00421          * IRQ line, and calls hcd_start method.
00422          */
00423         retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
00424         if (retval < 0) {
00425                 goto error2;
00426         }
00427 
00428         dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
00429         return 0;
00430 
00431 error2:
00432         usb_put_hcd(hcd);
00433 error1:
00434         return retval;
00435 }
00436 
00441 void hcd_remove(
00442 #ifdef LM_INTERFACE
00443                        struct lm_device *_dev
00444 #elif  defined(PCI_INTERFACE)
00445                        struct pci_dev *_dev
00446 #endif
00447     )
00448 {
00449 #ifdef LM_INTERFACE
00450         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
00451 #elif  defined(PCI_INTERFACE)
00452         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
00453 #endif
00454 
00455         dwc_otg_hcd_t *dwc_otg_hcd;
00456         struct usb_hcd *hcd;
00457 
00458         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
00459 
00460         if (!otg_dev) {
00461                 DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
00462                 return;
00463         }
00464 
00465         dwc_otg_hcd = otg_dev->hcd;
00466 
00467         if (!dwc_otg_hcd) {
00468                 DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
00469                 return;
00470         }
00471 
00472         hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
00473 
00474         if (!hcd) {
00475                 DWC_DEBUGPL(DBG_ANY,
00476                             "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
00477                             __func__);
00478                 return;
00479         }
00480         usb_remove_hcd(hcd);
00481         dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
00482         dwc_otg_hcd_remove(dwc_otg_hcd);
00483         usb_put_hcd(hcd);
00484 }
00485 
00486 /* =========================================================================
00487  *  Linux HC Driver Functions
00488  * ========================================================================= */
00489 
00493 int hcd_start(struct usb_hcd *hcd)
00494 {
00495         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00496         struct usb_bus *bus;
00497 
00498         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
00499         bus = hcd_to_bus(hcd);
00500 
00501         hcd->state = HC_STATE_RUNNING;
00502         if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
00503                 return 0;
00504         }
00505 
00506         /* Initialize and connect root hub if one is not already attached */
00507         if (bus->root_hub) {
00508                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
00509                 /* Inform the HUB driver to resume. */
00510                 usb_hcd_resume_root_hub(hcd);
00511         }
00512 
00513         return 0;
00514 }
00515 
00520 void hcd_stop(struct usb_hcd *hcd)
00521 {
00522         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00523 
00524         dwc_otg_hcd_stop(dwc_otg_hcd);
00525 }
00526 
00528 static int get_frame_number(struct usb_hcd *hcd)
00529 {
00530         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00531 
00532         return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
00533 }
00534 
00535 #ifdef DEBUG
00536 static void dump_urb_info(struct urb *urb, char *fn_name)
00537 {
00538         DWC_PRINTF("%s, urb %p\n", fn_name, urb);
00539         DWC_PRINTF("  Device address: %d\n", usb_pipedevice(urb->pipe));
00540         DWC_PRINTF("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
00541                    (usb_pipein(urb->pipe) ? "IN" : "OUT"));
00542         DWC_PRINTF("  Endpoint type: %s\n", ( {
00543                                              char *pipetype;
00544                                              switch (usb_pipetype(urb->pipe)) {
00545 case PIPE_CONTROL:
00546 pipetype = "CONTROL"; break; case PIPE_BULK:
00547 pipetype = "BULK"; break; case PIPE_INTERRUPT:
00548 pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
00549 pipetype = "ISOCHRONOUS"; break; default:
00550                                              pipetype = "UNKNOWN"; break;};
00551                                              pipetype;}
00552                    )) ;
00553         DWC_PRINTF("  Speed: %s\n", ( {
00554                                      char *speed; switch (urb->dev->speed) {
00555 case USB_SPEED_HIGH:
00556 speed = "HIGH"; break; case USB_SPEED_FULL:
00557 speed = "FULL"; break; case USB_SPEED_LOW:
00558 speed = "LOW"; break; default:
00559                                      speed = "UNKNOWN"; break;};
00560                                      speed;}
00561                    )) ;
00562         DWC_PRINTF("  Max packet size: %d\n",
00563                    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
00564         DWC_PRINTF("  Data buffer length: %d\n", urb->transfer_buffer_length);
00565         DWC_PRINTF("  Transfer buffer: %p, Transfer DMA: %p\n",
00566                    urb->transfer_buffer, (void *)urb->transfer_dma);
00567         DWC_PRINTF("  Setup buffer: %p, Setup DMA: %p\n",
00568                    urb->setup_packet, (void *)urb->setup_dma);
00569         DWC_PRINTF("  Interval: %d\n", urb->interval);
00570         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
00571                 int i;
00572                 for (i = 0; i < urb->number_of_packets; i++) {
00573                         DWC_PRINTF("  ISO Desc %d:\n", i);
00574                         DWC_PRINTF("    offset: %d, length %d\n",
00575                                    urb->iso_frame_desc[i].offset,
00576                                    urb->iso_frame_desc[i].length);
00577                 }
00578         }
00579 }
00580 
00581 #endif
00582 
00586 static int urb_enqueue(struct usb_hcd *hcd,
00587 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00588                        struct usb_host_endpoint *ep,
00589 #endif
00590                        struct urb *urb, gfp_t mem_flags)
00591 {
00592         int retval = 0;
00593 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
00594         struct usb_host_endpoint *ep = urb->ep;
00595 #endif
00596         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00597         dwc_otg_hcd_urb_t *dwc_otg_urb;
00598         int i;
00599         int alloc_bandwidth = 0;
00600         uint8_t ep_type = 0;
00601         uint32_t flags = 0;
00602         void *buf;
00603 
00604 #ifdef DEBUG
00605         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
00606                 dump_urb_info(urb, "urb_enqueue");
00607         }
00608 #endif
00609 
00610         if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
00611             || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
00612                 if (!dwc_otg_hcd_is_bandwidth_allocated
00613                     (dwc_otg_hcd, &ep->hcpriv)) {
00614                         alloc_bandwidth = 1;
00615                 }
00616         }
00617 
00618         switch (usb_pipetype(urb->pipe)) {
00619         case PIPE_CONTROL:
00620                 ep_type = USB_ENDPOINT_XFER_CONTROL;
00621                 break;
00622         case PIPE_ISOCHRONOUS:
00623                 ep_type = USB_ENDPOINT_XFER_ISOC;
00624                 break;
00625         case PIPE_BULK:
00626                 ep_type = USB_ENDPOINT_XFER_BULK;
00627                 break;
00628         case PIPE_INTERRUPT:
00629                 ep_type = USB_ENDPOINT_XFER_INT;
00630                 break;
00631         default:
00632                 DWC_WARN("Wrong ep type\n");
00633         }
00634 
00635         dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
00636                                             urb->number_of_packets,
00637                                             mem_flags == GFP_ATOMIC ? 1 : 0);
00638 
00639         dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
00640                                      usb_pipeendpoint(urb->pipe), ep_type,
00641                                      usb_pipein(urb->pipe),
00642                                      usb_maxpacket(urb->dev, urb->pipe,
00643                                                    !(usb_pipein(urb->pipe))));
00644 
00645         buf = urb->transfer_buffer;
00646         if (hcd->self.uses_dma) {
00647                 /*
00648                  * Calculate virtual address from physical address,
00649                  * because some class driver may not fill transfer_buffer.
00650                  * In Buffer DMA mode virual address is used,
00651                  * when handling non DWORD aligned buffers.
00652                  */
00653                 buf = phys_to_virt(urb->transfer_dma);
00654         }
00655 
00656         if (!(urb->transfer_flags & URB_NO_INTERRUPT))
00657                 flags |= URB_GIVEBACK_ASAP;
00658         if (urb->transfer_flags & URB_ZERO_PACKET)
00659                 flags |= URB_SEND_ZERO_PACKET;
00660 
00661         dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
00662                                    urb->transfer_dma,
00663                                    urb->transfer_buffer_length,
00664                                    urb->setup_packet,
00665                                    urb->setup_dma, flags, urb->interval);
00666 
00667         for (i = 0; i < urb->number_of_packets; ++i) {
00668                 dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
00669                                                     urb->
00670                                                     iso_frame_desc[i].offset,
00671                                                     urb->
00672                                                     iso_frame_desc[i].length);
00673         }
00674 
00675         urb->hcpriv = dwc_otg_urb;
00676         retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, &ep->hcpriv,
00677                                          mem_flags == GFP_ATOMIC ? 1 : 0);
00678         if (!retval) {
00679                 if (alloc_bandwidth) {
00680                         allocate_bus_bandwidth(hcd,
00681                                                dwc_otg_hcd_get_ep_bandwidth
00682                                                (dwc_otg_hcd, ep->hcpriv), urb);
00683                 }
00684         } else {
00685                 if (retval == -DWC_E_NO_DEVICE) {
00686                         retval = -ENODEV;
00687                 }
00688         }
00689 
00690         return retval;
00691 }
00692 
00695 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00696 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
00697 #else
00698 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
00699 #endif
00700 {
00701         dwc_irqflags_t flags;
00702         dwc_otg_hcd_t *dwc_otg_hcd;
00703         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
00704 
00705         dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00706 
00707 #ifdef DEBUG
00708         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
00709                 dump_urb_info(urb, "urb_dequeue");
00710         }
00711 #endif
00712 
00713         DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
00714 
00715         dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, urb->hcpriv);
00716 
00717         DWC_FREE(urb->hcpriv);
00718         urb->hcpriv = NULL;
00719         DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
00720 
00721         /* Higher layer software sets URB status. */
00722 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
00723         usb_hcd_giveback_urb(hcd, urb);
00724 #else
00725         usb_hcd_giveback_urb(hcd, urb, status);
00726 #endif
00727         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
00728                 DWC_PRINTF("Called usb_hcd_giveback_urb()\n");
00729                 DWC_PRINTF("  urb->status = %d\n", urb->status);
00730         }
00731 
00732         return 0;
00733 }
00734 
00735 /* Frees resources in the DWC_otg controller related to a given endpoint. Also
00736  * clears state in the HCD related to the endpoint. Any URBs for the endpoint
00737  * must already be dequeued. */
00738 static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
00739 {
00740         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00741 
00742         DWC_DEBUGPL(DBG_HCD,
00743                     "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
00744                     "endpoint=%d\n", ep->desc.bEndpointAddress,
00745                     dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
00746         dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
00747         ep->hcpriv = NULL;
00748 }
00749 
00750 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
00751 /* Resets endpoint specific parameter values, in current version used to reset 
00752  * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
00753 static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
00754 {
00755         dwc_irqflags_t flags;
00756         struct usb_device *udev = NULL;
00757         int epnum = usb_endpoint_num(&ep->desc);
00758         int is_out = usb_endpoint_dir_out(&ep->desc);
00759         int is_control = usb_endpoint_xfer_control(&ep->desc);
00760         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00761 #ifdef LM_INTERFACE
00762         struct lm_device *_dev = dwc_otg_hcd->otg_dev->os_dep.lmdev;
00763 #elif defined(PCI_INTERFACE)
00764         struct pci_dev *_dev = dwc_otg_hcd->otg_dev->os_dep.pcidev;
00765 #endif
00766 
00767         if (_dev)
00768                 udev = to_usb_device(&_dev->dev);
00769         else
00770                 return;
00771 
00772         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
00773 
00774         DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
00775         usb_settoggle(udev, epnum, is_out, 0);
00776         if (is_control)
00777                 usb_settoggle(udev, epnum, !is_out, 0);
00778 
00779         if (ep->hcpriv) {
00780                 dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
00781         }
00782         DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
00783 }
00784 #endif
00785 
00791 static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
00792 {
00793         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00794         int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
00795         if (retval != 0) {
00796                 S3C2410X_CLEAR_EINTPEND();
00797         }
00798         return IRQ_RETVAL(retval);
00799 }
00800 
00805 int hub_status_data(struct usb_hcd *hcd, char *buf)
00806 {
00807         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
00808 
00809         buf[0] = 0;
00810         buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
00811 
00812         return (buf[0] != 0);
00813 }
00814 
00816 int hub_control(struct usb_hcd *hcd,
00817                 u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
00818 {
00819         int retval;
00820 
00821         retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
00822                                          typeReq, wValue, wIndex, buf, wLength);
00823 
00824         switch (retval) {
00825         case -DWC_E_INVALID:
00826                 retval = -EINVAL;
00827                 break;
00828         }
00829 
00830         return retval;
00831 }
00832 
00833 #endif /* DWC_DEVICE_ONLY */

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