123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883 |
- /* ==========================================================================
- * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
- * $Revision: #20 $
- * $Date: 2011/10/26 $
- * $Change: 1872981 $
- *
- * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
- * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
- * otherwise expressly agreed to in writing between Synopsys and you.
- *
- * The Software IS NOT an item of Licensed Software or Licensed Product under
- * any End User Software License Agreement or Agreement for Licensed Product
- * with Synopsys or any supplement thereto. You are permitted to use and
- * redistribute this Software in source and binary forms, with or without
- * modification, provided that redistributions of source code must retain this
- * notice. You may not view, use, disclose, copy or distribute this file or
- * any information contained herein except pursuant to this license grant from
- * Synopsys. If you do not agree with this notice, including the disclaimer
- * below, then you are not authorized to use the Software.
- *
- * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- * ========================================================================== */
- #ifndef DWC_DEVICE_ONLY
- /**
- * @file
- *
- * This file contains the implementation of the HCD. In Linux, the HCD
- * implements the hc_driver API.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/errno.h>
- #include <linux/list.h>
- #include <linux/interrupt.h>
- #include <linux/string.h>
- #include <linux/dma-mapping.h>
- #include <linux/version.h>
- #include <asm/io.h>
- #include <linux/usb.h>
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
- #include <../drivers/usb/core/hcd.h>
- #else
- #include <linux/usb/hcd.h>
- #endif
- #include "dwc_otg_hcd_if.h"
- #include "dwc_otg_dbg.h"
- #include "dwc_otg_driver.h"
- #include "dwc_otg_hcd.h"
- /**
- * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
- * qualified with its direction (possible 32 endpoints per device).
- */
- #define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
- ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
- static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
- /** @name Linux HC Driver API Functions */
- /** @{ */
- static int urb_enqueue(struct usb_hcd *hcd,
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- struct usb_host_endpoint *ep,
- #endif
- struct urb *urb, gfp_t mem_flags);
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
- #else
- static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
- #endif
- static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
- static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
- #endif
- static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
- extern int hcd_start(struct usb_hcd *hcd);
- extern void hcd_stop(struct usb_hcd *hcd);
- extern int hcd_suspend(struct usb_hcd *hcd);
- extern int hcd_resume(struct usb_hcd *hcd);
- static int get_frame_number(struct usb_hcd *hcd);
- extern int hub_status_data(struct usb_hcd *hcd, char *buf);
- extern int hub_control(struct usb_hcd *hcd,
- u16 typeReq,
- u16 wValue, u16 wIndex, char *buf, u16 wLength);
- struct wrapper_priv_data {
- dwc_otg_hcd_t *dwc_otg_hcd;
- };
- /** @} */
- static struct hc_driver dwc_otg_hc_driver = {
- .description = dwc_otg_hcd_name,
- .product_desc = "DWC OTG Controller",
- .hcd_priv_size = sizeof(struct wrapper_priv_data),
- .irq = dwc_otg_hcd_irq,
- .flags = HCD_MEMORY | HCD_USB2,
- //.reset =
- .start = hcd_start,
- .stop = hcd_stop,
- .bus_suspend = hcd_suspend,
- .bus_resume = hcd_resume,
- .urb_enqueue = urb_enqueue,
- .urb_dequeue = urb_dequeue,
- .endpoint_disable = endpoint_disable,
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
- .endpoint_reset = endpoint_reset,
- #endif
- .get_frame_number = get_frame_number,
- .hub_status_data = hub_status_data,
- .hub_control = hub_control,
- };
- /** Gets the dwc_otg_hcd from a struct usb_hcd */
- static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
- {
- struct wrapper_priv_data *p;
- p = (struct wrapper_priv_data *)(hcd->hcd_priv);
- return p->dwc_otg_hcd;
- }
- /** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */
- static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
- {
- return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
- }
- /** Gets the usb_host_endpoint associated with an URB. */
- inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
- {
- struct usb_device *dev = urb->dev;
- int ep_num = usb_pipeendpoint(urb->pipe);
- if (usb_pipein(urb->pipe))
- return dev->ep_in[ep_num];
- else
- return dev->ep_out[ep_num];
- }
- static int _disconnect(dwc_otg_hcd_t * hcd)
- {
- struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
- usb_hcd->self.is_b_host = 0;
- return 0;
- }
- static int _start(dwc_otg_hcd_t * hcd)
- {
- struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
- usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
- hcd_start(usb_hcd);
- return 0;
- }
- static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
- uint32_t * port_addr)
- {
- struct urb *urb = (struct urb *)urb_handle;
- if (urb->dev->tt) {
- *hub_addr = urb->dev->tt->hub->devnum;
- } else {
- *hub_addr = 0;
- }
- *port_addr = urb->dev->ttport;
- return 0;
- }
- static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
- {
- struct urb *urb = (struct urb *)urb_handle;
- return urb->dev->speed;
- }
- static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
- {
- struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
- return usb_hcd->self.b_hnp_enable;
- }
- static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
- struct urb *urb)
- {
- hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
- } else {
- hcd_to_bus(hcd)->bandwidth_int_reqs++;
- }
- }
- static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
- struct urb *urb)
- {
- hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
- } else {
- hcd_to_bus(hcd)->bandwidth_int_reqs--;
- }
- }
- /**
- * Sets the final status of an URB and returns it to the device driver. Any
- * required cleanup of the URB is performed.
- */
- static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
- dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
- {
- struct urb *urb = (struct urb *)urb_handle;
- #ifdef DEBUG
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
- __func__, urb, usb_pipedevice(urb->pipe),
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "IN" : "OUT", status);
- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- int i;
- for (i = 0; i < urb->number_of_packets; i++) {
- DWC_PRINTF(" ISO Desc %d status: %d\n",
- i, urb->iso_frame_desc[i].status);
- }
- }
- }
- #endif
- urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
- /* Convert status value. */
- switch (status) {
- case -DWC_E_PROTOCOL:
- status = -EPROTO;
- break;
- case -DWC_E_IN_PROGRESS:
- status = -EINPROGRESS;
- break;
- case -DWC_E_PIPE:
- status = -EPIPE;
- break;
- case -DWC_E_IO:
- status = -EIO;
- break;
- case -DWC_E_TIMEOUT:
- status = -ETIMEDOUT;
- break;
- case -DWC_E_OVERFLOW:
- status = -EOVERFLOW;
- break;
- default:
- if (status) {
- DWC_PRINTF("Uknown urb status %d\n", status);
- }
- }
- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- int i;
- urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
- for (i = 0; i < urb->number_of_packets; ++i) {
- urb->iso_frame_desc[i].actual_length =
- dwc_otg_hcd_urb_get_iso_desc_actual_length
- (dwc_otg_urb, i);
- urb->iso_frame_desc[i].status =
- dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
- }
- }
- urb->status = status;
- urb->hcpriv = NULL;
- if (!status) {
- if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- (urb->actual_length < urb->transfer_buffer_length)) {
- urb->status = -EREMOTEIO;
- }
- }
- if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
- (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
- struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
- if (ep) {
- free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
- dwc_otg_hcd_get_ep_bandwidth(hcd,
- ep->hcpriv),
- urb);
- }
- }
- #if 0
- usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
- #endif
- DWC_FREE(dwc_otg_urb);
- DWC_SPINUNLOCK(hcd->lock);
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
- #else
- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
- #endif
- DWC_SPINLOCK(hcd->lock);
- return 0;
- }
- static struct dwc_otg_hcd_function_ops hcd_fops = {
- .start = _start,
- .disconnect = _disconnect,
- .hub_info = _hub_info,
- .speed = _speed,
- .complete = _complete,
- .get_b_hnp_enable = _get_b_hnp_enable,
- };
- /**
- * Initializes the HCD. This function allocates memory for and initializes the
- * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
- * USB bus with the core and calls the hc_driver->start() function. It returns
- * a negative error on failure.
- */
- int hcd_init(
- #ifdef LM_INTERFACE
- struct lm_device *_dev
- #elif defined(PCI_INTERFACE)
- struct pci_dev *_dev
- #endif
- )
- {
- struct usb_hcd *hcd = NULL;
- dwc_otg_hcd_t *dwc_otg_hcd = NULL;
- #ifdef LM_INTERFACE
- dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
- #elif defined(PCI_INTERFACE)
- dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
- #endif
- int retval = 0;
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
-
- #if 0 /* move to dwc_otg_driver_probe*/
- /* Set device flags indicating whether the HCD supports DMA. */
- if (dwc_otg_is_dma_enable(otg_dev->core_if)) {
- #ifdef LM_INTERFACE
- _dev->dev.dma_mask = (void *)~0;
- _dev->dev.coherent_dma_mask = ~0;
- #elif defined(PCI_INTERFACE)
- pci_set_dma_mask(_dev, DMA_32BIT_MASK);
- pci_set_consistent_dma_mask(_dev, DMA_32BIT_MASK);
- #endif
- } else {
- #ifdef LM_INTERFACE
- _dev->dev.dma_mask = (void *)0;
- _dev->dev.coherent_dma_mask = 0;
- #elif defined(PCI_INTERFACE)
- pci_set_dma_mask(_dev, 0);
- pci_set_consistent_dma_mask(_dev, 0);
- #endif
- }
- #endif
- /*
- * Allocate memory for the base HCD plus the DWC OTG HCD.
- * Initialize the base HCD.
- */
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
- hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
- #else
- hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev));
- hcd->has_tt = 1;
- // hcd->uses_new_polling = 1;
- // hcd->poll_rh = 0;
- #endif
- if (!hcd) {
- retval = -ENOMEM;
- goto error1;
- }
- hcd->regs = otg_dev->os_dep.base;
- /* Initialize the DWC OTG HCD. */
- dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
- if (!dwc_otg_hcd) {
- goto error2;
- }
- ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
- dwc_otg_hcd;
- otg_dev->hcd = dwc_otg_hcd;
- if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
- goto error2;
- }
- otg_dev->hcd->otg_dev = otg_dev;
- hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
- // hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if);
- /* Don't support SG list at this point */
- hcd->self.sg_tablesize = 0;
- #endif
- /*
- * Finish generic HCD initialization and start the HCD. This function
- * allocates the DMA buffer pool, registers the USB bus, requests the
- * IRQ line, and calls hcd_start method.
- */
- retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
- if (retval < 0) {
- goto error2;
- }
- dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
- return 0;
- error2:
- usb_put_hcd(hcd);
- error1:
- return retval;
- }
- /**
- * Removes the HCD.
- * Frees memory and resources associated with the HCD and deregisters the bus.
- */
- void hcd_remove(
- #ifdef LM_INTERFACE
- struct lm_device *_dev
- #elif defined(PCI_INTERFACE)
- struct pci_dev *_dev
- #endif
- )
- {
- #ifdef LM_INTERFACE
- dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
- #elif defined(PCI_INTERFACE)
- dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
- #endif
- dwc_otg_hcd_t *dwc_otg_hcd;
- struct usb_hcd *hcd;
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
- if (!otg_dev) {
- DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
- return;
- }
- dwc_otg_hcd = otg_dev->hcd;
- if (!dwc_otg_hcd) {
- DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
- return;
- }
- hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
- if (!hcd) {
- DWC_DEBUGPL(DBG_ANY,
- "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
- __func__);
- return;
- }
- usb_remove_hcd(hcd);
- dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
- dwc_otg_hcd_remove(dwc_otg_hcd);
- usb_put_hcd(hcd);
- }
- /* =========================================================================
- * Linux HC Driver Functions
- * ========================================================================= */
- /** Initializes the DWC_otg controller and its root hub and prepares it for host
- * mode operation. Activates the root port. Returns 0 on success and a negative
- * error code on failure. */
- int hcd_start(struct usb_hcd *hcd)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- struct usb_bus *bus;
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
- bus = hcd_to_bus(hcd);
- hcd->state = HC_STATE_RUNNING;
- if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
- return 0;
- }
- /* Initialize and connect root hub if one is not already attached */
- if (bus->root_hub) {
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
- /* Inform the HUB driver to resume. */
- usb_hcd_resume_root_hub(hcd);
- }
- return 0;
- }
- /**
- * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
- * stopped.
- */
- void hcd_stop(struct usb_hcd *hcd)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- dwc_otg_hcd_stop(dwc_otg_hcd);
- }
- /** HCD Suspend */
- int hcd_suspend(struct usb_hcd *hcd)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- DWC_DEBUGPL(DBG_HCD, "HCD SUSPEND\n");
- dwc_otg_hcd_suspend(dwc_otg_hcd);
- return 0;
- }
- /** HCD resume */
- int hcd_resume(struct usb_hcd *hcd)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- DWC_DEBUGPL(DBG_HCD, "HCD RESUME\n");
-
- dwc_otg_hcd_resume(dwc_otg_hcd);
- return 0;
- }
- /** Returns the current frame number. */
- static int get_frame_number(struct usb_hcd *hcd)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
- }
- #ifdef DEBUG
- static void dump_urb_info(struct urb *urb, char *fn_name)
- {
- DWC_PRINTF("%s, urb %p\n", fn_name, urb);
- DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe));
- DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
- (usb_pipein(urb->pipe) ? "IN" : "OUT"));
- DWC_PRINTF(" Endpoint type: %s\n", ( {
- char *pipetype;
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- pipetype = "CONTROL"; break; case PIPE_BULK:
- pipetype = "BULK"; break; case PIPE_INTERRUPT:
- pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
- pipetype = "ISOCHRONOUS"; break; default:
- pipetype = "UNKNOWN"; break;};
- pipetype;}
- )) ;
- DWC_PRINTF(" Speed: %s\n", ( {
- char *speed; switch (urb->dev->speed) {
- case USB_SPEED_HIGH:
- speed = "HIGH"; break; case USB_SPEED_FULL:
- speed = "FULL"; break; case USB_SPEED_LOW:
- speed = "LOW"; break; default:
- speed = "UNKNOWN"; break;};
- speed;}
- )) ;
- DWC_PRINTF(" Max packet size: %d\n",
- usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
- DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length);
- DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n",
- urb->transfer_buffer, (void *)urb->transfer_dma);
- DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n",
- urb->setup_packet, (void *)urb->setup_dma);
- DWC_PRINTF(" Interval: %d\n", urb->interval);
- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
- int i;
- for (i = 0; i < urb->number_of_packets; i++) {
- DWC_PRINTF(" ISO Desc %d:\n", i);
- DWC_PRINTF(" offset: %d, length %d\n",
- urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].length);
- }
- }
- }
- #endif
- /** Starts processing a USB transfer request specified by a USB Request Block
- * (URB). mem_flags indicates the type of memory allocation to use while
- * processing this URB. */
- static int urb_enqueue(struct usb_hcd *hcd,
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- struct usb_host_endpoint *ep,
- #endif
- struct urb *urb, gfp_t mem_flags)
- {
- int retval = 0;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
- struct usb_host_endpoint *ep = urb->ep;
- #endif
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- dwc_otg_hcd_urb_t *dwc_otg_urb;
- int i;
- int alloc_bandwidth = 0;
- uint8_t ep_type = 0;
- uint32_t flags = 0;
- void *buf;
- #ifdef DEBUG
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- dump_urb_info(urb, "urb_enqueue");
- }
- #endif
- #if 0
- retval = usb_hcd_link_urb_to_ep(hcd,urb);
- if (unlikely(retval)) {
- DWC_ERROR("DWC OTG HCD URB Enqueue failed linking urb. "
- "Error status %d\n", retval);
- return retval;
- }
- #endif
- if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
- || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
- if (!dwc_otg_hcd_is_bandwidth_allocated
- (dwc_otg_hcd, &ep->hcpriv)) {
- alloc_bandwidth = 1;
- }
- }
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ep_type = USB_ENDPOINT_XFER_CONTROL;
- break;
- case PIPE_ISOCHRONOUS:
- ep_type = USB_ENDPOINT_XFER_ISOC;
- break;
- case PIPE_BULK:
- ep_type = USB_ENDPOINT_XFER_BULK;
- break;
- case PIPE_INTERRUPT:
- ep_type = USB_ENDPOINT_XFER_INT;
- break;
- default:
- DWC_WARN("Wrong ep type\n");
- }
- dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
- urb->number_of_packets,
- mem_flags == GFP_ATOMIC ? 1 : 0);
- dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
- usb_pipeendpoint(urb->pipe), ep_type,
- usb_pipein(urb->pipe),
- usb_maxpacket(urb->dev, urb->pipe,
- !(usb_pipein(urb->pipe))));
- buf = urb->transfer_buffer;
- if (hcd->self.uses_dma) {
- /*
- * Calculate virtual address from physical address,
- * because some class driver may not fill transfer_buffer.
- * In Buffer DMA mode virual address is used,
- * when handling non DWORD aligned buffers.
- */
- buf = phys_to_virt(urb->transfer_dma);
- }
- if (!(urb->transfer_flags & URB_NO_INTERRUPT))
- flags |= URB_GIVEBACK_ASAP;
- if (urb->transfer_flags & URB_ZERO_PACKET)
- flags |= URB_SEND_ZERO_PACKET;
- dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- urb->setup_packet,
- urb->setup_dma, flags, urb->interval);
- for (i = 0; i < urb->number_of_packets; ++i) {
- dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
- urb->
- iso_frame_desc[i].offset,
- urb->
- iso_frame_desc[i].length);
- }
- urb->hcpriv = dwc_otg_urb;
- retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, &ep->hcpriv,
- mem_flags == GFP_ATOMIC ? 1 : 0);
- if (!retval) {
- if (alloc_bandwidth) {
- allocate_bus_bandwidth(hcd,
- dwc_otg_hcd_get_ep_bandwidth
- (dwc_otg_hcd, ep->hcpriv), urb);
- }
- } else {
- #if 0
- usb_hcd_unlink_urb_from_ep(hcd,urb);
- #endif
- if (retval == -DWC_E_NO_DEVICE) {
- retval = -ENODEV;
- }
- }
- return retval;
- }
- /** Aborts/cancels a USB transfer request. Always returns 0 to indicate
- * success. */
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
- #else
- static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
- #endif
- {
- int retval = 0;
- dwc_irqflags_t flags;
- dwc_otg_hcd_t *dwc_otg_hcd;
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
- dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- #ifdef DEBUG
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- dump_urb_info(urb, "urb_dequeue");
- }
- #endif
- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
- #if 0
- retval = usb_hcd_check_unlink_urb(hcd, urb, status);
- if(unlikely(retval))
- goto EXIT;
- #endif
- if(urb->hcpriv == NULL){
- printk(KERN_ERR "###########urb = %p status=%d\n",urb,status);
- goto EXIT;
- }
- retval = dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, urb->hcpriv);
- DWC_FREE(urb->hcpriv);
- urb->hcpriv = NULL;
- EXIT:
- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
- if(retval) return retval;
- /* Higher layer software sets URB status. */
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- usb_hcd_giveback_urb(hcd, urb);
- #else
- usb_hcd_giveback_urb(hcd, urb, status);
- #endif
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- DWC_PRINTF("Called usb_hcd_giveback_urb()\n");
- DWC_PRINTF(" urb->status = %d\n", urb->status);
- }
- return 0;
- }
- /* Frees resources in the DWC_otg controller related to a given endpoint. Also
- * clears state in the HCD related to the endpoint. Any URBs for the endpoint
- * must already be dequeued. */
- static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- DWC_DEBUGPL(DBG_HCD,
- "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
- "endpoint=%d\n", ep->desc.bEndpointAddress,
- dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
- dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
- ep->hcpriv = NULL;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
- /* Resets endpoint specific parameter values, in current version used to reset
- * the data toggle(as a WA). This function can be called from usb_clear_halt routine */
- static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
- {
- dwc_irqflags_t flags;
- struct usb_device *udev = NULL;
- int epnum = usb_endpoint_num(&ep->desc);
- int is_out = usb_endpoint_dir_out(&ep->desc);
- int is_control = usb_endpoint_xfer_control(&ep->desc);
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- #ifdef LM_INTERFACE
- struct lm_device *_dev = dwc_otg_hcd->otg_dev->os_dep.lmdev;
- #elif defined(PCI_INTERFACE)
- struct pci_dev *_dev = dwc_otg_hcd->otg_dev->os_dep.pcidev;
- #endif
- if (_dev)
- udev = to_usb_device(&_dev->dev);
- else
- return;
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum);
- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
- usb_settoggle(udev, epnum, is_out, 0);
- if (is_control)
- usb_settoggle(udev, epnum, !is_out, 0);
- if (ep->hcpriv) {
- dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
- }
- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
- }
- #endif
- /** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
- * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
- * interrupt.
- *
- * This function is called by the USB core when an interrupt occurs */
- static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
- if (retval != 0) {
- S3C2410X_CLEAR_EINTPEND();
- }
- return IRQ_RETVAL(retval);
- }
- /** Creates Status Change bitmap for the root hub and root port. The bitmap is
- * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
- * is the status change indicator for the single root port. Returns 1 if either
- * change indicator is 1, otherwise returns 0. */
- int hub_status_data(struct usb_hcd *hcd, char *buf)
- {
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- buf[0] = 0;
- buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
- return (buf[0] != 0);
- }
- /** Handles hub class-specific requests. */
- int hub_control(struct usb_hcd *hcd,
- u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
- {
- int retval;
- retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
- typeReq, wValue, wIndex, buf, wLength);
- switch (retval) {
- case -DWC_E_INVALID:
- retval = -EINVAL;
- break;
- }
- return retval;
- }
- #endif /* DWC_DEVICE_ONLY */
|