Re: [PATCH] usb: gadget: Add driver for PLX USB338x

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Amit

I am working on a patch that adds the functionality of the usb338x to
the net2280 driver. There are some problems with the driver from plx:
There are some global variables n_ep, enhanced_mode... that should not
be global. There are some fixes on the net2280 that are not applied on
the driver from plx, and more imporant, there is a LOT of code that is
the same for both chips. The usb338x supports legacy mode.

I plan to test it tomorrow on real hardware and send it to the mail
list. perhaps you could test it with your hardware.

Regards!

On Tue, May 13, 2014 at 7:47 PM, Amit Uttamchandani
<auttamchandani@xxxxxxxxxxxx> wrote:
> This adds the gadget driver for PLX USB338x USB 3.0 Controllers. This is
> the latest version 3.0 from upstream
> (http://www.plxtech.com/products/usbcontrollers/usb3380).
> ---
>  drivers/usb/gadget/Kconfig   |   11 +
>  drivers/usb/gadget/Makefile  |    1 +
>  drivers/usb/gadget/usb338x.c | 4493 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/gadget/usb338x.h |  952 +++++++++
>  4 files changed, 5457 insertions(+)
>  create mode 100644 drivers/usb/gadget/usb338x.c
>  create mode 100644 drivers/usb/gadget/usb338x.h
>
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index 3557c7e..7e059b4 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -429,6 +429,17 @@ config USB_NET2280
>            dynamically linked module called "net2280" and force all
>            gadget drivers to also be dynamically linked.
>
> +config USB_USB338X
> +       tristate "PLX 338x"
> +       depends on PCI
> +       help
> +          PLX USB 338x is a PCI based USB peripheral controller which
> +          supports full/high/super speed USB 3.0 data transfers.
> +
> +          Say "y" to link the driver statically, or "m" to build a
> +          dynamically linked module called "usb338x" and force all
> +          gadget drivers to also be dynamically linked.
> +
>  config USB_GOKU
>         tristate "Toshiba TC86C001 'Goku-S'"
>         depends on PCI
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 5f150bc..f1cbad3 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -11,6 +11,7 @@ libcomposite-y                        += composite.o functions.o configfs.o u_f.o
>  obj-$(CONFIG_USB_DUMMY_HCD)    += dummy_hcd.o
>  obj-$(CONFIG_USB_NET2272)      += net2272.o
>  obj-$(CONFIG_USB_NET2280)      += net2280.o
> +obj-$(CONFIG_USB_USB338X)      += usb338x.o
>  obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc.o
>  obj-$(CONFIG_USB_PXA25X)       += pxa25x_udc.o
>  obj-$(CONFIG_USB_PXA27X)       += pxa27x_udc.o
> diff --git a/drivers/usb/gadget/usb338x.c b/drivers/usb/gadget/usb338x.c
> new file mode 100644
> index 0000000..e9eabd7
> --- /dev/null
> +++ b/drivers/usb/gadget/usb338x.c
> @@ -0,0 +1,4493 @@
> +/******************************************************************************
> + * Driver for PLX USB3380/USB3382 USB device controller
> + *
> + * Copyright (c) PLX Technology, Inc.
> + *
> + * PLX Technology Inc. licenses this source file under the GNU Lesser General
> + * Public License (LGPL) version 2.  This program is free software; the source
> + * file may be modified or redistributed under the terms of the LGPL and
> + * without express permission from PLX Technology.
> + *
> + * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
> + * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  PLX makes no guarantee
> + * or representations regarding the use of, or the results of the use of,
> + * the software and documentation in terms of correctness, accuracy,
> + * reliability, currentness, or otherwise; and you rely on the software,
> + * documentation and results solely at your own risk.
> + *
> + * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
> + * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
> + * OF ANY KIND.
> + *
> + * Specs and errata are available from http://www.plxtech.com.
> + *
> + ******************************************************************************/
> +
> +/******************************************************************************
> + *
> + * File Name:
> + *
> + *     usb338x.c
> + *
> + * Revision: v3.0, 2-5-2014
> + *
> + * Description:
> + *
> + *     Initializes the driver and claims system resources for USB3 and USB2 on
> + *     Linux kernel version 3.8.
> + *
> + *     This driver works with most Linux gadget drivers, including
> + *     the File Storage, Serial, and Ethernet/RNDIS gadget drivers
> + *     as well as Gadget Zero and Gadgetfs.
> + *
> + *     MSI is enabled by default.  The legacy IRQ is used if MSI couldn't
> + *     be enabled.  DMA is enabled by default.  Drivers using transfer
> + *     queues might use DMA chaining to remove IRQ latencies between
> + *     transfers excep when short OUT transfers happen.
> + *
> + *****************************************************************************/
> +
> +#undef  DEBUG       /* messages on error and most fault paths */
> +#undef  VERBOSE     /* extra debug messages (success too) */
> +
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/ioport.h>
> +#include <linux/slab.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/timer.h>
> +#include <linux/list.h>
> +#include <linux/interrupt.h>
> +#include <linux/moduleparam.h>
> +#include <linux/device.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <linux/prefetch.h>
> +
> +#include <asm/byteorder.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/unaligned.h>
> +
> +#define  DEBUG
> +#define  VERBOSE
> +
> +#define DRIVER_DESC     "PLX USB3380/USB3382 USB Peripheral Controller"
> +#define DRIVER_VERSION  "usb3380/usb3382 v3.0"
> +
> +#define DMA_ADDR_INVALID    (~(dma_addr_t)0)
> +#define EP_DONTUSE          13  /* nonzero */
> +
> +#define USE_RDK_LEDS        /* GPIO pins control three LEDs */
> +
> +static const char driver_name [] = "usb338x";
> +static const char driver_desc [] = DRIVER_DESC;
> +
> +static const char ep0name [] = "ep0";
> +static const char *const ep_name [9] =
> +{
> +    ep0name,
> +    "ep-1", "ep-2", "ep-3", "ep-4",
> +    "ep-5", "ep-6", "ep-7", "ep-8",
> +};
> +
> +static unsigned int u32_i = 0;
> +static int enhanced_mode = 1;
> +static int n_ep = 5;
> +
> +#define     FIFO_SIZE_64                0
> +#define     FIFO_SIZE_128               1
> +#define     FIFO_SIZE_256               2
> +#define     FIFO_SIZE_512               3
> +#define     FIFO_SIZE_1024              4
> +#define     FIFO_SIZE_2048              5
> +#define     FIFO_SIZE_4096              6
> +
> +/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
> + * use_dma_chaining -- dma descriptor queueing gives even more irq reduction
> + *
> + * The usb338x DMA engines are not tightly integrated with their FIFOs;
> + * not all cases are (yet) handled well in this driver or the silicon.
> + * Some gadget drivers work better with the dma support here than others.
> + * These two parameters let you use PIO or more aggressive DMA.
> + */
> +static bool use_dma = 1;
> +static bool use_dma_chaining = 0;
> +static bool use_msi   = 1;
> +
> +/* "modprobe usb338x use_dma=n" etc */
> +module_param (use_msi, bool, S_IRUGO);
> +module_param (use_dma, bool, S_IRUGO);
> +module_param (use_dma_chaining, bool, S_IRUGO);
> +
> +/* enable_suspend -- When enabled, the driver will respond to
> + * USB suspend requests by powering down the usb338x.  Otherwise,
> + * USB suspend requests will be ignored.  This is acceptable for
> + * self-powered devices
> + */
> +static bool enable_suspend = 0;
> +
> +/* "modprobe usb338x enable_suspend=1" etc */
> +module_param (enable_suspend, bool, S_IRUGO);
> +
> +#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
> +
> +#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG)
> +static char *type_string (u8 bmAttributes)
> +{
> +    switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK)
> +    {
> +    case USB_ENDPOINT_XFER_BULK:    return "bulk";
> +    case USB_ENDPOINT_XFER_ISOC:    return "iso";
> +    case USB_ENDPOINT_XFER_INT:     return "intr";
> +    };
> +    return "control";
> +}
> +#endif
> +
> +#include "usb338x.h"
> +
> +#define valid_bit   cpu_to_le32 (1 << VALID_BIT)
> +#define dma_done_ie cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
> +
> +static u32 ep_bit[9]      = {0, 17, 2, 19, 4, 1, 18, 3, 20};
> +static u32 ep_key[9]      = {1, 0, 1, 0, 1, 1, 0, 1, 0};
> +static u32 ep_enhanced[9] = {0x10, 0x60, 0x30, 0x80, 0x50, 0x20, 0x70, 0x40, 0x90};
> +static u32 ep_legacy[5]   = {0x10, 0x20, 0x30, 0x40, 0x50};
> +static u32 ne[9]          = {0, 1, 2, 3, 4, 1, 2, 3, 4};
> +static u32 ep_reg_addr[9] = {0x00, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0xC0};
> +static u32 ep_pl[9]       = {0, 3, 4, 7, 8, 2, 5, 6, 9};
> +
> +static u32 u32_pciirqenb1;
> +/*-------------------------------------------------------------------------*/
> +
> +#ifdef  CONFIG_USB_GADGET_DEBUG_FILES
> +
> +/* FIXME move these into procfs, and use seq_file.
> + * Sysfs _still_ doesn't behave for arbitrarily sized files,
> + * and also doesn't help products using this with 2.4 kernels.
> + */
> +
> +/* "function" sysfs attribute */
> +static ssize_t
> +show_function (struct device *_dev, struct device_attribute *attr, char *buf)
> +{
> +    struct usb338x  *dev = dev_get_drvdata (_dev);
> +
> +    if (!dev->driver
> +            || !dev->driver->function
> +            || strlen (dev->driver->function) > PAGE_SIZE)
> +        return 0;
> +
> +    return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
> +}
> +static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
> +
> +
> +static ssize_t
> +usb338x_show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
> +{
> +    struct usb338x      *dev;
> +    char                *next;
> +    unsigned            size, t;
> +    unsigned long       flags;
> +    int                 i;
> +    u32                 t1, t2;
> +    const char          *s;
> +
> +    dev = dev_get_drvdata (_dev);
> +    next = buf;
> +    size = PAGE_SIZE;
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    if (dev->driver)
> +        s = dev->driver->driver.name;
> +    else
> +        s = "(none)";
> +
> +    /* Main Control Registers */
> +    t = scnprintf (next, size, "%s version " DRIVER_VERSION
> +                   ", chiprev %04x, dma %s\n\n"
> +                   "devinit %03x fifoctl %08x gadget '%s'\n"
> +                   "pci irqenb0 %02x irqenb1 %08x "
> +                   "irqstat0 %04x irqstat1 %08x\n",
> +                   driver_name, dev->chiprev,
> +                   use_dma
> +                   ? (use_dma_chaining ? "chaining" : "enabled")
> +                       : "disabled",
> +                       readl (&dev->regs->devinit),
> +                       readl (&dev->regs->fifoctl),
> +                       s,
> +                       readl (&dev->regs->pciirqenb0),
> +                       readl (&dev->regs->pciirqenb1),
> +                       readl (&dev->regs->irqstat0),
> +                       readl (&dev->regs->irqstat1));
> +    size -= t;
> +    next += t;
> +
> +    /* USB Control Registers */
> +    t1 = readl (&dev->usb->usbctl);
> +    t2 = readl (&dev->usb->usbstat);
> +
> +    if (t1 & (1 << VBUS_PIN))
> +    {
> +        if (t2 & (1 << HIGH_SPEED_MODE))
> +            s = "high speed";
> +        else if (dev->gadget.speed == USB_SPEED_UNKNOWN)
> +            s = "powered";
> +        else
> +            s = "full speed";
> +        /* full speed bit (6) not working?? */
> +    }
> +    else
> +        s = "not attached";
> +
> +    t = scnprintf (next, size,
> +                   "stdrsp %08x usbctl %08x usbstat %08x "
> +                   "addr 0x%02x (%s)\n",
> +                   readl (&dev->usb->stdrsp), t1, t2,
> +                   readl (&dev->usb->ouraddr), s);
> +    size -= t;
> +    next += t;
> +
> +    /* PCI Master Control Registers */
> +
> +    /* DMA Control Registers */
> +
> +    /* Configurable EP Control Registers */
> +    for (i = 0; i < n_ep; i++)
> +    {
> +        struct usb338x_ep   *ep;
> +
> +        ep = &dev->ep [i];
> +
> +        if (i && !ep->desc)
> +            continue;
> +
> +        t1 = readl (&ep->cfg->ep_cfg);
> +        t2 = readl (&ep->regs->ep_rsp) & 0xff;
> +        t = scnprintf (next, size,
> +                       "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
> +                       "irqenb %02x\n",
> +                       ep->ep.name, t1, t2,
> +                       (t2 & (1 << CLEAR_NAK_OUT_PACKETS))
> +                       ? "NAK " : "",
> +                       (t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE))
> +                       ? "hide " : "",
> +                       (t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR))
> +                       ? "CRC " : "",
> +                       (t2 & (1 << CLEAR_INTERRUPT_MODE))
> +                       ? "interrupt " : "",
> +                       (t2 & (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE))
> +                       ? "status " : "",
> +                       (t2 & (1 << CLEAR_NAK_OUT_PACKETS_MODE))
> +                       ? "NAKmode " : "",
> +                       (t2 & (1 << CLEAR_ENDPOINT_TOGGLE))
> +                       ? "DATA1 " : "DATA0 ",
> +                       (t2 & (1 << CLEAR_ENDPOINT_HALT))
> +                       ? "HALT " : "",
> +                       readl (&ep->regs->ep_irqenb));
> +        size -= t;
> +        next += t;
> +
> +        t = scnprintf (next, size,
> +                       "\tstat %08x avail %04x "
> +                       "(ep%d%s-%s)%s\n",
> +                       readl (&ep->regs->ep_stat),
> +                       readl (&ep->regs->ep_avail),
> +                       t1 & 0x0f, DIR_STRING (t1),
> +                       type_string (t1 >> 8),
> +                       ep->stopped ? "*" : "");
> +        size -= t;
> +        next += t;
> +
> +        if (!ep->dma)
> +            continue;
> +
> +        t = scnprintf (next, size,
> +                       "  dma\tctl %08x stat %08x count %08x\n"
> +                       "\taddr %08x desc %08x\n",
> +                       readl (&ep->dma->dmactl),
> +                       readl (&ep->dma->dmastat),
> +                       readl (&ep->dma->dmacount),
> +                       readl (&ep->dma->dmaaddr),
> +                       readl (&ep->dma->dmadesc));
> +        size -= t;
> +        next += t;
> +
> +    }
> +
> +    /* Indexed Registers */
> +    // none yet
> +
> +    /* Statistics */
> +    t = scnprintf (next, size, "\nirqs:  ");
> +    size -= t;
> +    next += t;
> +
> +    for (i = 0; i < n_ep; i++)
> +    {
> +        struct usb338x_ep   *ep;
> +
> +        ep = &dev->ep [i];
> +
> +        if (i && !ep->irqs)
> +            continue;
> +
> +        t = scnprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs);
> +        size -= t;
> +        next += t;
> +
> +    }
> +
> +    t = scnprintf (next, size, "\n");
> +    size -= t;
> +    next += t;
> +
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    return PAGE_SIZE - size;
> +}
> +static DEVICE_ATTR(registers, S_IRUGO, usb338x_show_registers, NULL);
> +
> +
> +static ssize_t
> +show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
> +{
> +    struct usb338x      *dev;
> +    char                *next;
> +    unsigned            size;
> +    unsigned long       flags;
> +    int                 i;
> +
> +    dev = dev_get_drvdata (_dev);
> +    next = buf;
> +    size = PAGE_SIZE;
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    for (i = 0; i < n_ep; i++)
> +    {
> +        struct usb338x_ep       *ep = &dev->ep [i];
> +        struct usb338x_request  *req;
> +        int                     t;
> +
> +        if (i != 0)
> +        {
> +            const struct usb_endpoint_descriptor    *d;
> +
> +            d = ep->desc;
> +
> +            if (!d)
> +                continue;
> +
> +            t = d->bEndpointAddress;
> +            t = scnprintf (next, size,
> +                           "\n%s (ep%d%s-%s) max %04x %s fifo %d\n",
> +                           ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
> +                           (t & USB_DIR_IN) ? "in" : "out",
> +                           ( {  char *val;
> +                                switch (d->bmAttributes & 0x03)
> +                                {
> +                                case USB_ENDPOINT_XFER_BULK:
> +                                    val = "bulk"; break;
> +                                case USB_ENDPOINT_XFER_INT:
> +                                    val = "intr"; break;
> +                                default:
> +                                    val = "iso"; break;
> +                                }; val;
> +                         } ),
> +        usb_endpoint_maxp (d) & 0x1fff,
> +        ep->dma ? "dma" : "pio", ep->fifo_size
> +                      );
> +        }
> +        else   /* ep0 should only have one transfer queued */
> +            t = scnprintf (next, size, "ep0 max 64 pio %s\n",
> +                           ep->is_in ? "in" : "out");
> +        if (t <= 0 || t > size)
> +            goto done;
> +
> +        size -= t;
> +        next += t;
> +
> +        if (list_empty (&ep->queue))
> +        {
> +            t = scnprintf (next, size, "\t(nothing queued)\n");
> +
> +            if (t <= 0 || t > size)
> +                goto done;
> +
> +            size -= t;
> +            next += t;
> +            continue;
> +
> +        }
> +
> +        list_for_each_entry (req, &ep->queue, queue)
> +        {
> +            if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc))
> +                t = scnprintf (next, size,
> +                               "\treq %p len %d/%d "
> +                               "buf %p (dmacount %08x)\n",
> +                               &req->req, req->req.actual,
> +                               req->req.length, req->req.buf,
> +                               readl (&ep->dma->dmacount));
> +            else
> +                t = scnprintf (next, size,
> +                               "\treq %p len %d/%d buf %p\n",
> +                               &req->req, req->req.actual,
> +                               req->req.length, req->req.buf);
> +            if (t <= 0 || t > size)
> +                goto done;
> +
> +            size -= t;
> +            next += t;
> +
> +            if (ep->dma)
> +            {
> +                struct usb338x_dma  *td;
> +
> +                td = req->td;
> +                t = scnprintf (next, size, "\t    td %08x "
> +                               " count %08x buf %08x desc %08x\n",
> +                               (u32) req->td_dma,
> +                               le32_to_cpu (td->dmacount),
> +                               le32_to_cpu (td->dmaaddr),
> +                               le32_to_cpu (td->dmadesc));
> +
> +                if (t <= 0 || t > size)
> +                    goto done;
> +
> +                size -= t;
> +                next += t;
> +            }
> +        }
> +    }
> +
> +done:
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    return PAGE_SIZE - size;
> +}
> +static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
> +
> +
> +#else
> +
> +#define device_create_file(a,b) (0)
> +#define device_remove_file(a,b) do { } while (0)
> +
> +#endif
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static void write_fifo (struct usb338x_ep *ep, struct usb_request *req);
> +static void complete_req (struct usb338x_ep *ep, struct usb338x_request *req, int status);
> +static void scan_dma_completions (struct usb338x_ep *ep);
> +static inline void spin_stop_dma (struct usb338x_dma_regs __iomem *dma);
> +static inline void dma_done (struct usb338x_ep *ep, struct usb338x_request *req, u32 dmacount, int status);
> +static void out_flush (struct usb338x_ep *ep);
> +static void  restart_dma (struct usb338x_ep *ep);
> +static int read_fifo (struct usb338x_ep *ep, struct usb338x_request *req);
> +static void abort_dma (struct usb338x_ep *ep);
> +
> +/* handle with 64 byte packets: packet per irq.
> + * also works for dma-capable endpoints, in pio mode or just
> + * to manually advance the queue after short OUT transfers.
> + */
> +static void
> +handle_ep_small (struct usb338x_ep *ep)
> +{
> +    struct usb338x_request  *req;
> +    u32                     t;
> +    /* 0 error, 1 mid-data, 2 done */
> +    int                     mode = 1;
> +
> +    if (!list_empty (&ep->queue))
> +        req = list_entry (ep->queue.next,
> +                          struct usb338x_request, queue);
> +    else
> +        req = NULL;
> +
> +    /* ack all, and handle what we care about */
> +    t = readl (&ep->regs->ep_stat);
> +
> +    ep->irqs++;
> +
> +#if 0
> +    VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",
> +            ep->ep.name, t, req ? &req->req : 0);
> +#endif
> +
> +    if (!ep->is_in)
> +    {
> +        writel (t & ~(1 << NAK_PACKETS), &ep->regs->ep_stat);
> +    }
> +    else
> +    {
> +        /* Added for 2282 */
> +        writel (t, &ep->regs->ep_stat);
> +    }
> +
> +    /* for ep0, monitor token irqs to catch data stage length errors
> +     * and to synchronize on status.
> +     *
> +     * also, to defer reporting of protocol stalls ... here's where
> +     * data or status first appears, handling stalls here should never
> +     * cause trouble on the host side..
> +     *
> +     * control requests could be slightly faster without token synch for
> +     * status, but status can jam up that way.
> +     */
> +    if (unlikely (ep->num == 0))
> +    {
> +        if (ep->is_in)
> +        {
> +            /* status; stop NAKing */
> +            if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT))
> +            {
> +                if (ep->dev->protocol_stall)
> +                {
> +                    ep->stopped = 1;
> +
> +                    writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                              ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
> +                              (1 << SET_ENDPOINT_HALT),
> +                              &ep->regs->ep_rsp);
> +                }
> +
> +                if (!req)
> +                {
> +                    writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                              (1 << CLEAR_NAK_OUT_PACKETS) |
> +                              (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                              &ep->regs->ep_rsp);
> +
> +                    ep->stopped = 1;
> +                }
> +
> +                mode = 2;
> +                /* reply to extra IN data tokens with a zlp */
> +            }
> +            else if (t & (1 << DATA_IN_TOKEN_INTERRUPT))
> +            {
> +                if (ep->dev->protocol_stall)
> +                {
> +                    ep->stopped = 1;
> +
> +                    writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                              ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
> +                              (1 << SET_ENDPOINT_HALT),
> +                              &ep->regs->ep_rsp);
> +
> +                    mode = 2;
> +                }
> +                else if (ep->responded &&
> +                         !req && !ep->stopped)
> +                    write_fifo (ep, NULL);
> +            }
> +        }
> +        else
> +        {
> +            /* status; stop NAKing */
> +            if (t & (1 << DATA_IN_TOKEN_INTERRUPT))
> +            {
> +                if (ep->dev->protocol_stall)
> +                {
> +                    ep->stopped = 1;
> +
> +                    writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                              ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
> +                              (1 << SET_ENDPOINT_HALT),
> +                              &ep->regs->ep_rsp);
> +                }
> +                mode = 2;
> +                /* an extra OUT token is an error */
> +            }
> +            else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT))
> +                      && req
> +                      && req->req.actual == req->req.length)
> +                     || (ep->responded && !req))
> +            {
> +                ep->dev->protocol_stall = 1;
> +
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
> +                          (1 << SET_ENDPOINT_HALT),
> +                          &ep->regs->ep_rsp);
> +
> +                ep->stopped = 1;
> +
> +                if (req)
> +                    complete_req (ep, req, -EOVERFLOW);
> +
> +                req = NULL;
> +            }
> +        }
> +    }
> +
> +    if (unlikely (!req))
> +        return;
> +
> +    /* manual DMA queue advance after short OUT */
> +    if (likely (ep->dma != 0))
> +    {
> +        if (t & (1 << SHORT_OUT_PACKET_RECEIVED_INTERRUPT))
> +        {
> +            u32 count;
> +            int stopped = ep->stopped;
> +
> +            /* TRANSFERRED works around OUT_DONE erratum 0112.
> +             * we expect (N <= maxpacket) bytes; host wrote M.
> +             * iff (M < N) we won't ever see a DMA interrupt.
> +             */
> +            ep->stopped = 1;
> +
> +            for (count = 0; ; t = readl (&ep->regs->ep_stat))
> +            {
> +
> +                /* any preceding dma transfers must finish.
> +                 * dma handles (M >= N), may empty the queue
> +                 */
> +                scan_dma_completions (ep);
> +                if (unlikely (list_empty (&ep->queue)
> +                              || ep->out_overflow))
> +                {
> +                    req = NULL;
> +                    break;
> +                }
> +                req = list_entry (ep->queue.next,
> +                                  struct usb338x_request, queue);
> +
> +                /* here either (M < N), a "real" short rx;
> +                 * or (M == N) and the queue didn't empty
> +                 */
> +                if (likely (t & (1 << FIFO_EMPTY)))
> +                {
> +                    count = readl (&ep->dma->dmacount);
> +                    count &= DMA_TRANSFER_MAX_LENGTH;
> +
> +                    if (readl (&ep->dma->dmadesc) != req->td_dma)
> +                        req = NULL;
> +
> +                    break;
> +                }
> +                udelay(1);
> +            }
> +
> +            /* stop DMA, leave ep NAKing */
> +            writel ((1 << DMA_ABORT), &ep->dma->dmastat);
> +            spin_stop_dma (ep->dma);
> +
> +            if (likely (req))
> +            {
> +                req->td->dmacount = 0;
> +                t = readl (&ep->regs->ep_avail);
> +                dma_done (ep, req, count,
> +                          (ep->out_overflow || t)
> +                          ? -EOVERFLOW : 0);
> +            }
> +
> +            /* also flush to prevent erratum 0106 trouble */
> +            if (unlikely (ep->out_overflow
> +                          || (ep->dev->chiprev == 0x0100
> +                              && ep->dev->gadget.speed
> +                              == USB_SPEED_FULL)))
> +            {
> +                out_flush (ep);
> +                ep->out_overflow = 0;
> +            }
> +
> +            /* (re)start dma if needed, stop NAKing */
> +            ep->stopped = stopped;
> +
> +            if (!list_empty (&ep->queue))
> +                restart_dma (ep);
> +        }
> +        else
> +            DEBUG (ep->dev, "%s dma ep_stat %08x ??\n",
> +                   ep->ep.name, t);
> +
> +        return;
> +
> +        /* data packet(s) received (in the fifo, OUT) */
> +    }
> +    else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT))
> +    {
> +        if (read_fifo (ep, req) && ep->num != 0)
> +            mode = 2;
> +
> +        /* data packet(s) transmitted (IN) */
> +    }
> +    else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))
> +    {
> +        unsigned    len;
> +
> +        len = req->req.length - req->req.actual;
> +
> +        if (len > ep->ep.maxpacket)
> +            len = ep->ep.maxpacket;
> +
> +        req->req.actual += len;
> +
> +        /* if we wrote it all, we're usually done */
> +        if (req->req.actual == req->req.length)
> +        {
> +            if (ep->num == 0)
> +            {
> +                /* send zlps until the status stage */
> +            }
> +            else if (!req->req.zero || len != ep->ep.maxpacket)
> +                mode = 2;
> +        }
> +
> +        /* there was nothing to do ...  */
> +    }
> +    else if (mode == 1)
> +        return;
> +
> +    /* done */
> +    if (mode == 2)
> +    {
> +        /* stream endpoints often resubmit/unlink in completion */
> +        complete_req (ep, req, 0);
> +
> +        /* maybe advance queue to next request */
> +        if (ep->num == 0)
> +        {
> +            /* NOTE:  usb338x could let gadget driver start the
> +             * status stage later. since not all controllers let
> +             * them control that, the api doesn't (yet) allow it.
> +             */
> +            if (!ep->stopped)
> +            {
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                          &ep->regs->ep_rsp);
> +
> +                ep->stopped = 1;
> +            }
> +
> +            req = NULL;
> +        }
> +        else
> +        {
> +            if (!list_empty (&ep->queue) && !ep->stopped)
> +                req = list_entry (ep->queue.next,
> +                                  struct usb338x_request, queue);
> +            else
> +                req = NULL;
> +
> +            if (req && !ep->is_in)
> +            {
> +                u32 reg_value;
> +
> +                reg_value = readl (&ep->regs->ep_stat);
> +
> +                if ((reg_value & (1 << NAK_PACKETS)) != 0)
> +                    writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
> +            }
> +        }
> +    }
> +
> +    /* is there a buffer for the next packet?
> +     * for best streaming performance, make sure there is one.
> +     */
> +    if (req && !ep->stopped)
> +    {
> +
> +        /* load IN fifo with next packet (may be zlp) */
> +        if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))
> +            write_fifo (ep, &req->req);
> +    }
> +}
> +
> +
> +static struct usb338x_ep *
> +get_ep_by_addr (struct usb338x *dev, u16 wIndex)
> +{
> +    struct usb338x_ep   *ep;
> +
> +    if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
> +        return &dev->ep [0];
> +
> +    list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list)
> +    {
> +        u8  bEndpointAddress;
> +
> +        if (!ep->desc)
> +            continue;
> +
> +        bEndpointAddress = ep->desc->bEndpointAddress;
> +
> +        if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
> +            continue;
> +
> +        if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f))
> +            return ep;
> +    }
> +
> +    return NULL;
> +}
> +
> +
> +static void Defect7374_DisableDataEps (struct usb338x *dev);
> +static void set_fifo_bytecount (struct usb338x_ep *ep, unsigned count);
> +static void allow_status (struct usb338x_ep *ep);
> +static void ep_stdrsp (struct usb338x_ep *ep, int value, int wedged);
> +static void ep_stall (struct usb338x_ep *ep, int stall);
> +static void resume_dma (struct usb338x_ep *ep);
> +static void ep_stop_dma (struct usb338x_ep *ep);
> +
> +
> +static void
> +handle_stat0_irqs (struct usb338x *dev, u32 stat)
> +{
> +    struct usb338x_ep   *ep;
> +    u32                 num, scratch;
> +    u32                 value;
> +    u32                 reg_value;
> +    u32                 Scratch, FsmValue;
> +    u32                 AckWaitTimeout, State;
> +
> +    /* most of these don't need individual acks */
> +    stat &= ~(1 << INTA_ASSERTED);
> +
> +    if (!stat)
> +        return;
> +
> +    // DEBUG (dev, "irqstat0 %04x\n", stat);
> +
> +    /* starting a control request? */
> +    if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT_STATUS)))
> +    {
> +        union
> +        {
> +            u32                     raw [2];
> +            struct usb_ctrlrequest  r;
> +        } u;
> +
> +        int                         tmp;
> +        struct usb338x_request      *req;
> +        u32                         val;
> +
> +        if (dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        {
> +            val = readl (&dev->usb->usbstat);
> +
> +            if (val & (1 << SUPER_SPEED_MODE))
> +            {
> +                dev->gadget.speed = USB_SPEED_SUPER;
> +                dev->ep[0].ep.maxpacket = EP0_SS_MAX_PACKET_SIZE;
> +            }
> +            else if (val & (1 << HIGH_SPEED_MODE))
> +            {
> +                dev->gadget.speed = USB_SPEED_HIGH;
> +                dev->ep[0].ep.maxpacket = EP0_HS_MAX_PACKET_SIZE;
> +            }
> +            else
> +            {
> +                dev->gadget.speed = USB_SPEED_FULL;
> +                dev->ep[0].ep.maxpacket = EP0_HS_MAX_PACKET_SIZE;
> +            }
> +
> +            value = readl (&dev->regs->gpioctl);
> +
> +            switch (dev->gadget.speed)
> +            {
> +            case USB_SPEED_HIGH:        /* green */
> +                value &= ~(1 << GPIO0_DATA);
> +                value |= (1 << GPIO1_DATA);
> +
> +                break;
> +
> +            case USB_SPEED_FULL:        /* red */
> +                value &= ~(1 << GPIO1_DATA);
> +                value |= (1 << GPIO0_DATA);
> +
> +                break;
> +
> +            default:            /* (off/black) */
> +                value &= ~((1 << GPIO1_DATA) | (1 << GPIO0_DATA));
> +
> +                break;
> +            }
> +
> +            writel (value, &dev->regs->gpioctl);
> +
> +            DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed));
> +        }
> +
> +        ep = &dev->ep [0];
> +        ep->irqs++;
> +
> +        /* make sure any leftover request state is cleared */
> +        stat &= ~(1 << ENDPOINT_0_INTERRUPT_STATUS);
> +
> +        while (!list_empty (&ep->queue))
> +        {
> +            req = list_entry (ep->queue.next,
> +                              struct usb338x_request, queue);
> +
> +            complete_req (ep, req, (req->req.actual == req->req.length)
> +                          ? 0 : -EPROTO);
> +        }
> +
> +        ep->stopped = 0;
> +        ep->is_halt = 0;
> +        dev->protocol_stall = 0;
> +
> +#if 0
> +        tmp = 0;
> +
> +        writel (tmp | (1 << TIMEOUT)
> +                | (1 << USB_STALL_SENT)
> +                | (1 << USB_IN_NAK_SENT)
> +                | (1 << USB_IN_ACK_RCVD)
> +                | (1 << USB_OUT_NAK_SENT)
> +                | (1 << USB_OUT_ACK_SENT)
> +                | (1 << SHORT_OUT_PACKET_DONE_INTERRUPT)
> +                | (1 << SHORT_OUT_PACKET_RECEIVED_INTERRUPT)
> +                | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
> +                | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
> +                | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
> +                | (1 << DATA_IN_TOKEN_INTERRUPT)
> +                , &ep->regs->ep_stat);
> +#endif
> +
> +        u.raw [0] = readl (&dev->usb->setupdw0);
> +        u.raw [1] = readl (&dev->usb->setupdw1);
> +
> +        cpu_to_le32s (&u.raw [0]);
> +        cpu_to_le32s (&u.raw [1]);
> +
> +        tmp = 0;
> +
> +#define w_value     le16_to_cpu(u.r.wValue)
> +#define w_index     le16_to_cpu(u.r.wIndex)
> +#define w_length    le16_to_cpu(u.r.wLength)
> +
> +        /* Workaround for Defect 7374 (U1/U2 erroneously rejected): */
> +        writel (SCRATCH, &dev->regs->idxaddr);
> +        Scratch = readl (&dev->regs->idxdata);
> +
> +        FsmValue = Scratch & 0xf << DEFECT7374_FSM_FIELD;
> +        Scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
> +
> +        if ((FsmValue == DEFECT7374_FSM_WAITING_FOR_CONTROL_READ) &&
> +                (u.r.bRequestType & USB_DIR_IN))
> +        {
> +            /* This is the first Control Read for this connection: */
> +            if ( readl(&dev->usb->usbstat) & ( 1 << SUPER_SPEED_MODE))
> +            {
> +
> +                // Connection is SS:
> +                for (AckWaitTimeout = 0; AckWaitTimeout < DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS; AckWaitTimeout++)
> +                {
> +                    State = readl (&dev->plregs->pl_ep_status_1) & (0xff << STATE);
> +
> +                    if ((State >= (ACK_GOOD_NORMAL << STATE)) && (State <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE)))
> +                    {
> +                        Scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
> +
> +                        break;
> +                    }
> +
> +                    // We have not yet received host's Data Phase ACK
> +                    //  - Wait and try again.
> +                    udelay (DEFECT_7374_PROCESSOR_WAIT_TIME);
> +
> +                    continue;
> +                }
> +
> +                printk ("INFO: Defect 7374 workaround waited about %duSec for Control Read Data Phase ACK\n", DEFECT_7374_PROCESSOR_WAIT_TIME * AckWaitTimeout);
> +
> +                if (AckWaitTimeout >= DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS)
> +                    printk ("FAIL: Defect 7374 workaround waited but failed to detect SS host's data phase ACK. PL_EP_STATUS_1(23:16): Expected from 0x11 to 0x16 got 0x%2.2x.\n", State >> STATE);
> +            }
> +            else
> +            {
> +                // Connection is NOT SS:
> +                //  - Connection must be FS or HS.
> +                //  - This FSM state should allow workaround software to
> +                // run after the next USB connection.
> +                Scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
> +            }
> +
> +            // Restore data EPs to their pre-workaround settings (disabled,
> +            // initialized, and other details).
> +            Defect7374_DisableDataEps (dev);
> +
> +            writel (SCRATCH, &dev->regs->idxaddr);
> +            writel (Scratch, &dev->regs->idxdata);
> +        }
> +
> +        /* ack the irq */
> +        writel (1 << SETUP_PACKET_INTERRUPT_STATUS, &dev->regs->irqstat0);
> +        stat ^= (1 << SETUP_PACKET_INTERRUPT_STATUS);
> +
> +        /* watch control traffic at the token level, and force
> +         * synchronization before letting the status stage happen.
> +         * FIXME ignore tokens we'll NAK, until driver responds.
> +         * that'll mean a lot less irqs for some drivers.
> +         */
> +        ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
> +
> +        if (ep->is_in)
> +        {
> +            scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
> +                      | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
> +                      | (1 << DATA_IN_TOKEN_INTERRUPT);
> +
> +            reg_value = readl (&ep->regs->ep_stat);
> +
> +            if ((reg_value & (1 << NAK_PACKETS)) != 0)
> +                writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
> +        }
> +        else
> +            scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT)
> +                      | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
> +                      | (1 << DATA_IN_TOKEN_INTERRUPT);
> +
> +        writel (scratch, &dev->epregs [0].ep_irqenb);
> +
> +        /* we made the hardware handle most lowlevel requests;
> +         * everything else goes uplevel to the gadget code.
> +         */
> +        ep->responded = 1;
> +
> +        if (dev->gadget.speed == USB_SPEED_SUPER)
> +        {
> +            switch (u.r.bRequest)
> +            {
> +                struct usb338x_ep   *e;
> +                u16                 status;
> +
> +            case USB_REQ_SET_CONFIGURATION:
> +
> +                if (w_value == 0)
> +                {
> +                    dev->addressed_state = true;
> +                }
> +                else
> +                {
> +                    dev->addressed_state = false;
> +                }
> +
> +                goto usb3_delegate;
> +
> +            case USB_REQ_GET_STATUS:
> +
> +                switch (u.r.bRequestType)
> +                {
> +
> +                case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
> +
> +                    status = dev->wakeup_enable ? 0x02 : 0x00;
> +
> +                    if (dev->selfpowered)
> +                    {
> +                        status |= 1 << 0;
> +                    }
> +
> +                    if (dev->gadget.speed == USB_SPEED_SUPER)
> +                    {
> +                        status |= ( dev->u1_enable << 2 |
> +                                    dev->u2_enable << 3 |
> +                                    dev->ltm_enable << 4);
> +                    }
> +                    else if (dev->wakeup_enable)
> +                    {
> +                        status |= 0x01;
> +                    }
> +
> +                    writel (0, &dev->epregs[0].ep_irqenb);
> +
> +                    set_fifo_bytecount (ep, sizeof(status));
> +
> +                    writel ((__force u32)status, &dev->epregs[0].ep_data);
> +
> +                    allow_status(ep);
> +
> +                    break;
> +
> +                case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT):
> +
> +                    e = get_ep_by_addr (dev, w_index);
> +
> +                    if (!e)
> +                    {
> +                        goto do_stall;
> +                    }
> +
> +                    status = readl (&e->regs->ep_rsp) &
> +                             (1 << CLEAR_ENDPOINT_HALT);
> +
> +                    writel (0, &dev->epregs [0].ep_irqenb);
> +
> +                    set_fifo_bytecount(ep, sizeof(status));
> +
> +                    writel ((__force u32)status, &dev->epregs[0].ep_data);
> +
> +                    allow_status(ep);
> +
> +                    break;
> +
> +                default:
> +                    goto usb3_delegate;
> +                }
> +
> +                break;
> +
> +            case USB_REQ_CLEAR_FEATURE:
> +
> +                switch (u.r.bRequestType)
> +                {
> +
> +                case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
> +
> +                    if (dev->gadget.speed == USB_SPEED_SUPER && !dev->addressed_state)
> +                    {
> +                        switch (w_value)
> +                        {
> +
> +                        case USB_DEVICE_U1_ENABLE:
> +
> +                            dev->u1_enable = 0;
> +
> +                            writel (readl(&dev->usb->usbctl2) &
> +                                    ~(1 << U1_ENABLE),
> +                                    &dev->usb->usbctl2);
> +
> +                            allow_status(ep);
> +
> +                            goto next_endpoints;
> +
> +                        case USB_DEVICE_U2_ENABLE:
> +
> +                            dev->u2_enable = 0;
> +
> +                            writel (readl(&dev->usb->usbctl2) &
> +                                    ~(1 << U2_ENABLE),
> +                                    &dev->usb->usbctl2);
> +
> +                            allow_status(ep);
> +
> +                            goto next_endpoints;
> +
> +                        case USB_DEVICE_LTM_ENABLE:
> +
> +                            dev->ltm_enable = 0;
> +
> +                            writel (readl(&dev->usb->usbctl2) &
> +                                    ~(1 << LTM_ENABLE),
> +                                    &dev->usb->usbctl2);
> +
> +                            allow_status(ep);
> +
> +                            goto next_endpoints;
> +
> +                        default:
> +                            break;
> +                        }
> +                    }
> +
> +                    if (w_value == USB_DEVICE_REMOTE_WAKEUP)
> +                    {
> +                        dev->wakeup_enable = 0;
> +
> +                        writel (readl(&dev->usb->usbctl) &
> +                                ~(1 << REMOTE_WAKEUP_ENABLE),
> +                                &dev->usb->usbctl);
> +
> +                        allow_status(ep);
> +
> +                        break;
> +                    }
> +
> +                    goto usb3_delegate;
> +
> +                case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT):
> +
> +                    e = get_ep_by_addr (dev, w_index);
> +
> +                    if (!e)
> +                        goto do_stall;
> +
> +                    if (w_value != USB_ENDPOINT_HALT)
> +                        goto do_stall;
> +
> +                    VDEBUG(dev, "%s clear halt\n", e->ep.name);
> +
> +                    ep_stall (e, false);
> +
> +                    if (!list_empty(&e->queue) && e->td_dma)
> +                    {
> +                        restart_dma (e);
> +                    }
> +
> +                    writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                              (1 << CLEAR_NAK_OUT_PACKETS) |
> +                              (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                              &ep->regs->ep_rsp);
> +
> +                    ep->stopped = 1;
> +
> +                    break;
> +
> +                default:
> +                    goto usb3_delegate;
> +                }
> +
> +                break;
> +
> +            case USB_REQ_SET_FEATURE:
> +
> +                switch (u.r.bRequestType)
> +                {
> +
> +                case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
> +
> +                    if (dev->gadget.speed == USB_SPEED_SUPER && !dev->addressed_state)
> +                    {
> +                        switch (w_value)
> +                        {
> +
> +                        case USB_DEVICE_U1_ENABLE:
> +
> +                            dev->u1_enable = 1;
> +
> +                            writel (readl(&dev->usb->usbctl2) |
> +                                    (1 << U1_ENABLE),
> +                                    &dev->usb->usbctl2);
> +
> +                            allow_status(ep);
> +
> +                            goto next_endpoints;
> +
> +                        case USB_DEVICE_U2_ENABLE:
> +
> +                            dev->u2_enable = 1;
> +
> +                            writel (readl(&dev->usb->usbctl2) |
> +                                    (1 << U2_ENABLE),
> +                                    &dev->usb->usbctl2);
> +
> +                            allow_status(ep);
> +
> +                            goto next_endpoints;
> +
> +                        case USB_DEVICE_LTM_ENABLE:
> +
> +                            dev->ltm_enable = 1;
> +
> +                            writel (readl(&dev->usb->usbctl2) |
> +                                    (1 << LTM_ENABLE),
> +                                    &dev->usb->usbctl2);
> +
> +                            allow_status(ep);
> +
> +                            goto next_endpoints;
> +
> +                        default:
> +                            break;
> +                        }
> +                    }
> +
> +                    if (w_value == USB_DEVICE_REMOTE_WAKEUP)
> +                    {
> +
> +                        dev->wakeup_enable = 1;
> +
> +                        writel (readl(&dev->usb->usbctl) |
> +                                (1 << REMOTE_WAKEUP_ENABLE),
> +                                &dev->usb->usbctl);
> +
> +                        allow_status(ep);
> +
> +                        break;
> +                    }
> +
> +                    goto usb3_delegate;
> +
> +                case (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT):
> +
> +                    e = get_ep_by_addr (dev, w_index);
> +
> +                    if (!e)
> +                    {
> +                        goto do_stall;
> +                    }
> +
> +                    if (w_value != USB_ENDPOINT_HALT)
> +                    {
> +                        goto do_stall;
> +                    }
> +
> +                    ep_stdrsp (e, true, false);
> +
> +                    allow_status(ep);
> +
> +                    break;
> +
> +                default:
> +                    goto usb3_delegate;
> +                }
> +
> +                break;
> +
> +            default:
> +
> +usb3_delegate:
> +                VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x "
> +                        "ep_cfg %08x\n",
> +                        u.r.bRequestType, u.r.bRequest,
> +                        w_value, w_index, w_length,
> +                        readl (&ep->cfg->ep_cfg));
> +
> +                ep->responded = 0;
> +
> +                spin_unlock (&dev->lock);
> +                tmp = dev->driver->setup (&dev->gadget, &u.r);
> +                spin_lock (&dev->lock);
> +            }
> +        }
> +        else if (dev->gadget.speed == USB_SPEED_HIGH ||
> +                 dev->gadget.speed == USB_SPEED_FULL )
> +        {
> +
> +            switch (u.r.bRequest)
> +            {
> +            case USB_REQ_GET_STATUS:
> +            {
> +                struct usb338x_ep   *e;
> +                __le32              status;
> +
> +                /* hw handles device and interface status */
> +                if (u.r.bRequestType != (USB_DIR_IN | USB_RECIP_ENDPOINT))
> +                    goto delegate;
> +
> +                if ((e = get_ep_by_addr (dev, w_index)) == 0
> +                        || w_length > 2)
> +                    goto do_stall;
> +
> +                if (readl (&e->regs->ep_rsp)
> +                        & (1 << SET_ENDPOINT_HALT))
> +                    status = cpu_to_le32 (1);
> +                else
> +                    status = cpu_to_le32 (0);
> +
> +                /* don't bother with a request object! */
> +                writel (0, &dev->epregs [0].ep_irqenb);
> +
> +                reg_value = readl(&ep->cfg->ep_cfg) & (~(0x07 << EP_FIFO_BYTE_COUNT));
> +                writel (reg_value | (w_length << EP_FIFO_BYTE_COUNT), &ep->cfg->ep_cfg);
> +
> +                writel ((__force u32)status, &dev->epregs [0].ep_data);
> +
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                          &ep->regs->ep_rsp);
> +
> +                ep->stopped = 1;
> +
> +                VDEBUG (dev, "%s stat %02x\n", e->ep.name, status);
> +
> +                goto next_endpoints;
> +            }
> +
> +            break;
> +
> +            case USB_REQ_CLEAR_FEATURE:
> +            {
> +                struct usb338x_ep   *e;
> +
> +                /* hw handles device features */
> +                if (u.r.bRequestType != USB_RECIP_ENDPOINT)
> +                    goto delegate;
> +
> +                if (w_value != USB_ENDPOINT_HALT
> +                        || w_length != 0)
> +                    goto do_stall;
> +
> +                if ((e = get_ep_by_addr (dev, w_index)) == 0)
> +                    goto do_stall;
> +
> +                if (e->wedged)
> +                {
> +                    VDEBUG(dev, "%s wedged, halt not cleared\n",
> +                           e->ep.name);
> +                }
> +                else
> +                {
> +                    VDEBUG(dev, "%s clear halt\n", e->ep.name);
> +
> +                    writel (  (1 << CLEAR_ENDPOINT_HALT) |
> +                              (1 << CLEAR_ENDPOINT_TOGGLE) |
> +                              ((e->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS),
> +                              &e->regs->ep_rsp);
> +
> +                    if (!list_empty(&e->queue) && e->td_dma)
> +                    {
> +                        restart_dma (e);
> +                    }
> +
> +                }
> +
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                          &ep->regs->ep_rsp);
> +
> +                ep->stopped = 1;
> +
> +                goto next_endpoints;
> +            }
> +
> +            break;
> +
> +            case USB_REQ_SET_FEATURE:
> +            {
> +                struct usb338x_ep   *e;
> +
> +                /* hw handles device features */
> +                if (u.r.bRequestType != USB_RECIP_ENDPOINT)
> +                    goto delegate;
> +
> +                if (w_value != USB_ENDPOINT_HALT
> +                        || w_length != 0)
> +                    goto do_stall;
> +
> +                if ((e = get_ep_by_addr (dev, w_index)) == 0)
> +                    goto do_stall;
> +
> +                if (e->ep.name == ep0name)
> +                    goto do_stall;
> +
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          ((e->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
> +                          (1 << SET_ENDPOINT_HALT),
> +                          &e->regs->ep_rsp);
> +
> +                if (e->dma)
> +                    abort_dma (e);
> +
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                          &ep->regs->ep_rsp);
> +
> +                ep->stopped = 1;
> +
> +                VDEBUG (dev, "%s set halt\n", e->ep.name);
> +
> +                goto next_endpoints;
> +            }
> +
> +            break;
> +
> +            default:
> +delegate:
> +                VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x "
> +                        "ep_cfg %08x\n",
> +                        u.r.bRequestType, u.r.bRequest,
> +                        w_value, w_index, w_length,
> +                        readl (&ep->cfg->ep_cfg));
> +
> +                ep->responded = 0;
> +
> +                spin_unlock (&dev->lock);
> +                tmp = dev->driver->setup (&dev->gadget, &u.r);
> +                spin_lock (&dev->lock);
> +            }
> +        }
> +        else
> +        {
> +            VDEBUG (dev, "gadget speed UNKNOWN\n");
> +        }
> +
> +        /* stall ep0 on error */
> +        if (tmp < 0)
> +        {
> +
> +do_stall:
> +            VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n",
> +                    u.r.bRequestType, u.r.bRequest, tmp);
> +
> +            dev->protocol_stall = 1;
> +
> +            if (dev->gadget.speed == USB_SPEED_SUPER)
> +            {
> +                /* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
> +                ep_stall (ep, true);
> +
> +                //ep->responded = 1;
> +            }
> +        }
> +
> +        /* some in/out token irq should follow; maybe stall then.
> +         * driver must queue a request (even zlp) or halt ep0
> +         * before the host times out.
> +         */
> +    }
> +
> +#undef  w_value
> +#undef  w_index
> +#undef  w_length
> +
> +next_endpoints:
> +
> +    /* endpoint data irq ? */
> +    scratch = stat & 0x7f;
> +    stat &= ~0x7f;
> +
> +    for (num = 0; scratch; num++)
> +    {
> +        u32     t;
> +
> +        /* do this endpoint's FIFO and queue need tending? */
> +        t = 1 << num;
> +
> +        if ((scratch & t) == 0)
> +            continue;
> +        scratch ^= t;
> +
> +        ep = &dev->ep [num];
> +
> +        handle_ep_small (ep);
> +    }
> +
> +    if (stat)
> +        DEBUG (dev, "unhandled irqstat0 %08x\n", stat);
> +}
> +
> +
> +static void stop_activity (struct usb338x *dev, struct usb_gadget_driver *driver);
> +static void ep0_start (struct usb338x *dev);
> +static inline void stop_dma (struct usb338x_dma_regs __iomem *dma);
> +
> +#define DMA_INTERRUPTS ( \
> +                         (1 << DMA_3_INTERRUPT) \
> +                         | (1 << DMA_2_INTERRUPT) \
> +                         | (1 << DMA_1_INTERRUPT) \
> +                         | (1 << DMA_0_INTERRUPT))
> +#define PCI_ERROR_INTERRUPTS ( \
> +                               (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT) \
> +                               | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT) \
> +                               | (1 << 17))
> +
> +
> +static void
> +handle_stat1_irqs (struct usb338x *dev, u32 stat)
> +{
> +    struct usb338x_ep   *ep;
> +    u32                 tmp, num, mask, scratch;
> +    u32                 r_dmacount;
> +
> +    /* after disconnect there's nothing else to do! */
> +    tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
> +    mask = (1 << SUPER_SPEED_MODE) | (1 << HIGH_SPEED_MODE) | (1 << FULL_SPEED_MODE);
> +
> +    /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
> +     * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRUPT set and
> +     * both HIGH_SPEED_MODE and FULL_SPEED_MODE clear (as ROOT_PORT_RESET_INTERRUPT
> +     * only indicates a change in the reset state).
> +     */
> +    if (stat & tmp)
> +    {
> +        writel (tmp, &dev->regs->irqstat1);
> +
> +        if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
> +                && ((readl (&dev->usb->usbstat) & mask) == 0))
> +                || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0) )
> +                && ( dev->gadget.speed != USB_SPEED_UNKNOWN))
> +        {
> +            DEBUG (dev, "disconnect %s\n",
> +                   dev->driver->driver.name);
> +
> +            stop_activity (dev, dev->driver);
> +
> +            ep0_start (dev);
> +
> +            return;
> +        }
> +
> +        stat &= ~tmp;
> +
> +        /* vBUS can bounce ... one of many reasons to ignore the
> +         * notion of hotplug events on bus connect/disconnect!
> +         */
> +        if (!stat)
> +            return;
> +    }
> +
> +    /* NOTE: chip stays in PCI D0 state for now, but it could
> +     * enter D1 to save more power
> +     */
> +    tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT);
> +
> +    if (stat & tmp)
> +    {
> +        writel (tmp, &dev->regs->irqstat1);
> +
> +        if (stat & (1 << SUSPEND_REQUEST_INTERRUPT))
> +        {
> +            if (dev->driver->suspend)
> +                dev->driver->suspend (&dev->gadget);
> +
> +            if (!enable_suspend)
> +                stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
> +        }
> +        else
> +        {
> +            if (dev->driver->resume)
> +                dev->driver->resume (&dev->gadget);
> +        }
> +
> +        stat &= ~tmp;
> +    }
> +
> +    /* clear any other status/irqs */
> +    if (stat)
> +    {
> +        writel (stat, &dev->regs->irqstat1);
> +    }
> +
> +    stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
> +              | (1 << RESUME_INTERRUPT)
> +              | (1 << SOF_DOWNCOUNT_INTERRUPT)
> +              | (1 << SOF_INTERRUPT));
> +
> +    if (!stat)
> +    {
> +        return;
> +    }
> +
> +    // DEBUG (dev, "irqstat1 %08x\n", stat);
> +
> +    /* DMA status */
> +    scratch = stat & DMA_INTERRUPTS;
> +    stat &= ~DMA_INTERRUPTS;
> +    scratch >>= 9;
> +
> +    for (num = 0; scratch; num++)
> +    {
> +        struct usb338x_dma_regs __iomem *dma;
> +        tmp = 1 << num;
> +
> +        if ((tmp & scratch) == 0)
> +            continue;
> +
> +        scratch ^= tmp;
> +
> +        ep = &dev->ep [num + 1];
> +        dma = ep->dma;
> +
> +        if (!dma)
> +            continue;
> +
> +        /* clear ep's dma status */
> +        tmp = readl (&dma->dmastat);
> +        writel (tmp, &dma->dmastat);
> +
> +        // dma sync
> +        r_dmacount = readl (&dma->dmacount);
> +
> +        if (!ep->is_in &&
> +                (tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) &&
> +                ((r_dmacount & 0x00FFFFFF) != 0))
> +        {
> +            continue;
> +        }
> +
> +        /* chaining should stop on abort, short OUT from fifo,
> +         * or (stat0 codepath) short OUT transfer.
> +         */
> +        if (!use_dma_chaining)
> +        {
> +            if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))
> +                    == 0)
> +            {
> +                DEBUG (ep->dev, "DMA_TRANSACTION_DONE_INTERRUPT - %s no xact done? %08x\n",
> +                       ep->ep.name, tmp);
> +
> +                continue;
> +            }
> +
> +            stop_dma (ep->dma);
> +        }
> +
> +        /* OUT transfers terminate when the data from the
> +         * host is in our memory.  Process whatever's done.
> +         * On this path, we know transfer's last packet wasn't
> +         * less than req->length. NAK_PACKETS may be set,
> +         * or the FIFO may already be holding new packets.
> +         *
> +         * IN transfers can linger in the FIFO for a very
> +         * long time ... we ignore that for now, accounting
> +         * precisely (like PIO does) needs per-packet irqs
> +         */
> +        scan_dma_completions (ep);
> +
> +        /* disable dma on inactive queues; else maybe restart */
> +        if (list_empty (&ep->queue))
> +        {
> +            if (use_dma_chaining)
> +                stop_dma (ep->dma);
> +        }
> +        else
> +        {
> +            tmp = readl (&dma->dmactl);
> +            if (!use_dma_chaining || (tmp & (1 << DMA_ENABLE)) == 0)
> +                restart_dma (ep);
> +
> +            else if (ep->is_in && use_dma_chaining)
> +            {
> +                struct usb338x_request  *req;
> +                __le32          dmacount;
> +
> +                /* the descriptor at the head of the chain
> +                 * may still have VALID_BIT clear; that's
> +                 * used to trigger changing DMA_FIFO_VALIDATE
> +                 * (affects automagic zlp writes).
> +                 */
> +                req = list_entry (ep->queue.next,
> +                                  struct usb338x_request, queue);
> +                dmacount = req->td->dmacount;
> +                dmacount &= cpu_to_le32 (
> +                                (1 << VALID_BIT)
> +                                | DMA_TRANSFER_MAX_LENGTH);
> +
> +                if (dmacount && (dmacount & valid_bit) == 0)
> +                    restart_dma (ep);
> +            }
> +        }
> +        ep->irqs++;
> +    }
> +
> +    /* NOTE:  there are other PCI errors we might usefully notice.
> +     * if they appear very often, here's where to try recovering.
> +     */
> +    if (stat & PCI_ERROR_INTERRUPTS)
> +    {
> +        ERROR (dev, "PCI_ERROR_INTERRUPTS pci dma error; stat %08x\n", stat);
> +
> +        stat &= ~PCI_ERROR_INTERRUPTS;
> +        /* these are fatal errors, but "maybe" they won't
> +         * happen again ...
> +         */
> +        stop_activity (dev, dev->driver);
> +
> +        ep0_start (dev);
> +
> +        stat = 0;
> +    }
> +
> +    if (stat)
> +        DEBUG (dev, "unhandled irqstat1 %08x\n", stat);
> +}
> +
> +
> +static irqreturn_t
> +usb338x_irq (int irq, void *_dev)
> +{
> +    struct usb338x      *dev = _dev;
> +
> +    spin_lock (&dev->lock);
> +
> +    /* handle disconnect, dma, and more */
> +    handle_stat1_irqs (dev, readl (&dev->regs->irqstat1));
> +
> +    /* control requests and PIO */
> +    handle_stat0_irqs (dev, readl (&dev->regs->irqstat0));
> +
> +    /* re-enable interrupt to trigger any possible new interrupt */
> +    u32_pciirqenb1 = readl (&dev->regs->pciirqenb1);
> +    writel (u32_pciirqenb1 & 0x7FFFFFFF,   &dev->regs->pciirqenb1);
> +    writel (u32_pciirqenb1, &dev->regs->pciirqenb1);
> +
> +    spin_unlock (&dev->lock);
> +
> +    return IRQ_HANDLED;
> +}
> +
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static int
> +usb338x_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
> +{
> +    struct usb338x      *dev;
> +    struct usb338x_ep   *ep;
> +    u32                 max, tmp;
> +    unsigned long       flags;
> +    u32 max_pkt;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || !desc || ep->desc || _ep->name == ep0name
> +            || desc->bDescriptorType != USB_DT_ENDPOINT)
> +        return -EINVAL;
> +
> +    dev = ep->dev;
> +
> +    if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        return -ESHUTDOWN;
> +
> +    if ((desc->bEndpointAddress & 0x0f) >= 0x0c)
> +        return -EDOM;
> +
> +    ep->is_in = usb_endpoint_dir_in(desc) ? 1 : 0;
> +
> +    if (enhanced_mode && ep->is_in && ep_key[ep->num])
> +        return -EINVAL;
> +
> +    max = usb_endpoint_maxp (desc) & 0x1fff;
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +    _ep->maxpacket = max & 0x7ff;
> +    ep->desc = desc;
> +
> +    /* ep_reset() has already been called */
> +    ep->stopped = 0;
> +    ep->wedged = 0;
> +    ep->out_overflow = 0;
> +
> +    max_pkt = (enhanced_mode) ? ep_enhanced[ep->num] : ep_legacy[ep->num];
> +
> +    writel (max_pkt, &dev->regs->idxaddr);
> +    writel (max, &dev->regs->idxdata);
> +
> +    /* FIFO lines can't go to different packets.  PIO is ok, so
> +     * use it instead of troublesome (non-bulk) multi-packet DMA.
> +     */
> +    if (ep->dma && (max % 4) != 0 && use_dma_chaining)
> +    {
> +        DEBUG (ep->dev, "%s, no dma for maxpacket %d\n",
> +               ep->ep.name, ep->ep.maxpacket);
> +        ep->dma = NULL;
> +    }
> +
> +    /* set type, direction, address; reset fifo counters */
> +    writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
> +
> +    tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
> +
> +    if (tmp == USB_ENDPOINT_XFER_INT)
> +    {
> +        /* erratum 0105 workaround prevents hs NYET */
> +        if (dev->chiprev == 0100
> +                && dev->gadget.speed == USB_SPEED_HIGH
> +                && !(desc->bEndpointAddress & USB_DIR_IN))
> +        {
> +            writel ((1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                    &ep->regs->ep_rsp);
> +        }
> +    }
> +    else if (tmp == USB_ENDPOINT_XFER_BULK)
> +    {
> +        /* catch some particularly blatant driver bugs */
> +        if ((dev->gadget.speed == USB_SPEED_SUPER && max != 1024) ||
> +            (dev->gadget.speed == USB_SPEED_HIGH && max != 512) ||
> +            (dev->gadget.speed == USB_SPEED_FULL && max > 64))
> +        {
> +            spin_unlock_irqrestore (&dev->lock, flags);
> +            return -ERANGE;
> +        }
> +    }
> +
> +    ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
> +
> +    /* Enable this endpoint */
> +    /* In Legacy mode, only OUT endpoints are used */
> +    if (enhanced_mode && ep->is_in)
> +    {
> +        tmp <<= IN_ENDPOINT_TYPE;
> +        tmp |= (1 << IN_ENDPOINT_ENABLE);
> +        tmp |= (1 << ENDPOINT_DIRECTION); /* Not applicable to Legacy */
> +    }
> +    else
> +    {
> +        tmp <<= OUT_ENDPOINT_TYPE;
> +        tmp |= (1 << OUT_ENDPOINT_ENABLE);
> +        tmp |= (ep->is_in << ENDPOINT_DIRECTION);
> +    }
> +
> +    tmp |= usb_endpoint_num(desc);
> +    tmp |= (ep->ep.maxburst << MAX_BURST_SIZE);
> +
> +    wmb ();
> +
> +    /* for OUT transfers, block the rx fifo until a read is posted */
> +
> +    if (!ep->is_in)
> +        writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
> +    else
> +        /* use nak packets on an in endpoint */
> +        writel ((1 << CLEAR_NAK_OUT_PACKETS) |
> +                (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
> +
> +    writel (tmp, &ep->cfg->ep_cfg);
> +
> +    /* enable irqs */
> +    if (!ep->dma)               /* pio, per-packet */
> +    {
> +        tmp = (1 << ep_bit[ep->num]) | readl (&dev->regs->pciirqenb0);
> +
> +        writel (tmp, &dev->regs->pciirqenb0);
> +
> +        tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) |
> +              (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE);
> +
> +        writel (tmp, &ep->regs->ep_irqenb);
> +    }
> +    else                    /* dma, per-request */
> +    {
> +        tmp = (1 << (8 + ep->num)); /* completion */
> +        tmp |= readl (&dev->regs->pciirqenb1);
> +
> +        writel (tmp, &dev->regs->pciirqenb1);
> +
> +        /* for short OUT transfers, dma completions can't
> +         * advance the queue; do it pio-style, by hand.
> +         * NOTE erratum 0112 workaround #2
> +         */
> +        if ((desc->bEndpointAddress & USB_DIR_IN) == 0)
> +        {
> +            tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE);
> +
> +            writel (tmp, &ep->regs->ep_irqenb);
> +
> +            tmp = (1 << ep_bit[ep->num]) | readl (&dev->regs->pciirqenb0);
> +
> +            writel (tmp, &dev->regs->pciirqenb0);
> +        }
> +    }
> +
> +    tmp = desc->bEndpointAddress;
> +
> +    DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n",
> +           _ep->name, tmp & 0x0f, DIR_STRING (tmp),
> +           type_string (desc->bmAttributes),
> +           ep->dma ? "dma" : "pio", max);
> +
> +    /* pci writes may still be posted */
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    return 0;
> +}
> +
> +
> +static int
> +handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
> +{
> +    u32 result;
> +
> +    do
> +    {
> +        result = readl (ptr);
> +        if (result == ~(u32)0)      /* "device unplugged" */
> +            return -ENODEV;
> +        result &= mask;
> +        if (result == done)
> +            return 0;
> +        udelay (1);
> +        usec--;
> +    }
> +    while (usec > 0);
> +
> +    return -ETIMEDOUT;
> +}
> +
> +
> +static const struct usb_ep_ops usb338x_ep_ops;
> +
> +
> +static void
> +ep_reset (struct usb338x_regs __iomem *regs, struct usb338x_ep *ep)
> +{
> +    u32     tmp, dmastat;
> +
> +    ep->desc = NULL;
> +    INIT_LIST_HEAD (&ep->queue);
> +
> +    ep->ep.maxpacket = ~0;
> +    ep->ep.ops = &usb338x_ep_ops;
> +
> +    /* disable the dma, irqs, endpoint... */
> +    if (ep->dma)
> +    {
> +        writel (0, &ep->dma->dmactl);
> +        writel (  (1 << DMA_ABORT_DONE_INTERRUPT)
> +                  | (1 << DMA_PAUSE_DONE_INTERRUPT)
> +                  | (1 << DMA_LAST_DESCRIPTOR_DONE_INTERRUPT)
> +                  | (1 << DMA_TRANSACTION_DONE_INTERRUPT)
> +                  // | (1 << DMA_ABORT)
> +                  , &ep->dma->dmastat);
> +
> +        dmastat = readl (&ep->dma->dmastat);
> +
> +        if (dmastat == 0x5002)
> +        {
> +            printk(KERN_WARNING "The dmastat return = %x!!\n", dmastat);
> +            writel( 0x5a, &ep->dma->dmastat);
> +        }
> +
> +        tmp = readl (&regs->pciirqenb0);
> +
> +        tmp &= ~(1 << ep_bit[ep->num]);
> +
> +        writel (tmp, &regs->pciirqenb0);
> +    }
> +    else
> +    {
> +        if (ep->num < 5)
> +        {
> +            tmp = readl (&regs->pciirqenb1);
> +            tmp &= ~(1 << (8 + ep->num));   /* completion */
> +            writel (tmp, &regs->pciirqenb1);
> +        }
> +    }
> +
> +    writel (0, &ep->regs->ep_irqenb);
> +
> +    writel ((1 << SHORT_OUT_PACKET_DONE_INTERRUPT)
> +            | (1 << SHORT_OUT_PACKET_RECEIVED_INTERRUPT)
> +            | (1 << ZLP_INTERRUPT)
> +            | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
> +            | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
> +            | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
> +            | (1 << DATA_IN_TOKEN_INTERRUPT),
> +            &ep->regs->ep_stat);
> +}
> +
> +
> +static void nuke (struct usb338x_ep *);
> +
> +static int
> +usb338x_disable (struct usb_ep *_ep)
> +{
> +    struct usb338x_ep   *ep;
> +    unsigned long       flags;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || !ep->desc || _ep->name == ep0name)
> +        return -EINVAL;
> +
> +    spin_lock_irqsave (&ep->dev->lock, flags);
> +
> +    nuke (ep);
> +    ep_reset (ep->dev->regs, ep);
> +
> +    VDEBUG (ep->dev, "disabled %s %s\n",
> +            ep->dma ? "dma" : "pio", _ep->name);
> +
> +    /* synch memory views with the device */
> +    (void) readl (&ep->cfg->ep_cfg);
> +
> +    if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
> +        ep->dma = &ep->dev->dma [ep->num - 1];
> +
> +    spin_unlock_irqrestore (&ep->dev->lock, flags);
> +
> +    return 0;
> +}
> +
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static struct usb_request *
> +usb338x_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
> +{
> +    struct usb338x_ep       *ep;
> +    struct usb338x_request  *req;
> +
> +    if (!_ep)
> +        return NULL;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    req = kzalloc(sizeof(*req), gfp_flags);
> +
> +    if (!req)
> +        return NULL;
> +
> +    req->req.dma = DMA_ADDR_INVALID;
> +
> +    INIT_LIST_HEAD (&req->queue);
> +
> +    /* this dma descriptor may be swapped with the previous dummy */
> +    if (ep->dma)
> +    {
> +        struct usb338x_dma  *td;
> +
> +        td = pci_pool_alloc (ep->dev->requests, gfp_flags,
> +                             &req->td_dma);
> +        if (!td)
> +        {
> +            kfree (req);
> +            return NULL;
> +        }
> +
> +        td->dmacount = 0;   /* not VALID */
> +        td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
> +        td->dmadesc = td->dmaaddr;
> +        req->td = td;
> +    }
> +
> +    return &req->req;
> +}
> +
> +
> +static void
> +usb338x_free_request (struct usb_ep *_ep, struct usb_request *_req)
> +{
> +    struct usb338x_ep       *ep;
> +    struct usb338x_request  *req;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || !_req)
> +        return;
> +
> +    req = container_of (_req, struct usb338x_request, req);
> +
> +    WARN_ON (!list_empty (&req->queue));
> +
> +    if (req->td)
> +        pci_pool_free (ep->dev->requests, req->td, req->td_dma);
> +
> +    kfree (req);
> +}
> +
> +
> +/*-------------------------------------------------------------------------*/
> +
> +/* load a packet into the fifo we use for usb IN transfers.
> + * works for all endpoints.
> + *
> + * NOTE: pio with ep1..ep4 could stuff multiple packets into the fifo
> + * at a time, but this code is simpler because it knows it only writes
> + * one packet.  ep1..ep4 should use dma instead.
> + */
> +static void
> +write_fifo (struct usb338x_ep *ep, struct usb_request *req)
> +{
> +    struct usb338x_ep_regs  __iomem *regs = ep->regs;
> +    u8          *buf;
> +    u32         tmp;
> +    unsigned    count, total;
> +    u32         reg_value;
> +
> +    /* INVARIANT:  fifo is currently empty. (testable) */
> +    if (req)
> +    {
> +        buf = req->buf + req->actual;
> +        prefetch (buf);
> +        total = req->length - req->actual;
> +    }
> +    else
> +    {
> +        total = 0;
> +        buf = NULL;
> +    }
> +
> +    /* write just one packet at a time */
> +    count = ep->ep.maxpacket;
> +
> +    if (count > total)  /* min() cannot be used on a bitfield */
> +        count = total;
> +
> +    VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n",
> +            ep->ep.name, count,
> +            (count != ep->ep.maxpacket) ? " (short)" : "",
> +            req);
> +
> +    while (count >= 4)
> +    {
> +        /* NOTE be careful if you try to align these. fifo lines
> +         * should normally be full (4 bytes) and successive partial
> +         * lines are ok only in certain cases.
> +         */
> +        tmp = get_unaligned ((u32 *)buf);
> +        cpu_to_le32s (&tmp);
> +        writel (tmp, &regs->ep_data);
> +        buf += 4;
> +        count -= 4;
> +    }
> +
> +    /* last fifo entry is "short" unless we wrote a full packet.
> +     * also explicitly validate last word in (periodic) transfers
> +     * when maxpacket is not a multiple of 4 bytes.
> +     */
> +    if (count || total < ep->ep.maxpacket)
> +    {
> +        tmp = count ? get_unaligned ((u32 *)buf) : count;
> +        cpu_to_le32s (&tmp);
> +
> +        reg_value = readl(&ep->cfg->ep_cfg) & (~(0x07 << EP_FIFO_BYTE_COUNT));
> +
> +        writel (reg_value | ((count  & 0x03) << EP_FIFO_BYTE_COUNT), &ep->cfg->ep_cfg);
> +
> +        writel (tmp, &regs->ep_data);
> +    }
> +
> +    /* pci writes may still be posted */
> +}
> +
> +
> +/* work around erratum 0106: PCI and USB race over the OUT fifo.
> + * caller guarantees chiprev 0100, out endpoint is NAKing, and
> + * there's no real data in the fifo.
> + *
> + * NOTE:  also used in cases where that erratum doesn't apply:
> + * where the host wrote "too much" data to us.
> + */
> +static void
> +out_flush (struct usb338x_ep *ep)
> +{
> +    u32 __iomem *statp;
> +    u32 tmp;
> +
> +    statp = &ep->regs->ep_stat;
> +
> +    writel (  (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
> +              | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
> +              , statp);
> +
> +    writel ((1 << FIFO_FLUSH), statp);
> +
> +    mb ();
> +
> +    tmp = readl (statp);
> +
> +    if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
> +            /* high speed did bulk NYET; fifo isn't filling */
> +            && ep->dev->gadget.speed == USB_SPEED_FULL)
> +    {
> +        unsigned    usec;
> +
> +        usec = 50;      /* 64 byte bulk/interrupt */
> +        handshake (statp, (1 << USB_OUT_NAK_SENT),
> +                   (1 << USB_OUT_NAK_SENT), usec);
> +        /* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */
> +    }
> +}
> +
> +
> +/* unload packet(s) from the fifo we use for usb OUT transfers.
> + * returns true iff the request completed, because of short packet
> + * or the request buffer having filled with full packets.
> + *
> + * for ep1..ep4 this will read multiple packets out when they
> + * have been accepted.
> + */
> +static int
> +read_fifo (struct usb338x_ep *ep, struct usb338x_request *req)
> +{
> +    struct usb338x_ep_regs  __iomem *regs = ep->regs;
> +    u8          *buf = req->req.buf + req->req.actual;
> +    unsigned    count, tmp, is_short;
> +    unsigned    cleanup = 0, prevent = 0;
> +
> +    /* erratum 0106 ... packets coming in during fifo reads might
> +     * be incompletely rejected.  not all cases have workarounds.
> +     */
> +    if (ep->dev->chiprev == 0x0100
> +            && ep->dev->gadget.speed == USB_SPEED_FULL)
> +    {
> +        udelay (1);
> +        tmp = readl (&ep->regs->ep_stat);
> +
> +        if ((tmp & (1 << NAK_PACKETS)))
> +            cleanup = 1;
> +
> +        else if ((tmp & (1 << FIFO_FULL)))
> +        {
> +            writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
> +            readl (&ep->regs->ep_rsp);
> +
> +            prevent = 1;
> +        }
> +        /* else: hope we don't see the problem */
> +    }
> +
> +    /* never overflow the rx buffer. the fifo reads packets until
> +     * it sees a short one; we might not be ready for them all.
> +     */
> +    prefetchw (buf);
> +    count = readl (&regs->ep_avail);
> +
> +    if (unlikely (count == 0))
> +    {
> +        udelay (1);
> +        tmp = readl (&ep->regs->ep_stat);
> +        count = readl (&regs->ep_avail);
> +
> +        /* handled that data already? */
> +        if (count == 0 && (tmp & (1 << NAK_PACKETS)) == 0)
> +            return 0;
> +    }
> +
> +    tmp = req->req.length - req->req.actual;
> +
> +    if (count > tmp)
> +    {
> +        /* as with DMA, data overflow gets flushed */
> +        if ((tmp % ep->ep.maxpacket) != 0)
> +        {
> +            ERROR (ep->dev,
> +                   "%s out fifo %d bytes, expected %d\n",
> +                   ep->ep.name, count, tmp);
> +
> +            req->req.status = -EOVERFLOW;
> +            cleanup = 1;
> +            /* NAK_PACKETS will be set, so flushing is safe;
> +             * the next read will start with the next packet
> +             */
> +        } /* else it's a ZLP, no worries */
> +        count = tmp;
> +    }
> +
> +    req->req.actual += count;
> +
> +    is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0);
> +
> +    VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n",
> +            ep->ep.name, count, is_short ? " (short)" : "",
> +            cleanup ? " flush" : "", prevent ? " nak" : "",
> +            req, req->req.actual, req->req.length);
> +
> +    while (count >= 4)
> +    {
> +        tmp = readl (&regs->ep_data);
> +        cpu_to_le32s (&tmp);
> +        put_unaligned (tmp, (u32 *)buf);
> +        buf += 4;
> +        count -= 4;
> +    }
> +
> +    if (count)
> +    {
> +        tmp = readl (&regs->ep_data);
> +        /* LE conversion is implicit here: */
> +        do
> +        {
> +            *buf++ = (u8) tmp;
> +            tmp >>= 8;
> +        }
> +        while (--count);
> +    }
> +
> +    if (cleanup)
> +        out_flush (ep);
> +
> +    if (prevent)
> +    {
> +        writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
> +        (void) readl (&ep->regs->ep_rsp);
> +    }
> +
> +    return is_short || ((req->req.actual == req->req.length)
> +                        && !req->req.zero);
> +}
> +
> +
> +/* fill out dma descriptor to match a given request */
> +static void
> +fill_dma_desc (struct usb338x_ep *ep, struct usb338x_request *req, int valid)
> +{
> +    struct usb338x_dma  *td = req->td;
> +    u32            dmacount = req->req.length;
> +
> +    /* don't let DMA continue after a short OUT packet,
> +     * so overruns can't affect the next transfer.
> +     * in case of overruns on max-size packets, we can't
> +     * stop the fifo from filling but we can flush it.
> +     */
> +    if (ep->is_in)
> +        dmacount |= (1 << DMA_DIRECTION);
> +
> +    /* if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0)) */
> +    dmacount |= (1 << LAST_DESCRIPTOR);
> +
> +    req->valid = valid;
> +
> +    if (valid)
> +        dmacount |= (1 << VALID_BIT);
> +
> +    if (likely(!req->req.no_interrupt || !use_dma_chaining))
> +    {
> +        dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
> +    }
> +
> +    /* td->dmadesc = previously set by caller */
> +    td->dmaaddr = cpu_to_le32 (req->req.dma);
> +
> +    wmb ();
> +    td->dmacount = cpu_to_le32(dmacount);
> +}
> +
> +static const u32 dmactl_default =
> +    (1 << DMA_LAST_DESCRIPTOR_DONE_INTERRUPT)
> +    | (1 << DMA_CLEAR_COUNT_ENABLE)
> +    | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE)
> +    | (1 << DMA_VALID_BIT_POLLING_ENABLE)
> +    | (1 << DMA_VALID_BIT_ENABLE)
> +    | (1 << DMA_DESCRIPTOR_MODE)
> +    | (1 << DMA_ENABLE);
> +
> +
> +static inline void
> +spin_stop_dma (struct usb338x_dma_regs __iomem *dma)
> +{
> +    int     usec = 50;
> +    u32     result;
> +
> +    do
> +    {
> +        result = readl (&dma->dmactl);
> +
> +        if (result == ~(u32)0) return;  /* "device unplugged" */
> +
> +        result &= (1 << DMA_ENABLE);
> +
> +        if (result == 0) return;
> +
> +        udelay (1);
> +        usec--;
> +
> +    }
> +    while (usec > 0);
> +
> +    return;
> +}
> +
> +
> +static inline void
> +stop_dma (struct usb338x_dma_regs __iomem *dma)
> +{
> +    writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl);
> +    spin_stop_dma (dma);
> +}
> +
> +
> +static void
> +start_queue (struct usb338x_ep *ep, u32 dmactl, u32 td_dma)
> +{
> +    u32   reg_value;
> +
> +    struct usb338x_dma_regs __iomem *dma = ep->dma;
> +    unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION);
> +
> +    tmp |= (1 << LAST_DESCRIPTOR);
> +
> +    writel (tmp, &dma->dmacount);
> +    writel (readl (&dma->dmastat), &dma->dmastat);
> +
> +    writel (td_dma, &dma->dmadesc);
> +
> +    dmactl |=  (0x01 << DMA_REQUEST_OUTSTANDING);
> +
> +    writel (dmactl, &dma->dmactl);
> +
> +    /* erratum 0116 workaround part 3:  pci arbiter away from usb338x */
> +    (void) readl (&ep->dev->pci->pcimstctl);
> +
> +    writel ((1 << DMA_START), &dma->dmastat);
> +
> +    if (!ep->is_in)
> +    {
> +        reg_value = readl (&ep->regs->ep_stat);
> +
> +        if ((reg_value & (1 << NAK_PACKETS)) != 0)
> +            writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
> +    }
> +}
> +
> +
> +static void
> +start_dma (struct usb338x_ep *ep, struct usb338x_request *req)
> +{
> +    u32         tmp;
> +    struct usb338x_dma_regs __iomem *dma = ep->dma;
> +
> +    /* FIXME can't use DMA for ZLPs */
> +
> +    /* on this path we "know" there's no dma active (yet) */
> +    WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE));
> +    writel (0, &ep->dma->dmactl);
> +
> +    /* previous OUT packet might have been short */
> +    if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
> +                       & (1 << NAK_PACKETS)) != 0)
> +    {
> +        writel ((1 << SHORT_OUT_PACKET_RECEIVED_INTERRUPT),
> +                &ep->regs->ep_stat);
> +
> +        tmp = readl (&ep->regs->ep_avail);
> +
> +        if (tmp)
> +        {
> +            writel (readl (&dma->dmastat), &dma->dmastat);
> +
> +            /* transfer all/some fifo data */
> +            writel (req->req.dma, &dma->dmaaddr);
> +            tmp = min (tmp, req->req.length);
> +
> +            /* dma irq, faking scatterlist status */
> +            req->td->dmacount = cpu_to_le32 (req->req.length - tmp);
> +            writel ((1 << DMA_DONE_INTERRUPT_ENABLE)
> +                    | tmp, &dma->dmacount);
> +            req->td->dmadesc = 0;
> +            req->valid = 1;
> +
> +            writel ((1 << DMA_ENABLE), &dma->dmactl);
> +            writel ((1 << DMA_START), &dma->dmastat);
> +
> +            return;
> +        }
> +    }
> +
> +    tmp = dmactl_default;
> +
> +    /* force packet boundaries between dma requests, but prevent the
> +     * controller from automagically writing a last "short" packet
> +     * (zero length) unless the driver explicitly said to do that.
> +     */
> +    if (ep->is_in)
> +    {
> +        if (likely ((req->req.length % ep->ep.maxpacket) != 0
> +                    || req->req.zero))
> +        {
> +            tmp |= (1 << DMA_FIFO_VALIDATE);
> +            ep->in_fifo_validate = 1;
> +        }
> +        else
> +            ep->in_fifo_validate = 0;
> +    }
> +
> +    /* init req->td, pointing to the current dummy */
> +    req->td->dmadesc = cpu_to_le32 (ep->td_dma);
> +    fill_dma_desc (ep, req, 1);
> +
> +    if (!use_dma_chaining)
> +        req->td->dmacount |= cpu_to_le32 (1 << LAST_DESCRIPTOR);
> +
> +    start_queue (ep, tmp, req->td_dma);
> +}
> +
> +
> +static inline void
> +queue_dma (struct usb338x_ep *ep, struct usb338x_request *req, int valid)
> +{
> +    struct usb338x_dma  *end;
> +    dma_addr_t          tmp;
> +
> +    /* swap new dummy for old, link; fill and maybe activate */
> +    end = ep->dummy;
> +    ep->dummy = req->td;
> +    req->td = end;
> +
> +    tmp = ep->td_dma;
> +    ep->td_dma = req->td_dma;
> +    req->td_dma = tmp;
> +
> +    end->dmadesc = cpu_to_le32 (ep->td_dma);
> +
> +    fill_dma_desc (ep, req, valid);
> +}
> +
> +
> +static void
> +complete_req (struct usb338x_ep *ep, struct usb338x_request *req, int status)
> +{
> +    struct usb338x    *dev;
> +    unsigned          stopped = ep->stopped;
> +
> +    list_del_init (&req->queue);
> +
> +    if (req->req.status == -EINPROGRESS)
> +        req->req.status = status;
> +    else
> +        status = req->req.status;
> +
> +    dev = ep->dev;
> +
> +    if (ep->dma)
> +        usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
> +
> +    if (status && status != -ESHUTDOWN)
> +        VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
> +                ep->ep.name, &req->req, status,
> +                req->req.actual, req->req.length);
> +
> +    /* don't modify queue heads during completion callback */
> +    ep->stopped = 1;
> +
> +    spin_unlock (&dev->lock);
> +    req->req.complete (&ep->ep, &req->req);
> +    spin_lock (&dev->lock);
> +
> +    ep->stopped = stopped;
> +}
> +
> +
> +static inline void
> +dma_done (struct usb338x_ep *ep, struct usb338x_request *req, u32 dmacount, int status)
> +{
> +    req->req.actual = req->req.length - (DMA_TRANSFER_MAX_LENGTH & dmacount);
> +
> +    complete_req (ep, req, status);
> +}
> +
> +
> +static void
> +scan_dma_completions (struct usb338x_ep *ep)
> +{
> +    /* only look at descriptors that were "naturally" retired,
> +     * so fifo and list head state won't matter
> +     */
> +    while (!list_empty (&ep->queue))
> +    {
> +        struct usb338x_request  *req;
> +        u32         tmp;
> +
> +        req = list_entry (ep->queue.next,
> +                          struct usb338x_request, queue);
> +        if (!req->valid)
> +            break;
> +
> +        rmb ();
> +
> +        tmp = le32_to_cpup (&req->td->dmacount);
> +
> +        if ((tmp & (1 << VALID_BIT)) != 0)
> +            break;
> +
> +        /* SHORT_OUT_PACKET_RECEIVED_INTERRUPT handles "usb-short"
> +         * cases where DMA must be aborted; this code handles
> +         * all non-abort DMA completions.
> +         */
> +        if (unlikely (req->td->dmadesc == 0))
> +        {
> +            /* paranoia */
> +            tmp = readl (&ep->dma->dmacount);
> +
> +            if (tmp & DMA_TRANSFER_MAX_LENGTH)
> +                break;
> +
> +            /* single transfer mode */
> +            dma_done (ep, req, tmp, 0);
> +
> +            break;
> +        }
> +        else if (!ep->is_in
> +                 && (req->req.length % ep->ep.maxpacket) != 0)
> +        {
> +            tmp = readl (&ep->regs->ep_stat);
> +
> +        }
> +
> +        dma_done (ep, req, tmp, 0);
> +    }
> +}
> +
> +
> +static void
> +restart_dma (struct usb338x_ep *ep)
> +{
> +    struct usb338x_request  *req;
> +    u32         dmactl = dmactl_default;
> +
> +    if (ep->stopped)
> +        return;
> +
> +    req = list_entry (ep->queue.next, struct usb338x_request, queue);
> +
> +    if (!use_dma_chaining)
> +    {
> +        start_dma (ep, req);
> +
> +        return;
> +    }
> +
> +
> +    /*  IN:   wanted automagic zlp, head doesn't (or vice versa)
> +     *        DMA_FIFO_VALIDATE doesn't init from dma descriptors.
> +     *  OUT:  was "usb-short", we must restart.
> +     */
> +    if (ep->is_in && !req->valid)
> +    {
> +        struct usb338x_request  *entry, *prev = NULL;
> +        int         reqmode, done = 0;
> +
> +        DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
> +
> +        ep->in_fifo_validate = likely (req->req.zero
> +                                       || (req->req.length % ep->ep.maxpacket) != 0);
> +        if (ep->in_fifo_validate)
> +            dmactl |= (1 << DMA_FIFO_VALIDATE);
> +
> +        list_for_each_entry (entry, &ep->queue, queue)
> +        {
> +            __le32      dmacount;
> +
> +            if (entry == req)
> +                continue;
> +
> +            dmacount = entry->td->dmacount;
> +
> +            if (!done)
> +            {
> +                reqmode = likely (entry->req.zero
> +                                  || (entry->req.length
> +                                      % ep->ep.maxpacket) != 0);
> +
> +                if (reqmode == ep->in_fifo_validate)
> +                {
> +                    entry->valid = 1;
> +                    dmacount |= valid_bit;
> +                    entry->td->dmacount = dmacount;
> +                    prev = entry;
> +
> +                    continue;
> +                }
> +                else
> +                {
> +                    /* force a hiccup */
> +                    prev->td->dmacount |= dma_done_ie;
> +                    done = 1;
> +                }
> +            }
> +
> +            /* walk the rest of the queue so unlinks behave */
> +            entry->valid = 0;
> +            dmacount &= ~valid_bit;
> +            entry->td->dmacount = dmacount;
> +            prev = entry;
> +        }
> +    }
> +
> +    writel (0, &ep->dma->dmactl);
> +
> +    start_queue (ep, dmactl, req->td_dma);
> +}
> +
> +
> +static void
> +abort_dma (struct usb338x_ep *ep)
> +{
> +    /* abort the current transfer */
> +    writel ((1 << DMA_ABORT), &ep->dma->dmastat);
> +
> +    spin_stop_dma (ep->dma);
> +}
> +
> +
> +/* dequeue ALL requests */
> +static void
> +nuke (struct usb338x_ep *ep)
> +{
> +    struct usb338x_request  *req;
> +
> +    /* called with spinlock held */
> +    ep->stopped = 1;
> +    if (ep->dma)
> +        abort_dma (ep);
> +
> +    while (!list_empty (&ep->queue))
> +    {
> +        req = list_entry (ep->queue.next,
> +                          struct usb338x_request,
> +                          queue);
> +
> +        complete_req (ep, req, -ESHUTDOWN);
> +    }
> +}
> +
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static int
> +usb338x_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
> +{
> +    struct usb338x_request  *req;
> +    struct usb338x_ep   *ep;
> +    struct usb338x      *dev;
> +    unsigned long       flags;
> +
> +    /* we always require a cpu-view buffer, so that we can
> +     * always use pio (as fallback or whatever).
> +     */
> +    req = container_of (_req, struct usb338x_request, req);
> +
> +    if (!_req || !_req->complete || !_req->buf
> +            || !list_empty (&req->queue))
> +        return -EINVAL;
> +
> +    if (_req->length > (~0 & DMA_TRANSFER_MAX_LENGTH))
> +        return -EDOM;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || (!ep->desc && ep->num != 0))
> +        return -EINVAL;
> +
> +    dev = ep->dev;
> +
> +    if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        return -ESHUTDOWN;
> +
> +    /* FIXME implement PIO fallback for ZLPs with DMA */
> +    if (ep->dma && _req->length == 0)
> +        return -EOPNOTSUPP;
> +
> +    /* set up dma mapping in case the caller didn't */
> +    if (ep->dma)
> +    {
> +        int ret;
> +
> +        ret = usb_gadget_map_request(&dev->gadget, _req,
> +                                     ep->is_in);
> +        if (ret)
> +            return ret;
> +    }
> +
> +#if 0
> +    VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
> +            _ep->name, _req, _req->length, _req->buf);
> +#endif
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    _req->status = -EINPROGRESS;
> +    _req->actual = 0;
> +
> +    /* kickstart this i/o queue? */
> +    if (list_empty (&ep->queue) && !ep->stopped)
> +    {
> +
> +        /* DMA request while EP halted */
> +        if (ep->dma && (readl(&ep->regs->ep_rsp) & (1 << CLEAR_ENDPOINT_HALT)))
> +        {
> +            int valid = 1;
> +
> +            if (ep->is_in)
> +            {
> +                int expect;
> +
> +                expect = likely (req->req.zero ||
> +                                 ((req->req.length % ep->ep.maxpacket) != 0));
> +
> +                if (expect != ep->in_fifo_validate)
> +                {
> +                    valid = 0;
> +                }
> +            }
> +
> +            queue_dma (ep, req, valid);
> +        }
> +
> +        /* use DMA if the endpoint supports it, else pio */
> +        else if (ep->dma)
> +            start_dma (ep, req);
> +        else
> +        {
> +            /* maybe there's no control data, just status ack */
> +            if (ep->num == 0 && _req->length == 0)
> +            {
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS) |
> +                          (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                          &ep->regs->ep_rsp);
> +
> +                ep->stopped = 1;
> +
> +                complete_req (ep, req, 0);
> +
> +                VDEBUG (dev, "%s status ack\n", ep->ep.name);
> +
> +                goto done;
> +            }
> +
> +            /* PIO ... stuff the fifo, or unblock it.  */
> +            if (ep->is_in)
> +                write_fifo (ep, _req);
> +            else if (list_empty (&ep->queue))
> +            {
> +                u32 s;
> +
> +                /* OUT FIFO might have packet(s) buffered */
> +                s = readl (&ep->regs->ep_stat);
> +
> +                if ((s & (1 << FIFO_EMPTY)) == 0)
> +                {
> +                    /* note:  _req->short_not_ok is
> +                     * ignored here since PIO _always_
> +                     * stops queue advance here, and
> +                     * _req->status doesn't change for
> +                     * short reads (only _req->actual)
> +                     */
> +                    if (read_fifo (ep, req))
> +                    {
> +                        complete_req (ep, req, 0);
> +
> +                        if (ep->num == 0)
> +                        {
> +                            writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                                      (1 << CLEAR_NAK_OUT_PACKETS) |
> +                                      (1 << CLEAR_NAK_OUT_PACKETS_MODE),
> +                                      &ep->regs->ep_rsp);
> +
> +                            ep->stopped = 1;
> +                        }
> +
> +                        /* don't queue it */
> +                        req = NULL;
> +                    }
> +                    else
> +                        s = readl (&ep->regs->ep_stat);
> +                }
> +
> +                /* don't NAK, let the fifo fill */
> +                if (req && (s & (1 << NAK_PACKETS)))
> +                {
> +                    writel ((1 << CLEAR_NAK_OUT_PACKETS),
> +                            &ep->regs->ep_rsp);
> +                }
> +            }
> +        }
> +
> +    }
> +    else if (ep->dma)
> +    {
> +        int valid = 1;
> +
> +        if (ep->is_in)
> +        {
> +            int expect;
> +
> +            /* preventing magic zlps is per-engine state, not
> +             * per-transfer; irq logic must recover hiccups.
> +             */
> +            expect = likely (req->req.zero
> +                             || (req->req.length % ep->ep.maxpacket) != 0);
> +            if (expect != ep->in_fifo_validate)
> +                valid = 0;
> +        }
> +
> +        queue_dma (ep, req, valid);
> +
> +    } /* else the irq handler advances the queue. */
> +
> +    ep->responded = 1;
> +
> +    if (req)
> +        list_add_tail (&req->queue, &ep->queue);
> +done:
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    /* pci writes may still be posted */
> +    return 0;
> +}
> +
> +
> +/* dequeue JUST ONE request */
> +static int
> +usb338x_dequeue (struct usb_ep *_ep, struct usb_request *_req)
> +{
> +    struct usb338x_ep   *ep;
> +    struct usb338x_request  *req;
> +    unsigned long       flags;
> +    u32         dmactl;
> +    int         stopped;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || (!ep->desc && ep->num != 0) || !_req)
> +        return -EINVAL;
> +
> +    spin_lock_irqsave (&ep->dev->lock, flags);
> +
> +    stopped = ep->stopped;
> +
> +    /* quiesce dma while we patch the queue */
> +    dmactl = 0;
> +    ep->stopped = 1;
> +
> +    if (ep->dma)
> +    {
> +        dmactl = readl (&ep->dma->dmactl);
> +
> +        /* WARNING erratum 0127 may kick in ... */
> +        stop_dma (ep->dma);
> +
> +        scan_dma_completions (ep);
> +    }
> +
> +    /* make sure it's still queued on this endpoint */
> +    list_for_each_entry (req, &ep->queue, queue)
> +    {
> +        if (&req->req == _req)
> +            break;
> +    }
> +
> +    if (&req->req != _req)
> +    {
> +        spin_unlock_irqrestore (&ep->dev->lock, flags);
> +
> +        return -EINVAL;
> +    }
> +
> +    /* queue head may be partially complete. */
> +    if (ep->queue.next == &req->queue)
> +    {
> +        if (ep->dma)
> +        {
> +            DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name);
> +            _req->status = -ECONNRESET;
> +
> +            abort_dma (ep);
> +
> +            if (likely (ep->queue.next == &req->queue))
> +            {
> +                // NOTE: misreports single-transfer mode
> +                req->td->dmacount = 0;  /* invalidate */
> +
> +                dma_done (ep, req,
> +                          readl (&ep->dma->dmacount),
> +                          -ECONNRESET);
> +            }
> +        }
> +        else
> +        {
> +            DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name);
> +            complete_req (ep, req, -ECONNRESET);
> +        }
> +
> +        req = NULL;
> +
> +        /* patch up hardware chaining data */
> +    }
> +    else if (ep->dma && use_dma_chaining)
> +    {
> +        if (req->queue.prev == ep->queue.next)
> +        {
> +            writel (le32_to_cpu (req->td->dmadesc),
> +                    &ep->dma->dmadesc);
> +
> +            if (req->td->dmacount & dma_done_ie)
> +                writel (readl (&ep->dma->dmacount)
> +                        | le32_to_cpu(dma_done_ie),
> +                        &ep->dma->dmacount);
> +        }
> +        else
> +        {
> +            struct usb338x_request  *prev;
> +
> +            prev = list_entry (req->queue.prev,
> +                               struct usb338x_request, queue);
> +            prev->td->dmadesc = req->td->dmadesc;
> +
> +            if (req->td->dmacount & dma_done_ie)
> +                prev->td->dmacount |= dma_done_ie;
> +        }
> +    }
> +
> +    if (req)
> +        complete_req (ep, req, -ECONNRESET);
> +
> +    ep->stopped = stopped;
> +
> +    if (ep->dma)
> +    {
> +        /* turn off dma on inactive queues */
> +        if (list_empty (&ep->queue))
> +            stop_dma (ep->dma);
> +
> +        else if (!ep->stopped)
> +        {
> +            /* resume current request, or start new one */
> +            if (req)
> +            {
> +                writel (dmactl, &ep->dma->dmactl);
> +            }
> +            else
> +                start_dma (ep, list_entry (ep->queue.next,
> +                                           struct usb338x_request, queue));
> +        }
> +    }
> +
> +    spin_unlock_irqrestore (&ep->dev->lock, flags);
> +
> +    return 0;
> +}
> +
> +
> +static int usb338x_fifo_status (struct usb_ep *_ep);
> +
> +static int
> +usb338x_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
> +{
> +    struct usb338x_ep   *ep;
> +    unsigned long       flags;
> +    int         retval = 0;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || (!ep->desc && ep->num != 0))
> +        return -EINVAL;
> +
> +    if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        return -ESHUTDOWN;
> +
> +    /* not ep0 */
> +    if (ep->desc && (ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
> +        return -EINVAL;
> +
> +    spin_lock_irqsave (&ep->dev->lock, flags);
> +
> +    if (!list_empty (&ep->queue))
> +        retval = -EAGAIN;
> +    else if (ep->is_in && value && usb338x_fifo_status (_ep) != 0)
> +        retval = -EAGAIN;
> +    else
> +    {
> +        VDEBUG (ep->dev, "%s %s %s\n", _ep->name,
> +                value ? "set" : "clear",
> +                wedged ? "wedge" : "halt");
> +
> +        /* set/clear, then synch memory views with the device */
> +        if (value)
> +        {
> +            if (ep->num == 0)
> +                ep->dev->protocol_stall = 1;
> +            else
> +                writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) |
> +                          ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) |
> +                          (1 << SET_ENDPOINT_HALT),
> +                          &ep->regs->ep_rsp);
> +
> +            if (wedged)
> +                ep->wedged = 1;
> +        }
> +        else
> +        {
> +            writel (  (1 << CLEAR_ENDPOINT_HALT) |
> +                      (1 << CLEAR_ENDPOINT_TOGGLE) |
> +                      ((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS),
> +                      &ep->regs->ep_rsp);
> +
> +            if (!list_empty(&ep->queue) && ep->td_dma)
> +            {
> +                restart_dma (ep);
> +            }
> +
> +            ep->wedged = 0;
> +        }
> +
> +        (void) readl (&ep->regs->ep_rsp);
> +    }
> +
> +    spin_unlock_irqrestore (&ep->dev->lock, flags);
> +
> +    return retval;
> +}
> +
> +
> +static int
> +usb338x_set_halt(struct usb_ep *_ep, int value)
> +{
> +    return usb338x_set_halt_and_wedge(_ep, value, 0);
> +}
> +
> +
> +static int
> +usb338x_set_wedge(struct usb_ep *_ep)
> +{
> +    if (!_ep || _ep->name == ep0name)
> +        return -EINVAL;
> +
> +    return usb338x_set_halt_and_wedge(_ep, 1, 1);
> +}
> +
> +
> +static int
> +usb338x_fifo_status (struct usb_ep *_ep)
> +{
> +    struct usb338x_ep   *ep;
> +    u32         avail;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || (!ep->desc && ep->num != 0))
> +        return -ENODEV;
> +
> +    if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        return -ESHUTDOWN;
> +
> +    avail = readl (&ep->regs->ep_avail) & ((1 << 12) - 1);
> +
> +    if (avail > ep->fifo_size)
> +        return -EOVERFLOW;
> +
> +    if (ep->is_in)
> +        avail = ep->fifo_size - avail;
> +
> +    return avail;
> +}
> +
> +
> +static void
> +usb338x_fifo_flush (struct usb_ep *_ep)
> +{
> +    struct usb338x_ep   *ep;
> +
> +    ep = container_of (_ep, struct usb338x_ep, ep);
> +
> +    if (!_ep || (!ep->desc && ep->num != 0))
> +        return;
> +
> +    if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        return;
> +
> +    writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
> +
> +    (void) readl (&ep->regs->ep_rsp);
> +}
> +
> +
> +static const struct usb_ep_ops usb338x_ep_ops =
> +{
> +    .enable        = usb338x_enable,
> +    .disable       = usb338x_disable,
> +
> +    .alloc_request = usb338x_alloc_request,
> +    .free_request  = usb338x_free_request,
> +
> +    .queue         = usb338x_queue,
> +    .dequeue       = usb338x_dequeue,
> +
> +    .set_halt      = usb338x_set_halt,
> +    .set_wedge     = usb338x_set_wedge,
> +    .fifo_status   = usb338x_fifo_status,
> +    .fifo_flush    = usb338x_fifo_flush,
> +};
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static int
> +usb338x_get_frame (struct usb_gadget *_gadget)
> +{
> +    struct usb338x      *dev;
> +    unsigned long       flags;
> +    u16                 retval;
> +
> +    if (!_gadget)
> +        return -ENODEV;
> +
> +    dev = container_of (_gadget, struct usb338x, gadget);
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    writel (REG_FRAME, &dev->regs->idxaddr);
> +
> +    retval =  readl (&dev->regs->idxdata)  & 0x03ff;
> +
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    return retval;
> +}
> +
> +
> +static int
> +usb338x_wakeup (struct usb_gadget *_gadget)
> +{
> +    struct usb338x      *dev;
> +    u32                 tmp;
> +    unsigned long       flags;
> +
> +    if (!_gadget)
> +        return 0;
> +
> +    dev = container_of (_gadget, struct usb338x, gadget);
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    tmp = readl (&dev->usb->usbctl);
> +
> +    if (tmp & (1 << REMOTE_WAKEUP_ENABLE))
> +    {
> +        writel (1 << GENERATE_RESUME, &dev->usb->usbstat);
> +    }
> +
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    /* pci writes may still be posted */
> +    return 0;
> +}
> +
> +
> +static int
> +usb338x_set_selfpowered (struct usb_gadget *_gadget, int value)
> +{
> +    struct usb338x      *dev;
> +    u32                 tmp;
> +    unsigned long       flags;
> +
> +    if (!_gadget)
> +        return 0;
> +
> +    dev = container_of (_gadget, struct usb338x, gadget);
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    tmp = readl (&dev->usb->usbctl);
> +
> +    if (value)
> +    {
> +        tmp |= (1 << SELF_POWERED_STATUS);
> +        dev->selfpowered = 1;
> +    }
> +
> +    else
> +    {
> +        tmp &= ~(1 << SELF_POWERED_STATUS);
> +        dev->selfpowered = 0;
> +    }
> +
> +    writel (tmp, &dev->usb->usbctl);
> +
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    return 0;
> +}
> +
> +
> +static int
> +usb338x_pullup(struct usb_gadget *_gadget, int is_on)
> +{
> +    struct usb338x  *dev;
> +    u32             tmp;
> +    unsigned long   flags;
> +
> +    if (!_gadget)
> +        return -ENODEV;
> +
> +    dev = container_of (_gadget, struct usb338x, gadget);
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    tmp = readl (&dev->usb->usbctl);
> +    dev->softconnect = (is_on != 0);
> +
> +    if (is_on)
> +        tmp |= (1 << USB_DETECT_ENABLE);
> +    else
> +        tmp &= ~(1 << USB_DETECT_ENABLE);
> +
> +    writel (tmp, &dev->usb->usbctl);
> +
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    return 0;
> +}
> +
> +static void Defect7374_DisableDataEps (struct usb338x *dev)
> +{
> +    /* For Defect 7374, disable data EPs (and more):
> +     *  - This phase undoes the earlier phase of the Defect 7374 workaround,
> +     *    returing ep regs back to normal.
> +     */
> +    struct usb338x_ep   *ep;
> +    int                 i;
> +    unsigned char       ep_sel;
> +    u32 tmp_reg;
> +
> +    for (i = 1; i < 5; i++)
> +    {
> +        ep = &dev->ep[i];
> +        writel (0, &ep->cfg->ep_cfg);
> +    }
> +
> +    // CSROUT, CSRIN, PCIOUT, PCIIN, STATIN, RCIN
> +    for (i = 0; i < 6; i++)
> +    {
> +        writel (0, &dev->dep[i].dep_cfg);
> +    }
> +
> +    for (ep_sel = 0; ep_sel <= 21; ep_sel++)
> +    {
> +        // Select an endpoint for subsequent operations:
> +        tmp_reg = readl (&dev->plregs->pl_ep_ctrl);
> +        writel (((tmp_reg & ~ 0x1f) | ep_sel), &dev->plregs->pl_ep_ctrl);
> +
> +        // Change settings on some selected endpoints
> +        switch (ep_sel)
> +        {
> +            // Undo earlier protocol layer EP programming:
> +        case 2:     // GPEP0 OUT
> +        case 3:     // GPEP0 IN
> +        case 4:     // GPEP1 OUT
> +        case 5:     // GPEP1 IN
> +        case 6:     // GPEP2 OUT
> +        case 7:     // GPEP2 IN
> +        case 8:     // GPEP3 OUT
> +        case 9:     // GPEP3 IN
> +        case 14:    // CSROUT
> +        case 15:    // CSRIN
> +        case 16:    // PCIOUT
> +        case 17:    // PCIIN
> +        case 19:    // STATIN
> +        case 21:    // RCIN
> +
> +            tmp_reg = readl(&dev->plregs->pl_ep_cfg_4);
> +            tmp_reg &=  ~(1 << NON_CTRL_IN_TOLERATE_BAD_DIR);
> +            writel (tmp_reg, &dev->plregs->pl_ep_cfg_4);
> +
> +            tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
> +            tmp_reg |=  (1 << EP_INITIALIZED);
> +            writel (tmp_reg, &dev->plregs->pl_ep_ctrl);
> +
> +            break;
> +        }
> +    }
> +}
> +
> +static void Defect7374_EnableDataEpsAtZero (struct usb338x *dev)
> +{
> +    u32 tmp = 0, tmp_reg;
> +    u32 FsmValue, Scratch;
> +    int i;
> +    unsigned char ep_sel;
> +
> +    writel (SCRATCH, &dev->regs->idxaddr);
> +    Scratch = readl (&dev->regs->idxdata);
> +
> +    FsmValue = Scratch & (0xf << DEFECT7374_FSM_FIELD);
> +    Scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
> +
> +    ///See if firmware needs to set up for workaround:
> +    if (FsmValue != DEFECT7374_FSM_SS_CONTROL_READ)
> +    {
> +        printk (KERN_WARNING "Operate Defect 7374 workaround software this time. (It will operate on cold-reboot and SS connection.)\n");
> +
> +        //GPEPs:
> +        tmp = ( (0 << ENDPOINT_NUMBER) |
> +                (1 << ENDPOINT_DIRECTION) |
> +                (2 << OUT_ENDPOINT_TYPE) |
> +                ((enhanced_mode) ? 1 << OUT_ENDPOINT_ENABLE : 1 << ENDPOINT_ENABLE) |
> +                (2 << IN_ENDPOINT_TYPE) |
> +                (1 << IN_ENDPOINT_ENABLE) );
> +
> +        for (i = 1; i < 5; i++)
> +        {
> +            struct usb338x_ep *ep = &dev->ep[i];
> +            writel (tmp, &ep->cfg->ep_cfg);
> +        }
> +
> +        // CSRIN, PCIIN, STATIN, RCIN
> +        tmp = ((0 << ENDPOINT_NUMBER) | (1 << ENDPOINT_ENABLE));
> +        writel (tmp, &dev->dep[1].dep_cfg);
> +        writel (tmp, &dev->dep[3].dep_cfg);
> +        writel (tmp, &dev->dep[4].dep_cfg);
> +        writel (tmp, &dev->dep[5].dep_cfg);
> +
> +        //XXXXXXXXXXXXX Implemented for development and debug. Can be refined/tuned later.
> +        for (ep_sel = 0; ep_sel <= 21; ep_sel++)
> +        {
> +            // Select an endpoint for subsequent operations:
> +            tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
> +            writel (((tmp_reg & ~ 0x1f) | ep_sel), &dev->plregs->pl_ep_ctrl);
> +
> +            // Change settings on some selected endpoints
> +            switch (ep_sel)
> +            {
> +            case 1:     // EP0 IN
> +
> +                tmp = (readl(&dev->plregs->pl_ep_ctrl) | (1 << CLEAR_ACK_ERROR_CODE) | 0);
> +                writel (tmp, &dev->plregs->pl_ep_ctrl);
> +
> +                break;
> +
> +                // Allow all EPs except control EP (EP0) to tolerate bad direction:
> +            case 2:     // GPEP0 OUT
> +            case 3:     // GPEP0 IN
> +            case 4:     // GPEP1 OUT
> +            case 5:     // GPEP1 IN
> +            case 6:     // GPEP2 OUT
> +            case 7:     // GPEP2 IN
> +            case 8:     // GPEP3 OUT
> +            case 9:     // GPEP3 IN
> +            case 14:    // CSROUT
> +            case 15:    // CSRIN
> +            case 16:    // PCIOUT
> +            case 17:    // PCIIN
> +            case 19:    // STATIN
> +            case 21:    // RCIN
> +
> +                tmp = (readl(&dev->plregs->pl_ep_cfg_4) | (1 << NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
> +                writel (tmp, &dev->plregs->pl_ep_cfg_4);
> +
> +                tmp = readl(&dev->plregs->pl_ep_ctrl) & ~(1 << EP_INITIALIZED);
> +                writel (tmp, &dev->plregs->pl_ep_ctrl);
> +
> +                break;
> +            }
> +        }
> +
> +        // Set FSM to focus on the first Control Read:
> +        //  - Tip: Connection speed is known upon the first setup request.
> +        Scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
> +
> +        writel (SCRATCH, &dev->regs->idxaddr);
> +        writel (Scratch, &dev->regs->idxdata);
> +    }
> +    else
> +    {
> +        printk (KERN_WARNING "Defect 7374 workaround software will NOT operate this time. (It will operate on cold-reboot and SS connection.)\n");
> +    }
> +}
> +
> +static int usb338x_start(struct usb_gadget *_gadget,
> +                         struct usb_gadget_driver *driver);
> +static int usb338x_stop(struct usb_gadget *_gadget,
> +                        struct usb_gadget_driver *driver);
> +
> +static const struct usb_gadget_ops usb338x_ops =
> +{
> +    .get_frame       = usb338x_get_frame,
> +    .wakeup          = usb338x_wakeup,
> +    .set_selfpowered = usb338x_set_selfpowered,
> +    .pullup          = usb338x_pullup,
> +    .udc_start       = usb338x_start,
> +    .udc_stop        = usb338x_stop,
> +};
> +
> +
> +/*-------------------------------------------------------------------------*/
> +
> +/* keeping it simple:
> + * - one bus driver, initted first;
> + * - one function driver, initted second
> + *
> + * most of the work to support multiple usb338x controllers would
> + * be to associate this gadget driver (yes?) with all of them, or
> + * perhaps to bind specific drivers to specific devices.
> + */
> +
> +static void
> +usb_reset (struct usb338x *dev)
> +{
> +    u32 tmp;
> +    u32 Scratch, FsmValue;
> +
> +    dev->gadget.speed = USB_SPEED_UNKNOWN;
> +    (void) readl (&dev->usb->usbctl);
> +
> +    writel ((1 << GPIO3_LED_SELECT) |
> +            (1 << GPIO3_OUTPUT_ENABLE) |
> +            (1 << GPIO2_OUTPUT_ENABLE) |
> +            (1 << GPIO1_OUTPUT_ENABLE) |
> +            (1 << GPIO0_OUTPUT_ENABLE),
> +            &dev->regs->gpioctl);
> +
> +    writel (SCRATCH, &dev->regs->idxaddr);
> +    Scratch = readl (&dev->regs->idxdata);
> +
> +    FsmValue = Scratch & (0xf << DEFECT7374_FSM_FIELD);
> +
> +    /* See if firmware needs to set up for workaround: */
> +    if (FsmValue != DEFECT7374_FSM_SS_CONTROL_READ)
> +    {
> +        INFO (dev, "%s: Defect 7374 FsmValue 0x%08X \n", __FUNCTION__ , FsmValue);
> +    }
> +    else
> +    {
> +        /* disable automatic responses, and irqs */
> +        writel (0, &dev->usb->stdrsp);
> +        writel (0, &dev->regs->pciirqenb0);
> +        writel (0, &dev->regs->pciirqenb1);
> +    }
> +
> +    /* clear old dma and irq state */
> +    for (tmp = 0; tmp < 4; tmp++)
> +    {
> +        struct usb338x_ep   *ep = &dev->ep [tmp + 1];
> +
> +        if (ep->dma)
> +            abort_dma (ep);
> +    }
> +
> +    writel (~0, &dev->regs->irqstat0),
> +           writel (~0, &dev->regs->irqstat1);
> +
> +    if (FsmValue == DEFECT7374_FSM_SS_CONTROL_READ)
> +    {
> +        /* reset, and enable pci */
> +        tmp = readl (&dev->regs->devinit)
> +              | (1 << PCI_ENABLE)
> +              | (1 << FIFO_SOFT_RESET)
> +              | (1 << USB_SOFT_RESET)
> +              | (1 << M8051_RESET);
> +
> +        writel (tmp, &dev->regs->devinit);
> +
> +    }
> +
> +#if 0
> +    /* keeping high bits preserves BAR2 */
> +    writel ((0xffff << PCI_BASE2_RANGE), &dev->regs->fifoctl);
> +#endif
> +
> +    /* always ep-{1,2,3,4} ... maybe not ep-3 or ep-4 */
> +    INIT_LIST_HEAD (&dev->gadget.ep_list);
> +
> +    for (tmp = 1; tmp < n_ep; tmp++)
> +    {
> +        list_add_tail (&dev->ep [tmp].ep.ep_list, &dev->gadget.ep_list);
> +    }
> +}
> +
> +
> +static void
> +usb_reinit (struct usb338x *dev)
> +{
> +    int init_dma;
> +    int i;
> +    u32 Scratch, FsmValue, tmp, val;
> +
> +    /* use_dma changes are ignored till next device re-init */
> +    init_dma = use_dma;
> +
> +    /* basic endpoint init */
> +    for (i = 0; i < n_ep; i++)
> +    {
> +        struct usb338x_ep *ep = &dev->ep [i];
> +
> +        ep->ep.name = ep_name [i];
> +        ep->dev = dev;
> +        ep->num = i;
> +
> +        if (i > 0 && i <= 4)
> +        {
> +            if (init_dma)
> +                ep->dma = &dev->dma [i - 1];
> +        }
> +
> +        if (enhanced_mode)
> +        {
> +            ep->cfg = &dev->epcfg[ne[i]];
> +            ep->regs = (struct usb338x_ep_regs __iomem *) (((unsigned char *)&dev->epregs[ne[i]]) + ep_reg_addr[i]);
> +            ep->fiforegs = &dev->fiforegs[i];
> +        }
> +        else
> +        {
> +            ep->cfg = &dev->epcfg[i];
> +            ep->regs = &dev->epregs[i];
> +            ep->fiforegs = &dev->fiforegs[i];
> +        }
> +
> +        ep->fifo_size = (i != 0) ? 2048 : 512;
> +
> +        ep_reset (dev->regs, ep);
> +    }
> +
> +    dev->ep [0].ep.maxpacket = 512;
> +
> +    dev->gadget.ep0 = &dev->ep [0].ep;
> +    dev->ep [0].stopped = 0;
> +
> +    /* Link layer set up */
> +    writel (SCRATCH, &dev->regs->idxaddr);
> +    Scratch = readl (&dev->regs->idxdata);
> +
> +    FsmValue = Scratch & (0xf << DEFECT7374_FSM_FIELD);
> +
> +    /* See if driver needs to set up for workaround: */
> +    if (FsmValue != DEFECT7374_FSM_SS_CONTROL_READ)
> +    {
> +        INFO (dev, "%s: Defect 7374 FsmValue %08x \n", __FUNCTION__ , FsmValue);
> +    }
> +    else
> +    {
> +        tmp = readl(&dev->usb->usbctl2) &
> +              ~((1 << U1_ENABLE) | (1 << U2_ENABLE) | (1 << LTM_ENABLE));
> +        writel(tmp, &dev->usb->usbctl2);
> +    }
> +
> +    // Hardware Defect and Workaround
> +    val = readl(&dev->ll_lfps_regs->ll_lfps_5);
> +    val &= ~(0xf << TIMER_LFPS_6US);
> +    val |=   0x5 << TIMER_LFPS_6US;
> +    writel (val, &dev->ll_lfps_regs->ll_lfps_5);
> +
> +    val = readl(&dev->ll_lfps_regs->ll_lfps_6);
> +    val &= ~(0xffff << TIMER_LFPS_80US);
> +    val |=   0x0100 << TIMER_LFPS_80US;
> +    writel (val, &dev->ll_lfps_regs->ll_lfps_6);
> +
> +    /* AA_AB Errata. Issue 4. Workaround for SuperSpeed USB
> +       Hot Reset Exit Handshake may Fail in Specific Case using
> +       Default Register Settings. Workaround for Enumeration test.
> +    */
> +    val = readl(&dev->ll_tsn_regs->ll_tsn_counters_2);
> +    val &= ~(0x1f << HOT_TX_NORESET_TS2);
> +    val |=   0x10 << HOT_TX_NORESET_TS2;
> +    writel (val, &dev->ll_tsn_regs->ll_tsn_counters_2);
> +
> +    val = readl(&dev->ll_tsn_regs->ll_tsn_counters_3);
> +    val &= ~(0x1f << HOT_RX_RESET_TS2);
> +    val |=   0x3 << HOT_RX_RESET_TS2;
> +    writel (val, &dev->ll_tsn_regs->ll_tsn_counters_3);
> +
> +    // Set Recovery Idle to Recover bit:
> +    //  - On SS connections, setting Recovery Idle to Recover Fmw improves
> +    //    link robustness with various hosts and hubs.
> +    //  - It is safe to set for all connection speeds; all chip revisions.
> +    //  - R-M-W to leave other bits undisturbed.
> +    //  - Reference PLX TT-7372
> +    val = readl(&dev->ll_chicken_reg->ll_tsn_chicken_bit);
> +    val |= (1 << RECOVERY_IDLE_TO_RECOVER_FMW);
> +    writel (val, &dev->ll_chicken_reg->ll_tsn_chicken_bit);
> +
> +#if 0 // to test with differnt USB3 host controllers
> +    // USB3CV 9.23: Reference Caution, Defect or Errata number.
> +    val = readl(&dev->factory_regs);
> +    val &= 0xFFFCFFFF; // bit[17:16] 11b
> +    val |= 0x00030000;
> +    writel (val, &dev->factory_regs);
> +
> +    val = readl(&dev->phy_regs);
> +    val &= 0xFF3FFFFF; // bit[23:22] 10b
> +    val |= 0x00800000;
> +    writel (val, &dev->phy_regs);
> +#endif
> +
> +    INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
> +
> +    /* disable dedicated endpoints */
> +    writel (0x0D, &dev->dep [0].dep_cfg);
> +    writel (0x0D, &dev->dep [1].dep_cfg);
> +    writel (0x0E, &dev->dep [2].dep_cfg);
> +    writel (0x0E, &dev->dep [3].dep_cfg);
> +    writel (0x0F, &dev->dep [4].dep_cfg);
> +    writel (0x0C, &dev->dep [5].dep_cfg);
> +}
> +
> +
> +static void
> +ep0_start (struct usb338x *dev)
> +{
> +    u32 Scratch, FsmValue;
> +
> +    writel (SCRATCH, &dev->regs->idxaddr);
> +    Scratch = readl (&dev->regs->idxdata);
> +
> +    FsmValue = Scratch & (0xf << DEFECT7374_FSM_FIELD);
> +
> +    if (FsmValue != DEFECT7374_FSM_SS_CONTROL_READ)
> +    {
> +        INFO (dev, "%s: Defect 7374 FsmValue %08x \n", __FUNCTION__ , FsmValue);
> +    }
> +    else
> +    {
> +        writel ( (1 << CLEAR_NAK_OUT_PACKETS_MODE)
> +                 | (1 << SET_EP_HIDE_STATUS_PHASE)
> +                 , &dev->epregs[0].ep_rsp);
> +    }
> +
> +    /*
> +     * hardware optionally handles a bunch of standard requests
> +     * that the API hides from drivers anyway.  have it do so.
> +     * endpoint status/features are handled in software, to
> +     * help pass tests for some dubious behavior.
> +     */
> +    writel ( (1 << SET_ISOCHRONOUS_DELAY)
> +             | (1 << SET_SEL)
> +             | (1 << SET_TEST_MODE)
> +             | (1 << SET_ADDRESS)
> +             | (1 << GET_INTERFACE_STATUS)
> +             | (1 << GET_DEVICE_STATUS)
> +             , &dev->usb->stdrsp);
> +
> +
> +    dev->wakeup_enable = 1;
> +
> +    writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE)
> +             | (dev->softconnect << USB_DETECT_ENABLE)
> +             | (1 << REMOTE_WAKEUP_ENABLE)
> +             , &dev->usb->usbctl);
> +
> +    /* enable irqs so we can see ep0 and general operation  */
> +    writel ( (1 << SETUP_PACKET_PCIE_INTERRUPT_ENABLE)
> +             | (1 << ENDPOINT_0_PCIE_INTERRUPT_ENABLE)
> +             , &dev->regs->pciirqenb0);
> +
> +    writel ( (1 << GLOBAL_PCIE_INTERRUPT_ENABLE)
> +             | (1 << ROOT_PORT_RESET_PCIE_INTERRUPT_ENABLE)
> +             | (1 << SUSPEND_REQUEST_CHANGE_PCIE_INTERRUPT_ENABLE)
> +             | (1 << VBUS_PCIE_INTERRUPT_ENABLE)
> +             , &dev->regs->pciirqenb1);
> +
> +    /* don't leave any writes posted */
> +    (void) readl (&dev->usb->usbctl);
> +}
> +
> +static void Defect7374_EnableDataEpsAtZero (struct usb338x *dev);
> +
> +/* when a driver is successfully registered, it will receive
> + * control requests including set_configuration(), which enables
> + * non-control requests.  then usb traffic follows until a
> + * disconnect is reported.  then a host may connect again, or
> + * the driver might get unbound.
> + */
> +static int
> +usb338x_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver)
> +{
> +    struct usb338x  *dev;
> +    int             retval;
> +    unsigned        i;
> +    u32             value;
> +
> +    /* insist on high speed support from the driver, since
> +     * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
> +     * "must not be used in normal operation"
> +     */
> +    if (!driver || driver->max_speed < USB_SPEED_HIGH || !driver->setup)
> +        return -EINVAL;
> +
> +    dev = container_of (_gadget, struct usb338x, gadget);
> +
> +    for (i = 0; i < n_ep; i++)
> +        dev->ep [i].irqs = 0;
> +
> +    /* hook up the driver ... */
> +    dev->softconnect = 1;
> +    driver->driver.bus = NULL;
> +    dev->driver = driver;
> +    dev->gadget.dev.driver = &driver->driver;
> +
> +    retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
> +
> +    if (retval) goto err_unbind;
> +
> +    retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
> +
> +    if (retval) goto err_func;
> +
> +    /* ... then enable host detection and ep0; and we're ready
> +     * for set_configuration as well as eventual disconnect.
> +     */
> +
> +    value = readl (&dev->regs->gpioctl);
> +    value |= GPIO2_DATA;
> +
> +    writel (value, &dev->regs->gpioctl);
> +
> +    Defect7374_EnableDataEpsAtZero(dev);
> +
> +    ep0_start (dev);
> +
> +    DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n",
> +           driver->driver.name,
> +           readl (&dev->usb->usbctl),
> +           readl (&dev->usb->stdrsp));
> +
> +    /* pci writes may still be posted */
> +    return 0;
> +
> +err_func:
> +    device_remove_file (&dev->pdev->dev, &dev_attr_function);
> +
> +err_unbind:
> +    driver->unbind (&dev->gadget);
> +    dev->gadget.dev.driver = NULL;
> +    dev->driver = NULL;
> +
> +    return retval;
> +}
> +
> +
> +static void
> +stop_activity (struct usb338x *dev, struct usb_gadget_driver *driver)
> +{
> +    int     i;
> +
> +    /* don't disconnect if it's not connected */
> +    if (dev->gadget.speed == USB_SPEED_UNKNOWN)
> +        driver = NULL;
> +
> +    /* stop hardware; prevent new request submissions;
> +     * and kill any outstanding requests.
> +     */
> +    usb_reset (dev);
> +
> +    for (i = 0; i < n_ep; i++)
> +        nuke (&dev->ep [i]);
> +
> +    usb_reinit (dev);
> +}
> +
> +
> +static int
> +usb338x_stop(struct usb_gadget *_gadget, struct usb_gadget_driver *driver)
> +{
> +    struct usb338x  *dev;
> +    unsigned long   flags;
> +    u32             value;
> +
> +    dev = container_of (_gadget, struct usb338x, gadget);
> +
> +    spin_lock_irqsave (&dev->lock, flags);
> +
> +    stop_activity (dev, driver);
> +
> +    spin_unlock_irqrestore (&dev->lock, flags);
> +
> +    dev->gadget.dev.driver = NULL;
> +    dev->driver = NULL;
> +
> +    value = readl (&dev->regs->gpioctl);
> +    value &= ~GPIO2_DATA;
> +
> +    writel (value, &dev->regs->gpioctl);
> +
> +    device_remove_file (&dev->pdev->dev, &dev_attr_function);
> +    device_remove_file (&dev->pdev->dev, &dev_attr_queues);
> +
> +    DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
> +
> +    return 0;
> +}
> +
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static void
> +gadget_release (struct device *_dev)
> +{
> +    struct usb338x  *dev = dev_get_drvdata (_dev);
> +
> +    kfree (dev);
> +}
> +
> +
> +/* tear down the binding between this driver and the pci device */
> +static void
> +usb338x_remove (struct pci_dev *pdev)
> +{
> +    struct usb338x      *dev = pci_get_drvdata (pdev);
> +
> +    usb_del_gadget_udc(&dev->gadget);
> +
> +    BUG_ON(dev->driver);
> +
> +    /* then clean up the resources we allocated during probe() */
> +    writel (readl (&dev->regs->gpioctl) & ~0x0f, &dev->regs->gpioctl);
> +
> +    if (dev->requests)
> +    {
> +        int     i;
> +        for (i = 1; i < 5; i++)
> +        {
> +            if (!dev->ep [i].dummy)
> +                continue;
> +
> +            pci_pool_free (dev->requests, dev->ep [i].dummy,
> +                           dev->ep [i].td_dma);
> +        }
> +        pci_pool_destroy (dev->requests);
> +    }
> +
> +    if (dev->got_irq)
> +        free_irq (pdev->irq, dev);
> +
> +    if (use_msi)
> +        pci_disable_msi(pdev);
> +
> +    if (dev->regs)
> +        iounmap (dev->regs);
> +
> +    if (dev->region)
> +        release_mem_region (pci_resource_start (pdev, 0),
> +                            pci_resource_len (pdev, 0));
> +
> +    if (dev->enabled)
> +        pci_disable_device (pdev);
> +
> +    device_unregister (&dev->gadget.dev);
> +    device_remove_file (&pdev->dev, &dev_attr_registers);
> +    pci_set_drvdata (pdev, NULL);
> +
> +    INFO (dev, "unbind\n");
> +}
> +
> +
> +/* wrap this driver around the specified device, but
> + * don't respond over USB until a gadget driver binds to us.
> + */
> +
> +static int
> +usb338x_probe (struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +    struct usb338x      *dev;
> +    unsigned long       resource, len;
> +    void       __iomem  *base = NULL;
> +    int                 retval, i;
> +    u32                 Scratch, FsmValue;
> +
> +
> +    /* alloc, and start init */
> +    dev = kzalloc (sizeof * dev, GFP_KERNEL);
> +
> +    if (dev == NULL)
> +    {
> +        retval = -ENOMEM;
> +
> +        goto done;
> +    }
> +
> +    pci_set_drvdata (pdev, dev);
> +
> +    spin_lock_init (&dev->lock);
> +
> +    dev->pdev             = pdev;
> +    dev->gadget.ops       = &usb338x_ops;
> +    //   dev->gadget.max_speed = USB_SPEED_HIGH;
> +    dev->gadget.max_speed = USB_SPEED_SUPER;
> +
> +    /* the "gadget" abstracts/virtualizes the controller */
> +    dev_set_name(&dev->gadget.dev, "gadget");
> +
> +    dev->gadget.dev.parent   = &pdev->dev;
> +    dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
> +    dev->gadget.dev.release  = gadget_release;
> +    dev->gadget.name         = driver_name;
> +
> +    /* now all the pci goodies ... */
> +    if (pci_enable_device (pdev) < 0)
> +    {
> +        retval = -ENODEV;
> +        goto done;
> +    }
> +    dev->enabled = 1;
> +
> +    resource = pci_resource_start (pdev, 0);
> +    len = pci_resource_len (pdev, 0);
> +
> +    if (!request_mem_region (resource, len, driver_name))
> +    {
> +        DEBUG (dev, "controller already in use\n");
> +
> +        retval = -EBUSY;
> +
> +        goto done;
> +    }
> +
> +    dev->region = 1;
> +
> +    base = ioremap_nocache (resource, len);
> +
> +    if (base == NULL)
> +    {
> +        DEBUG (dev, "can't map memory\n");
> +        retval = -EFAULT;
> +        goto done;
> +    }
> +
> +    dev->regs           = (struct usb338x_regs __iomem *) base;
> +    dev->usb            = (struct usb338x_usb_regs __iomem *) (base + 0x0080);
> +    dev->pci            = (struct usb338x_pci_regs __iomem *) (base + 0x0100);
> +    dev->dma            = (struct usb338x_dma_regs __iomem *) (base + 0x0180);
> +    dev->dep            = (struct usb338x_dep_regs __iomem *) (base + 0x0200);
> +    dev->epcfg          = (struct usb338x_ep_cfg __iomem *) (base + 0x0300);
> +    dev->epregs         = (struct usb338x_ep_regs __iomem *) (base + 0x0304);
> +    dev->fiforegs       = (struct usb338x_fifo_regs __iomem *) (base + 0x0500);
> +    dev->llregs         = (struct usb338x_ll_regs __iomem *) (base + 0x0700);
> +    dev->ll_lfps_regs   = (struct usb338x_ll_lfps_regs __iomem *) (base + 0x0748);
> +    dev->ll_tsn_regs    = (struct usb338x_ll_tsn_regs __iomem *) (base + 0x077c);
> +    dev->ll_chicken_reg = (struct usb338x_ll_chi_regs __iomem *) (base + 0x079c);
> +    dev->plregs         = (struct usb338x_pl_regs __iomem *) (base + 0x0800);
> +    dev->factory_regs   = (struct usb338x_factory_regs __iomem *) (base + 0x0B80);
> +    dev->phy_regs       = (struct usb338x_phy_regs __iomem *) (base + 0x0BE0);
> +
> +    u32_i = readl(&dev->usb->usbstat);
> +
> +    if (u32_i == 0xFFFFFFFF)
> +    {
> +        DEBUG (dev, "usb338x not existed\n");
> +        retval = -ENODEV;
> +
> +        goto done;
> +    }
> +
> +    // Enhanced or Legacy Mode
> +    enhanced_mode = (u32_i & (1 << 11)) ? 1 : 0;
> +    n_ep = (enhanced_mode) ? 9 : 5;
> +    // n_ep = (enhanced_mode) ? 5 : 5;
> +
> +    /* put into initial config, link up all endpoints */
> +
> +    writel (SCRATCH, &dev->regs->idxaddr);
> +    Scratch = readl (&dev->regs->idxdata);
> +
> +    FsmValue = Scratch & (0xf << DEFECT7374_FSM_FIELD);
> +
> +    /* See if firmware needs to set up for workaround: */
> +    if (FsmValue == DEFECT7374_FSM_SS_CONTROL_READ)
> +    {
> +        writel (0, &dev->usb->usbctl);
> +    }
> +
> +    usb_reset (dev);
> +    usb_reinit (dev);
> +
> +    /* irq setup after old hardware is cleaned up */
> +    if (!pdev->irq)
> +    {
> +        ERROR (dev, "No IRQ.  Check PCI setup!\n");
> +        retval = -ENODEV;
> +        goto done;
> +    }
> +
> +    if (use_msi)
> +    {
> +        if (pci_enable_msi(pdev))
> +        {
> +            printk ("Failed to enable MSI mode\n");
> +        }
> +    }
> +
> +    if (request_irq (pdev->irq, usb338x_irq, IRQF_SHARED, driver_name, dev) != 0)
> +    {
> +        ERROR (dev, "request interrupt %d failed\n", pdev->irq);
> +        retval = -EBUSY;
> +
> +        goto done;
> +    }
> +
> +    dev->got_irq = 1;
> +
> +    /* DMA setup */
> +    /* NOTE:  we know only the 32 LSBs of dma addresses may be nonzero */
> +    dev->requests = pci_pool_create ("requests", pdev,
> +                                     sizeof (struct usb338x_dma),
> +                                     0 /* no alignment requirements */,
> +                                     0 /* or page-crossing issues */);
> +
> +    if (!dev->requests)
> +    {
> +        DEBUG (dev, "can't get request pool\n");
> +        retval = -ENOMEM;
> +        goto done;
> +    }
> +
> +    for (i = 1; i < 5; i++)
> +    {
> +        struct usb338x_dma  *td;
> +
> +        td = pci_pool_alloc (dev->requests, GFP_KERNEL,
> +                             &dev->ep [i].td_dma);
> +        if (!td)
> +        {
> +            DEBUG (dev, "can't get dummy %d\n", i);
> +            retval = -ENOMEM;
> +            goto done;
> +        }
> +
> +        td->dmacount = 0;   /* not VALID */
> +        td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
> +        td->dmadesc = td->dmaaddr;
> +        dev->ep [i].dummy = td;
> +    }
> +
> +    pci_set_master (pdev);
> +    pci_try_set_mwi (pdev);
> +
> +    /* ... also flushes any posted pci writes */
> +    writel (REG_CHIPREV, &dev->regs->idxaddr);
> +
> +    dev->chiprev = readl (&dev->regs->idxdata) & 0xffff;
> +
> +    /* done */
> +    INFO (dev, "%s\n", driver_desc);
> +    INFO (dev, "irq %d, pci mem %p, chip rev %04x\n",
> +          pdev->irq, base, dev->chiprev);
> +    INFO (dev, "version: " DRIVER_VERSION "; dma %s %s\n",
> +          use_dma
> +          ? (use_dma_chaining ? "chaining" : "enabled")
> +              : "disabled", enhanced_mode ? "enhanced mode" : "legacy mode");
> +
> +    retval = device_register (&dev->gadget.dev);
> +
> +    if (retval) goto done;
> +
> +    retval = device_create_file (&pdev->dev, &dev_attr_registers);
> +
> +    if (retval) goto done;
> +
> +    retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
> +
> +    if (retval)
> +        goto done;
> +
> +    return 0;
> +
> +done:
> +
> +    if (dev)
> +        usb338x_remove (pdev);
> +
> +    return retval;
> +}
> +
> +
> +/* make sure the board is quiescent; otherwise it will continue
> + * generating IRQs across the upcoming reboot.
> + */
> +
> +static void
> +usb338x_shutdown (struct pci_dev *pdev)
> +{
> +    struct usb338x    *dev = pci_get_drvdata (pdev);
> +
> +    /* disable IRQs */
> +    writel (0, &dev->regs->pciirqenb0);
> +    writel (0, &dev->regs->pciirqenb1);
> +
> +    /* disable the pullup so the host will think we're gone */
> +    writel (0, &dev->usb->usbctl);
> +}
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static void
> +allow_status (struct usb338x_ep *ep)
> +{
> +    /* Control Status Phase Handshake was set by the chip when the setup
> +     * packet arrived. While set, the chip automatically NAKs the host's
> +     * Status Phase tokens.
> +     */
> +    writel (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE, &ep->regs->ep_rsp);
> +
> +    ep->stopped = 1;
> +
> +    /* TD 9.9 Halt Endpoint test.  TD 9.22 set feature test. */
> +    ep->responded = 0;
> +}
> +
> +
> +static void
> +set_fifo_bytecount (struct usb338x_ep *ep, unsigned count)
> +{
> +    u32 tmp;
> +
> +    tmp = readl (&ep->cfg->ep_cfg) & (~(0x07 << EP_FIFO_BYTE_COUNT));
> +
> +    writel (tmp | (count << EP_FIFO_BYTE_COUNT), &ep->cfg->ep_cfg);
> +}
> +
> +
> +static void
> +ep_stdrsp (struct usb338x_ep *ep, int value, int wedged)
> +{
> +    /* set/clear, then synch memory views with the device */
> +    if (value)
> +    {
> +        ep->stopped = 1;
> +
> +        if (ep->num == 0)
> +        {
> +            ep->dev->protocol_stall = 1;
> +        }
> +        else
> +        {
> +            if (ep->dma)
> +                ep_stop_dma (ep);
> +
> +            ep_stall (ep, true);
> +        }
> +
> +        if (wedged)
> +            ep->wedged = 1;
> +    }
> +    else
> +    {
> +        ep->stopped = 0;
> +        ep->wedged = 0;
> +
> +        ep_stall (ep, false);
> +
> +        /* Flush the queue */
> +        if (!list_empty(&ep->queue))
> +        {
> +            struct usb338x_request *req = list_entry(ep->queue.next, struct usb338x_request, queue);
> +
> +            if (ep->dma)
> +                resume_dma (ep);
> +            else
> +            {
> +                if (ep->is_in)
> +                    write_fifo(ep, &req->req);
> +                else
> +                {
> +                    if (read_fifo(ep, req))
> +                        complete_req (ep, req, 0);
> +                }
> +            }
> +        }
> +    }
> +}
> +
> +
> +static void
> +ep_stall (struct usb338x_ep *ep, int stall)
> +{
> +    struct usb338x *dev = ep->dev;
> +    u32             val;
> +
> +    if (stall)
> +    {
> +        writel ((1 << SET_ENDPOINT_HALT) |
> +                // (1 << SET_NAK_PACKETS) |
> +                (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
> +                &ep->regs->ep_rsp);
> +
> +        ep->is_halt = 1;
> +    }
> +    else
> +    {
> +
> +        if (dev->gadget.speed == USB_SPEED_SUPER)
> +        {
> +            /* Workaround for SS SeqNum not cleared via Endpoint Halt (Clear) bit.*/
> +            // select endpoint
> +            val = readl(&dev->plregs->pl_ep_ctrl);
> +            val = (val & ~ 0x1f) | ep_pl[ep->num];
> +            writel (val, &dev->plregs->pl_ep_ctrl);
> +
> +            val |= (1 << SEQUENCE_NUMBER_RESET);
> +            writel (val, &dev->plregs->pl_ep_ctrl);
> +        }
> +
> +        val = readl(&ep->regs->ep_rsp);
> +        val |= (1 << CLEAR_ENDPOINT_HALT) | (1 << CLEAR_ENDPOINT_TOGGLE);
> +        writel (val
> +                // | (1 << CLEAR_NAK_PACKETS)
> +                // | (1 << CLEAR_ENDPOINT_TOGGLE)
> +                , &ep->regs->ep_rsp);
> +
> +        ep->is_halt = 0;
> +
> +        val = readl(&ep->regs->ep_rsp);
> +    }
> +
> +}
> +
> +
> +static void
> +resume_dma (struct usb338x_ep *ep)
> +{
> +    writel (readl (&ep->dma->dmactl) | (1 << DMA_ENABLE), &ep->dma->dmactl);
> +
> +    ep->dma_started = true;
> +}
> +
> +
> +static void
> +ep_stop_dma (struct usb338x_ep *ep)
> +{
> +    writel (readl (&ep->dma->dmactl) & ~(1 << DMA_ENABLE), &ep->dma->dmactl);
> +    spin_stop_dma (ep->dma);
> +
> +    ep->dma_started = false;
> +}
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static const struct pci_device_id pci_ids [] =
> +{
> +    {
> +        .class      =  ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
> +        .class_mask =  ~0,
> +        .vendor     =  0x10b5,
> +        .device     =  0x3380,
> +        .subvendor  =  PCI_ANY_ID,
> +        .subdevice  =  PCI_ANY_ID,
> +    },
> +    {
> +        .class      =  ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
> +        .class_mask =  ~0,
> +        .vendor     =  0x10b5,
> +        .device     =  0x3382,
> +        .subvendor  =  PCI_ANY_ID,
> +        .subdevice  =  PCI_ANY_ID,
> +
> +    },
> +    { /* end: all zeroes */ }
> +};
> +MODULE_DEVICE_TABLE (pci, pci_ids);
> +
> +
> +/* pci driver glue; this is a "new style" PCI driver module */
> +static struct pci_driver usb338x_pci_driver =
> +{
> +    .name     = (char *) driver_name,
> +    .id_table = pci_ids,
> +
> +    .probe    = usb338x_probe,
> +    .remove   = usb338x_remove,
> +    .shutdown = usb338x_shutdown,
> +
> +};
> +
> +
> +static int
> +usb338x_pdc_register(void)
> +{
> +    return pci_register_driver(&usb338x_pci_driver);
> +}
> +
> +
> +static void
> +usb338x_pdc_unregister(void)
> +{
> +    pci_unregister_driver(&usb338x_pci_driver);
> +}
> +
> +
> +static int __init
> +init (void)
> +{
> +    int r_val;
> +
> +    if (!use_dma)
> +        use_dma_chaining = 0;
> +
> +    r_val = usb338x_pdc_register();
> +
> +    return r_val;
> +}
> +module_init (init);
> +
> +
> +static void __exit
> +cleanup (void)
> +{
> +    usb338x_pdc_unregister();
> +}
> +module_exit (cleanup);
> +
> +
> +MODULE_DESCRIPTION ("usb338x");
> +MODULE_AUTHOR ("PLX Technology, Inc.");
> +MODULE_LICENSE ("GPL");
> diff --git a/drivers/usb/gadget/usb338x.h b/drivers/usb/gadget/usb338x.h
> new file mode 100644
> index 0000000..93c6301
> --- /dev/null
> +++ b/drivers/usb/gadget/usb338x.h
> @@ -0,0 +1,952 @@
> +/******************************************************************************
> + * Driver for PLX USB3380/USB3382 USB device controller
> + *
> + * Copyright (c) PLX Technology, Inc.
> + *
> + * PLX Technology Inc. licenses this source file under the GNU Lesser General
> + * Public License (LGPL) version 2.  This program is free software; the source
> + * file may be modified or redistributed under the terms of the LGPL and
> + * without express permission from PLX Technology.
> + *
> + * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
> + * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  PLX makes no guarantee
> + * or representations regarding the use of, or the results of the use of,
> + * the software and documentation in terms of correctness, accuracy,
> + * reliability, currentness, or otherwise; and you rely on the software,
> + * documentation and results solely at your own risk.
> + *
> + * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
> + * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
> + * OF ANY KIND.
> + *
> + * Specs and errata are available from http://www.plxtech.com.
> + *
> + ******************************************************************************/
> +
> +/******************************************************************************
> + *
> + * File Name:
> + *
> + *     usb338x.h
> + *
> + * Revision: v3.0, 2-5-2014
> + *
> + * Description:
> + *
> + *     The header file for the PLX usb3380/3382 device driver
> + *
> + *****************************************************************************/
> +
> +#ifndef __USB338x_H
> +#define __USB338x_H
> +
> +/* USB338x MEMORY MAPPED REGISTERS
> + *
> + * The register layout came from the chip documentation, and the bit
> + * number definitions were extracted from chip specification.
> + *
> + * Use the shift operator ('<<') to build bit masks, with readl/writel
> + * to access the registers through PCI.
> + */
> +
> +/* main registers, BAR0 + 0x0000 */
> +struct usb338x_regs
> +{
> +    /* offset 0x0000 */
> +    u32   devinit;
> +#define     LOCAL_CLOCK_FREQUENCY                               8  /* 11:8 */
> +#define     FORCE_PCI_RESET                                     7
> +#define     PCI_ID                                              6
> +#define     PCI_ENABLE                                          5
> +#define     FIFO_SOFT_RESET                                     4
> +#define     CONFIGURATION_SOFT_RESET                            3
> +#define     PCI_SOFT_RESET                                      2
> +#define     USB_SOFT_RESET                                      1
> +#define     M8051_RESET                                         0
> +    u32   eectl;
> +#define     EEPROM_ADDRESS_WIDTH                                23
> +#define     EEPROM_CHIP_SELECT_ACTIVE                           22
> +#define     EEPROM_PRESENT                                      21
> +#define     EEPROM_VALID                                        20
> +#define     EEPROM_BUSY                                         19
> +#define     EEPROM_CHIP_SELECT_ENABLE                           18
> +#define     EEPROM_BYTE_READ_START                              17
> +#define     EEPROM_BYTE_WRITE_START                             16
> +#define     EEPROM_READ_DATA                                    8
> +#define     EEPROM_WRITE_DATA                                   0
> +    u32   eeclkfreq;
> +    u32   _unused0;
> +    /* offset 0x0010 */
> +    u32   pciirqenb0;  /* PCIE Interrupt Request Enable 0 */
> +#define     GPEP3_IN_PCIE_INTERRUPT_ENABLE                      20
> +#define     GPEP2_IN_PCIE_INTERRUPT_ENABLE                      19
> +#define     GPEP1_IN_PCIE_INTERRUPT_ENABLE                      18
> +#define     GPEP0_IN_PCIE_INTERRUPT_ENABLE                      17
> +#define     USB_IN_FIFO_TIMEOUT_PCIE_INTERRUPT_ENABLE           11
> +#define     USB_CONFIGURATION_RETRY_INTERRUPT_ENABLE            10
> +#define     USB2PCIE_TLP_DRAINED_PORT_1_PCIE_INTERRUPT_ENABLE   9
> +#define     USB2PCIE_TLP_DRAINED_PORT_0_PCIE_INTERRUPT_ENABLE   8
> +#define     SETUP_PACKET_PCIE_INTERRUPT_ENABLE                  7
> +#define     GPEP3_OUT_PCIE_INTERRUPT_ENABLE                     4
> +#define     GPEP2_OUT_PCIE_INTERRUPT_ENABLE                     3
> +#define     GPEP1_OUT_PCIE_INTERRUPT_ENABLE                     2
> +#define     GPEP0_OUT_PCIE_INTERRUPT_ENABLE                     1
> +#define     ENDPOINT_0_PCIE_INTERRUPT_ENABLE                    0
> +    u32   pciirqenb1; /* PCIE Interrupt Request Enable 1 */
> +#define     GLOBAL_PCIE_INTERRUPT_ENABLE                            31
> +#define     PCIE_ENDPOINT_POWER_MANAGEMENT_PCIE_INTERRUPT_ENABLE    30
> +#define     PCIE_HOT_RESET_PCIE_INTERRUPT_ENABLE                    29
> +#define     PCIE_DL_DOWN_STATE_CHANGE_PCIE_INTERRUPT_ENABLE         28
> +#define     POWER_STATE_CHANGE_PCIE_INTERRUPT_ENABLE                27
> +#define     PCI_PARITY_ERROR_PCIE_INTERRUPT_ENABLE                  25
> +#define     PCI_MASTER_ABORT_RECEIVED_PCIE_INTERRUPT_ENABLE         20
> +#define     PCI_TARGET_ABORT_RECEIVED_PCIE_INTERRUPT_ENABLE         19
> +#define     PCIE_HOT_PLUG_PCIE_INTERRUPT_ENABLE                     18
> +#define     PCI_MASTER_CYCLE_DONE_PCIE_INTERRUPT_ENABLE             16
> +#define     SOF_DOWNCOUNT_PCIE_INTERRUPT_ENABLE                     14
> +#define     GPIO_PCIE_INTERRUPT_ENABLE                              13
> +#define     DMA_3_PCIE_INTERRUPT_ENABLE                             12
> +#define     DMA_2_PCIE_INTERRUPT_ENABLE                             11
> +#define     DMA_1_PCIE_INTERRUPT_ENABLE                             10
> +#define     DMA_0_PCIE_INTERRUPT_ENABLE                              9
> +#define     EEPROM_DONE_PCIE_INTERRUPT_ENABLE                        8
> +#define     VBUS_PCIE_INTERRUPT_ENABLE                               7
> +#define     CONTROL_STATUS_PCIE_INTERRUPT_ENABLE                     6
> +#define     ROOT_PORT_RESET_PCIE_INTERRUPT_ENABLE                    4
> +#define     SUSPEND_REQUEST_PCIE_INTERRUPT_ENABLE                    3
> +#define     SUSPEND_REQUEST_CHANGE_PCIE_INTERRUPT_ENABLE             2
> +#define     RESUME_PCIE_INTERRUPT_ENABLE                             1
> +#define     SOF_PCIE_INTERRUPT_ENABLE                                0
> +    u32   cpuirqenb0;    /* 8051 Interrupt Request Enable 0 */
> +#define     GPEP3_IN_8051_INTERRUPT_ENABLE                      20
> +#define     GPEP2_IN_8051_INTERRUPT_ENABLE                      19
> +#define     GPEP1_IN_8051_INTERRUPT_ENABLE                      18
> +#define     GPEP0_IN_8051_INTERRUPT_ENABLE                      17
> +#define     USB_IN_FIFO_TIMEOUT_8051_INTERRUPT_ENABLE           11
> +#define     USB_CFG_RETRY_8051_INTERRUPT_ENABLE                 10
> +#define     USB2PCIE_TLP_DRAINED_PORT_1_8051_INTERRUPT_ENABLE   9
> +#define     USB2PCIE_TLP_DRAINED_PORT_0_8051_INTERRUPT_ENABLE   8
> +#define     SETUP_PACKET_8051_INTERRUPT_ENABLE                  7
> +#define     GPEP3_OUT_8051_INTERRUPT_ENABLE                     4
> +#define     GPEP2_OUT_8051_INTERRUPT_ENABLE                     3
> +#define     GPEP1_OUT_8051_INTERRUPT_ENABLE                     2
> +#define     GPEP0_OUT_8051_INTERRUPT_ENABLE                     1
> +#define     ENDPOINT_0_8051_INTERRUPT_ENABLE                    0
> +    u32       cpuirqenb1;
> +#define     GLOBAL_8051_INTERRUPT_ENABLE                        31
> +#define     PCIE_ENDPOINT_POWER_MGMT_8051_INTERRUPT_ENABLE      30
> +#define     PCIE_HOT_RESET_8051_INTERRUPT_ENABLE                29
> +#define     PCIE_DL_DOWN_STATE_CHANGE_8051_INTERRUPT_ENABLE     28
> +#define     POWER_STATE_CHANGE_8051_INTERRUPT_ENABLE            27
> +#define     PCI_PARITY_ERROR_8051_INTERRUPT_ENABLE              25
> +#define     PCI_INTA_8051_INTERRUPT_ENABLE                      24
> +#define     PCI_MASTER_ABORT_RECEIVED_8051_INTERRUPT_ENABLE     20
> +#define     PCI_TARGET_ABORT_RECEIVED_8051_INTERRUPT_ENABLE     19
> +#define     PCIE_HOT_PLUG_8051_INTERRUPT_ENABLE                 18
> +#define     PCI_MASTER_CYCLE_DONE_8051_INTERRUPT_ENABLE         16
> +#define     SOF_DOWNCOUNT_8051_INTERRUPT_ENABLE                 14
> +#define     GPIO_8051_INTERRUPT_ENABLE                          13
> +#define     DMA_3_8051_INTERRUPT_ENABLE                         12
> +#define     DMA_2_8051_INTERRUPT_ENABLE                         11
> +#define     DMA_1_8051_INTERRUPT_ENABLE                         10
> +#define     DMA_0_8051_INTERRUPT_ENABLE                         9
> +#define     SERIAL_EEPROM_DONE_8051_INTERRUPT_ENABLE            8
> +#define     VBUS_8051_INTERRUPT_ENABLE                          7
> +#define     CONTROL_STATUS_8051_INTERRUPT_ENABLE                6
> +#define     ROOT_PORT_RESET_8051_INTERRUPT_ENABLE               4
> +#define     SUSPEND_REQUEST_8051_INTERRUPT_ENABLE               3
> +#define     SUSPEND_REQUEST_CHANGE_8051_INTERRUPT_ENABLE        2
> +#define     RESUME_8051_INTERRUPT_ENABLE                        1
> +#define     SOF_8051_INTERRUPT_ENABLE                           0
> +    /* offset 0x0020 */
> +    u32       usbirqenb0; /* Used only by firmware running on the 8051 */
> +    u32       usbirqenb1;     /* Reserved in Legacy Adapter mode */
> +#define     USB_INTERRUPT_ENABLE                                31
> +#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
> +#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
> +#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
> +#define     PCI_INTA_INTERRUPT_ENABLE                           24
> +#define     PCI_PME_INTERRUPT_ENABLE                            23
> +#define     PCI_SERR_INTERRUPT_ENABLE                           22
> +#define     PCI_PERR_INTERRUPT_ENABLE                           21
> +#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
> +#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
> +#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
> +#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
> +#define     GPIO_INTERRUPT_ENABLE                               13
> +#define     DMA_3_INTERRUPT_ENABLE                              12
> +#define     DMA_2_INTERRUPT_ENABLE                              11
> +#define     DMA_1_INTERRUPT_ENABLE                              10
> +#define     DMA_0_INTERRUPT_ENABLE                              9
> +#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
> +#define     VBUS_INTERRUPT_ENABLE                               7
> +#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
> +#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
> +#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
> +#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
> +#define     RESUME_INTERRUPT_ENABLE                             1
> +#define     SOF_INTERRUPT_ENABLE                                0
> +    u32   irqstat0;
> +    /* GPEP[0..3]_IN_PCIE_INTERRUPT_STATUS - Enahnced Mode only */
> +#define     GPEP3_IN_PCIE_INTERRUPT_STATUS                      20
> +#define     GPEP2_IN_PCIE_INTERRUPT_STATUS                      19
> +#define     GPEP1_IN_PCIE_INTERRUPT_STATUS                      18
> +#define     GPEP0_IN_PCIE_INTERRUPT_STATUS                      17
> +#define     INTA_ASSERTED                                       12
> +#define     USB_IN_FIFO_TIMEOUT_INTERRUPT_STATUS                11
> +#define     USB_CONFIGURATION_RETRY_INTERRUPT_STATUS            10
> +#define     USB2PCIE_TLP_DRAINED_PORT_1_STATUS                  9
> +#define     USB2PCIE_TLP_DRAINED_PORT_0_STATUS                  8
> +#define     SETUP_PACKET_INTERRUPT_STATUS                       7
> +#define     GPEP3_OUT_PCIE_INTERRUPT_STATUS                     4
> +#define     GPEP2_OUT_PCIE_INTERRUPT_STATUS                     3
> +#define     GPEP1_OUT_PCIE_INTERRUPT_STATUS                     2
> +#define     GPEP0_OUT_PCIE_INTERRUPT_STATUS                     1
> +#define     ENDPOINT_0_INTERRUPT_STATUS                         0
> +    u32   irqstat1;
> +#define     PCIE_ENDPOINT_POWER_MGMT_INTERRUPT                  30
> +#define     PCIE_HOT_RESET_INTERRUPT                            29
> +#define     PCIE_DL_DOWN_STATE_CHANGE_INTERRUPT                 28
> +#define     POWER_STATE_CHANGE_INTERRUPT                        27
> +#define     PCI_PARITY_ERROR_INTERRUPT                          25
> +#define     PCI_INTA_INTERRUPT                                  24
> +#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT                 20
> +#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT                 19
> +#define     PCIE_HOT_PLUG_INTERRUPT                             18
> +#define     PCI_MASTER_CYCLE_DONE_INTERRUPT                     16
> +#define     SOF_DOWNCOUNT_INTERRUPT                             14
> +#define     GPIO_INTERRUPT                                      13
> +#define     DMA_3_INTERRUPT                                     12
> +#define     DMA_2_INTERRUPT                                     11
> +#define     DMA_1_INTERRUPT                                     10
> +#define     DMA_0_INTERRUPT                                     9
> +#define     SERIAL_EEPROM_DONE_INTERRUPT                        8
> +#define     VBUS_INTERRUPT                                      7
> +#define     CONTROL_STATUS_INTERRUPT                            6
> +#define     ROOT_PORT_RESET_INTERRUPT                           4
> +#define     SUSPEND_REQUEST_INTERRUPT                           3
> +#define     SUSPEND_REQUEST_CHANGE_INTERRUPT                    2
> +#define     RESUME_INTERRUPT                                    1
> +#define     SOF_INTERRUPT                                       0
> +    /* offset 0x0030 */
> +    u32   idxaddr;
> +#define     IDXREG_DIAG            0x00
> +#define     IDXREG_PKTLEN          0x01
> +#define     IDXREG_FRAME           0x02
> +#define     IDXREG_CHIPREV         0x03
> +#define     IDXREG_UFRAME          0x04
> +#define     IDXREG_FRAME_COUNT     0x05
> +#define     IDXREG_HS_MAXPOWER     0x06
> +#define     IDXREG_FS_MAXPOWER     0x07
> +#define     IDXREG_HS_INTPOLL_RATE 0x08
> +#define     IDXREG_FS_INTPOLL_RATE 0x09
> +#define     HS_NAK_RATE            0x0a
> +#define     SCRATCH                0x0b
> +    /* Index 0ch - 1fh: Reserved */
> +    /* Index 20h + n * 10h: GPEP[3:0/Out/In]_HS_MAXPKT */
> +    u32   idxdata;
> +    u32   fifoctl;
> +#define     PCI_BASE2_RANGE                                     16  /* 31:16 */
> +#define     IGNORE_FIFO_AVAILABILITY                            3
> +#define     PCI_BASE2_SELECT                                    2
> +#define     FIFO_CONFIGURATION_SELECT                           0   /* 1:0 */
> +    u32   bar2ctl;
> +#define     PCI_BAR2_RANGE                                      16
> +    /* offset 0x0040 */
> +    u32   memaddr;
> +#define     START                                               28
> +#define     DIRECTION                                           27
> +#define     FIFO_DIAGNOSTIC_SELECT                              24
> +#define     MEMORY_ADDRESS                                      0
> +    u32   memdata0;
> +    u32   memdata1;
> +    u32   _unused3;
> +    /* offset 0x0050 */
> +    u32   gpioctl;
> +#define     GPIO3_PWM_ENABLE                                    27
> +#define     GPIO2_PWM_ENABLE                                    26
> +#define     GPIO1_PWM_ENABLE                                    25
> +#define     GPIO0_PWM_ENABLE                                    24
> +#define     GPIO3_INPUT_DEBOUNCE_ENABLE                         19
> +#define     GPIO2_INPUT_DEBOUNCE_ENABLE                         18
> +#define     GPIO1_INPUT_DEBOUNCE_ENABLE                         17
> +#define     GPIO0_INPUT_DEBOUNCE_ENABLE                         16
> +#define     GPIO3_LED_SELECT                                    12
> +#define     GPIO3_INTERRUPT_ENABLE                              11
> +#define     GPIO2_INTERRUPT_ENABLE                              10
> +#define     GPIO1_INTERRUPT_ENABLE                              9
> +#define     GPIO0_INTERRUPT_ENABLE                              8
> +#define     GPIO3_OUTPUT_ENABLE                                 7
> +#define     GPIO2_OUTPUT_ENABLE                                 6
> +#define     GPIO1_OUTPUT_ENABLE                                 5
> +#define     GPIO0_OUTPUT_ENABLE                                 4
> +#define     GPIO3_DATA                                          3
> +#define     GPIO2_DATA                                          2
> +#define     GPIO1_DATA                                          1
> +#define     GPIO0_DATA                                          0
> +    u32   gpiostat;
> +#define     GPIO3_INTERRUPT                                     3
> +#define     GPIO2_INTERRUPT                                     2
> +#define     GPIO1_INTERRUPT                                     1
> +#define     GPIO0_INTERRUPT                                     0
> +} __attribute__ ((packed));
> +
> +/* usb control, BAR0 + 0x0080 */
> +struct usb338x_usb_regs
> +{
> +    /* offset 0x0080 */
> +    u32   stdrsp;
> +#define     STALL_UNSUPPORTED_REQUESTS                          31
> +#define     SET_ISOCHRONOUS_DELAY                               24
> +#define     GET_STRING_DESCRIPTOR_3                             23
> +#define     SET_SEL                                             22
> +#define     GET_BOS_DESCRIPTOR                                  21
> +#define     SET_CLR_LTM_ENABLE                                  20
> +#define     SET_CLR_U2_ENABLE                                   19
> +#define     SET_CLR_U1_ENABLE                                   18
> +#define     SET_CLR_FUNCTION_SUSPEND                            17
> +#define     SET_TEST_MODE                                       16
> +#define     GET_OTHER_SPEED_CONFIGURATION                       15
> +#define     GET_DEVICE_QUALIFIER                                14
> +#define     SET_ADDRESS                                         13
> +#define     ENDPOINT_SET_CLEAR_HALT                             12
> +#define     DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP               11
> +#define     GET_STRING_DESCRIPTOR_2                             10
> +#define     GET_STRING_DESCRIPTOR_1                             9
> +#define     GET_STRING_DESCRIPTOR_0                             8
> +#define     GET_SET_INTERFACE                                   6
> +#define     GET_SET_CONFIGURATION                               5
> +#define     GET_CONFIGURATION_DESCRIPTOR                        4
> +#define     GET_DEVICE_DESCRIPTOR                               3
> +#define     GET_ENDPOINT_STATUS                                 2
> +#define     GET_INTERFACE_STATUS                                1
> +#define     GET_DEVICE_STATUS                                   0
> +    u32   prodvendid;
> +#define     PRODUCT_ID                                          16
> +#define     VENDOR_ID                                           0
> +    u32   relnum;
> +#define     DEVICE_RELEASE_NUMBER                               0
> +    u32   usbctl;
> +#define usbctl_def    (unsigned int) 0x0x00003841
> +#define     PRODUCT_ID_STRING_ENABLE                            13
> +#define     VENDOR_ID_STRING_ENABLE                             12
> +#define     USB_ROOT_PORT_WAKEUP_ENABLE                         11
> +#define     VBUS_PIN                                            10
> +#define     TIMED_DISCONNECT                                    9
> +#define     IMMEDIATELY_SUSPEND                                 7
> +#define     SELF_POWERED_USB_DEVICE                             6
> +#define     REMOTE_WAKEUP_SUPPORT                               5
> +#define     PME_POLARITY                                        4
> +#define     USB_DETECT_ENABLE                                   3
> +#define     PCIE_WAKEUP_ENABLE                                  2
> +#define     REMOTE_WAKEUP_ENABLE                                1
> +#define     SELF_POWERED_STATUS                                 0
> +    /* offset 0x0090 */
> +    u32   usbstat;
> +#define     HOST_MODE                                           12
> +#define     ENHANCED_MODE                                       11
> +#define     REMOTE_WAKEUP_STATUS                                10
> +#define     SUSPEND_STATUS                                      9
> +#define     SUPER_SPEED_MODE                                    8
> +#define     HIGH_SPEED_MODE                                     7
> +#define     FULL_SPEED_MODE                                     6
> +#define     GENERATE_RESUME                                     5
> +#define     GENERATE_DEVICE_REMOTE_WAKEUP                       4
> +    u32   xcvrdiag;
> +#define     FORCE_HIGH_SPEED_MODE                               31
> +#define     FORCE_FULL_SPEED_MODE                               30
> +#define     USB_TEST_MODE                                       24  /* 26:24 */
> +#define     LINE_STATE                                          16  /* 17:16 */
> +#define     TRANSCEIVER_OPERATION_MODE                          2   /* 3:2 */
> +#define     TRANSCEIVER_SELECT                                  1
> +#define     TERMINATION_SELECT                                  0
> +    u32   setupdw0;
> +    u32   setupdw1;
> +    /* offset 0x0090 */
> +    u32   _unused0;
> +    u32   ouraddr;
> +#define     FORCE_IMMEDIATE                                     7
> +#define     OUR_USB_ADDRESS                                     0   /* 6:0 */
> +    u32   ourconfig;
> +    u32       _unused1[2];
> +    /* offset 0x00B4 */
> +    u32     usbclass;
> +#define     DEVICE_PROTOCOL                     16  /* 23:16 */
> +#define     DEVICE_SUB_CLASS                     8  /* 15:8 */
> +#define     DEVICE_CLASS                         0  /* 7:0 */
> +    u32     ss_sel;
> +#define     U2_SYSTEM_EXIT_LATENCY                 8    /* 23:8 */
> +#define     U1_SYSTEM_EXIT_LATENCY                 0    /* 7:0 */
> +    u32     ss_del;
> +#define     U2_DEVICE_EXIT_LATENCY                 8    /* 23:8 */
> +#define     U1_DEVICE_EXIT_LATENCY                 0    /* 7:0 */
> +    u32     usb2lpm;
> +#define     USB_L1_LPM_HIRD                        2    /* 5:2 */
> +#define     USB_L1_LPM_REMOTE_WAKE                 1
> +#define     USB_L1_LPM_SUPPORT                     0
> +    u32     usb3belt;
> +#define     BELT_MULTIPLIER                       10    /* 11:10 */
> +#define     BEST_EFFORT_LATENCY_TOLERANCE          0    /* 9:0 */
> +    u32     usbctl2;
> +#define     LTM_ENABLE                          7
> +#define     U2_ENABLE                           6
> +#define     U1_ENABLE                           5
> +#define     FUNCTION_SUSPEND                    4
> +#define     USB3_CORE_ENABLE                    3
> +#define     USB2_CORE_ENABLE                    2
> +#define     SERIAL_NUMBER_STRING_ENABLE         0
> +    u32     in_timeout;
> +#define     GPEP3_TIMEOUT             19
> +#define     GPEP2_TIMEOUT             18
> +#define     GPEP1_TIMEOUT             17
> +#define     GPEP0_TIMEOUT             16
> +#define     GPEP3_TIMEOUT_VALUE             13  /* 15:13 */
> +#define     GPEP3_TIMEOUT_ENABLE      12
> +#define     GPEP2_TIMEOUT_VALUE             9   /* 11:9 */
> +#define     GPEP2_TIMEOUT_ENABLE      8
> +#define     GPEP1_TIMEOUT_VALUE             5   /* 7:5 */
> +#define     GPEP1_TIMEOUT_ENABLE      4
> +#define     GPEP0_TIMEOUT_VALUE             1   /* 3:1 */
> +#define     GPEP0_TIMEOUT_ENABLE      0
> +    u32     isodelay;
> +#define     ISOCHRONOUS_DELAY               0
> +} __attribute__ ((packed));
> +
> +/* pci control, BAR0 + 0x0100 */
> +struct usb338x_pci_regs
> +{
> +    /* offset 0x0100 */
> +    u32    pcimstctl;
> +#define     PCIE_DW_LENGTH             24   /* 30:24 */
> +#define     PCIE_PORT                  20
> +#define     MESSAGE_TYPE               19
> +#define     MESSAGE_ROUTING            16   /* 18:16 */
> +#define     MESSAGE_CODE                8   /* 15:8 */
> +#define     PCIE_MASTER_READ_WRITE      7
> +#define     PCIE_MASTER_START           6
> +#define     PCIE_MASTER_COMMAND_SELECT  4   /* 5:4 */
> +#define     PCIE_FIRST_BYTE_ENABLES     0   /* 3:0 */
> +    u32    pcimstaddr;
> +    u32    pcimstdata;
> +    u32    pcimststat;
> +#define     ROOT_COMPLEX_MODE                   0
> +} __attribute__ ((packed));
> +
> +/* dma control, BAR0 + 0x0180 ... array of four structs like this,
> + * for channels 0..3.  see also struct usb338x_dma:  descriptor
> + * that can be loaded into some of these registers.
> + */
> +struct usb338x_dma_regs
> +{
> +    /* [11.7] */
> +    /* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */
> +    u32   dmactl;
> +#define     DMA_ABORT_DONE_INTERRUPT_ENABLE                     27
> +#define     DMA_PAUSE_DONE_INTERRUPT_ENABLE                     26
> +#define     DMA_DESCRIPTOR_DONE_INTERRUPT_ENABLE                25
> +#define     PAUSE_MODE                                          23
> +#define     PREFETCH_DISABLE                                    22
> +#define     DMA_CLEAR_COUNT_ENABLE                              21
> +#define     DESCRIPTOR_POLLING_RATE                             19  /* 20:19 */
> +#define         POLL_CONTINUOUS                                     0
> +#define         POLL_1_USEC                                         1
> +#define         POLL_100_USEC                                       2
> +#define         POLL_1_MSEC                                         3
> +#define     DMA_VALID_BIT_POLLING_ENABLE                        18
> +#define     DMA_VALID_BIT_ENABLE                                17
> +#define     DMA_DESCRIPTOR_MODE                                 16
> +#define     DMA_REQUEST_OUTSTANDING                             5   /* 7:5 */
> +#define     DMA_OUT_AUTO_START_ENABLE                           4
> +#define     DMA_FIFO_VALIDATE                                   2
> +#define     DMA_ENABLE                                          1
> +#define     DMA_ADDRESS_CONSTANT                                0
> +    u32   dmastat;
> +#define     DMA_COMPLETION_SEQUENCE_ERROR_STATUS                31
> +#define     DMA_ABORT_DONE_INTERRUPT                            27
> +#define     DMA_PAUSE_DONE_INTERRUPT                            26
> +#define     DMA_LAST_DESCRIPTOR_DONE_INTERRUPT                  25
> +#define     DMA_TRANSACTION_DONE_INTERRUPT                      24
> +#define     DMA_ABORT                                           1
> +#define     DMA_START                                           0
> +    u32   _unused0[2];
> +    /* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */
> +    u32   dmacount;
> +#define     VALID_BIT                                           31
> +#define     DMA_DIRECTION                                       30
> +#define     DMA_DONE_INTERRUPT_ENABLE                           29
> +#define     LAST_DESCRIPTOR                                     28
> +#define     DMA_DESCRIPTOR_FIFO_VALIDATE                        27
> +#define     DMA_OUT_CONTINUE                                    24
> +#define     DMA_TRANSFER_MAX_LENGTH                             ((1UL<<24)-1)
> +#define     DMA_TRANSFER_LENGTH                                 0   /* 23:0 */
> +    /* offset 0x194, 0x1b4, 0x1d4, 0x1f4 */
> +    u32   dmaaddr;
> +    /* offset 0x198, 0x1b8, 0x1d8, 0x1f8 */
> +    u32   dmadesc;
> +#define     DMA_DESC_ONCHIP                                     0
> +    u32   _unused1;
> +} __attribute__ ((packed));
> +
> +#define INTERNAL_DESCRIPTOR_OFFSET                              0x4000
> +
> +/* dma control Prefetch, BAR0 + 0x0680 */
> +struct usb338x_dmap_regs
> +{
> +    u32     dmacountp;
> +    u32     dmaaddrp;
> +    u32     dmadescp;
> +    u32     _unused1;
> +} __attribute__ ((packed));
> +
> +/* dedicated endpoint registers, BAR0 + 0x0200 */
> +
> +struct usb338x_dep_regs
> +{
> +    /* [11.8] */
> +    /* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */
> +    u32   dep_cfg;
> +    /* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
> +    u32   dep_rsp;
> +    u32   _unused[2];
> +} __attribute__ ((packed));
> +
> +/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
> + * like this, for ep0 then the configurable endpoints 1..8
> + * ep0 reserved for control
> + */
> +struct usb338x_ep_cfg
> +{
> +    /* offset 0x300, 0x320, 0x340, 0x360, 0x380 */
> +    u32   ep_cfg;
> +#define     USAGE_TYPE                      30  /* Legacy/Enhanced: 31:30 */
> +#define     SYNC_TYPE                       28  /* Legacy/Enhanced: 29:28 */
> +#define     MAX_BURST_SIZE                  24  /* Legacy/Enhanced: 27:24 */
> +#define     SERVICE_INTERVAL                19  /* Legacy/Enhanced: 23:19 */
> +#define     EP_FIFO_BYTE_COUNT              16  /* 18:16 */
> +#define     IN_EP_FORMAT                    15  /* Legacy/Enhanced */
> +#define     IN_ENDPOINT_ENABLE              14  /* Enhanced */
> +#define     IN_ENDPOINT_TYPE                12  /* Enhanced: 13:12 */
> +#define     BYTE_PACKING_ENABLE             11
> +#define     ENDPOINT_ENABLE                 10  /* Legacy/ep0 */
> +#define     OUT_ENDPOINT_ENABLE             10  /* Enhanced */
> +#define     ENDPOINT_TYPE                    8  /* Legacy/ep0: 9:8 */
> +#define     OUT_ENDPOINT_TYPE                8  /* Enhanced: 9:8 */
> +#define     ENDPOINT_DIRECTION               7  /* Legacy/ep0 */
> +#define     ENDPOINT_NUMBER                  0  /* 3:0 */
> +    u32   _unused0[7];
> +};
> +
> +struct usb338x_ep_regs
> +{
> +    /* [11.9] */
> +    /* ep0, ep1-out/in, ep2-out/in, ep3-out/in, ep4-out/in */
> +    /* offset 0x304, 0x324/0x3e4, 0x344/0x404, 0x364/0x424, 0x384/0x444 */
> +    u32   ep_rsp;
> +#define     SET_NAK_OUT_PACKETS                                 15
> +#define     SET_EP_HIDE_STATUS_PHASE                            14
> +#define     SET_EP_FORCE_CRC_ERROR                              13
> +#define     SET_INTERRUPT_MODE                                  12
> +#define     SET_CONTROL_STATUS_PHASE_HANDSHAKE                  11
> +#define     SET_NAK_OUT_PACKETS_MODE                            10
> +#define     SET_ENDPOINT_TOGGLE                                 9
> +#define     SET_ENDPOINT_HALT                                   8
> +#define     CLEAR_NAK_OUT_PACKETS                               7
> +#define     CLEAR_EP_HIDE_STATUS_PHASE                          6
> +#define     CLEAR_EP_FORCE_CRC_ERROR                            5
> +#define     CLEAR_INTERRUPT_MODE                                4
> +#define     CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE                3
> +#define     CLEAR_NAK_OUT_PACKETS_MODE                          2
> +#define     CLEAR_ENDPOINT_TOGGLE                               1
> +#define     CLEAR_ENDPOINT_HALT                                 0
> +    u32   ep_irqenb;
> +#define     SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE              6
> +#define     SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE           5
> +#define     DATA_PACKET_RECEIVED_INTERRUPT_ENABLE               3
> +#define     DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE            2
> +#define     DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE                1
> +#define     DATA_IN_TOKEN_INTERRUPT_ENABLE                      0
> +    u32   ep_stat;
> +#define     FIFO_VALID_COUNT                                    24
> +#define     HIGH_BANDWIDTH_OUT_TRANSACTION_PID                  22
> +#define     TIMEOUT                                             21
> +#define     USB_STALL_SENT                                      20
> +#define     USB_IN_NAK_SENT                                     19
> +#define     USB_IN_ACK_RCVD                                     18
> +#define     USB_OUT_NAK_SENT                                    17
> +#define     USB_OUT_ACK_SENT                                    16
> +#define     ZLP_INTERRUPT                                       13
> +#define     FIFO_FULL                                           11
> +#define     FIFO_EMPTY                                          10
> +#define     FIFO_FLUSH                                          9
> +#define     FIFO_VALIDATE                                       8
> +#define     SHORT_PACKET_TRANSFERRED_STATUS                     7
> +#define     SHORT_OUT_PACKET_DONE_INTERRUPT                     6
> +#define     SHORT_OUT_PACKET_RECEIVED_INTERRUPT                 5
> +#define     NAK_PACKETS                                         4
> +#define     DATA_PACKET_RECEIVED_INTERRUPT                      3
> +#define     DATA_PACKET_TRANSMITTED_INTERRUPT                   2
> +#define     DATA_OUT_PING_TOKEN_INTERRUPT                       1
> +#define     DATA_IN_TOKEN_INTERRUPT                             0
> +    /* offset 0x310, 0x330/0x3f0, 0x350/0x410, 0x370/0x430, 0x390/0x450 */
> +    u32   ep_avail;
> +    u32   ep_data;
> +    u32   ep_data1;
> +    u32   ep_val;
> +    u32   _unused0;
> +} __attribute__ ((packed));
> +
> +struct usb338x_fifo_regs
> +{
> +    /* offset 0x0500, 0x0520, 0x0540, 0x0560, 0x0580 */
> +    u32     ep_fifo_size_base;
> +#define     IN_FIFO_BASE_ADDRESS                                22  /* 30:22 */
> +#define     IN_FIFO_SIZE                                        16  /* 18:16 */
> +#define     OUT_FIFO_BASE_ADDRESS                               6   /* 14:6 */
> +#define     OUT_FIFO_SIZE                                       0   /* 2:0 */
> +    u32     ep_fifo_out_wrptr;
> +    u32     ep_fifo_out_rdptr;
> +    u32     ep_fifo_in_wrptr;
> +    u32     ep_fifo_in_rdptr;
> +    u32     unused[3];
> +} __attribute__ ((packed));
> +
> +// Link layer -----------------------------------------------------------------
> +struct usb338x_ll_regs
> +{
> +    /* offset 0x700 */
> +    u32   ll_ltssm_ctrl1;
> +    u32   ll_ltssm_ctrl2;
> +    u32   ll_ltssm_ctrl3;
> +    u32   unused[2];
> +    /* offset 0x714 */
> +    u32   ll_general_ctrl0;
> +    u32   ll_general_ctrl1;
> +#define     PM_U3_AUTO_EXIT                                     29
> +#define     PM_U2_AUTO_EXIT                                     28
> +#define     PM_U1_AUTO_EXIT                                     27
> +#define     PM_FORCE_U2_ENTRY                                   26
> +#define     PM_FORCE_U1_ENTRY                                   25
> +#define     PM_LGO_COLLISION_SEND_LAU                           24
> +#define     PM_DIR_LINK_REJECT                                  23
> +#define     PM_FORCE_LINK_ACCEPT                                22
> +#define     PM_DIR_ENTRY_U3                                     20
> +#define     PM_DIR_ENTRY_U2                                     19
> +#define     PM_DIR_ENTRY_U1                                     18
> +#define     PM_U2_ENABLE                                        17
> +#define     PM_U1_ENABLE                                        16
> +#define     SKP_THRESHOLD_ADJUST_FMW                            8   /* 13:8 */
> +#define     RESEND_DPP_ON_LRTY_FMW                              7
> +#define     DL_BIT_VALUE_FMW                                    6
> +#define     FORCE_DL_BIT                                        5
> +    u32   ll_general_ctrl2;
> +#define     SELECT_INVERT_LANE_POLARITY                         7
> +#define     FORCE_INVERT_LANE_POLARITY                          6
> +    u32   ll_general_ctrl3;
> +    u32   ll_general_ctrl4;
> +    u32   ll_error_gen;
> +} __attribute__ ((packed));
> +
> +struct usb338x_ll_lfps_regs
> +{
> +    /* offset 0x748 */
> +    u32   ll_lfps_5;
> +#define     TIMER_LFPS_6US                                      16  /* 19:16 */
> +    u32   ll_lfps_6; // 0x74c
> +#define     TIMER_LFPS_80US                                     0   /* 15:0 */
> +} __attribute__ ((packed));
> +
> +struct usb338x_ll_tsn_regs
> +{
> +    /* offset 0x77C */
> +    u32   ll_tsn_counters_2;
> +#define     HOT_TX_NORESET_TS2                                  24  /* 28:24 */
> +    u32   ll_tsn_counters_3;
> +#define     HOT_RX_RESET_TS2                                    0   /* 4:0 */
> +} __attribute__ ((packed));
> +
> +struct usb338x_ll_chi_regs
> +{
> +    /* offset 0x79C */
> +    u32   ll_tsn_chicken_bit;
> +#define     RECOVERY_IDLE_TO_RECOVER_FMW                        3   /* 28:24 */
> +} __attribute__ ((packed));
> +
> +// protocol layer -------------------------------------------------------------
> +
> +struct usb338x_pl_regs
> +{
> +    /* offset 0x800 */
> +    u32   pl_reg_1;
> +    u32   pl_reg_2;
> +    u32   pl_reg_3;
> +    u32   pl_reg_4;
> +    u32   pl_ep_ctrl;     //0x810
> +    // Protocol Layer Endpoint Control
> +#define     PL_EP_CTRL                                  0x810
> +#define     ENDPOINT_SELECT                             0      // [4:0]
> +#define     EP_INITIALIZED                              16
> +#define     SEQUENCE_NUMBER_RESET                       17
> +#define     CLEAR_ACK_ERROR_CODE                        20
> +    u32   pl_reg_6;
> +    u32   pl_reg_7;
> +    u32   pl_reg_8;
> +    u32   pl_ep_status_1; //0x820
> +    // Protocol Layer Endpoint Status 1
> +#define     PL_EP_STATUS_1                              0x820
> +#define     STATE                                       16     // [23:16] Tip: Subdivided. See spec
> +#define     ACK_GOOD_NORMAL                             0x11   // for bits [20:16]
> +#define     ACK_GOOD_MORE_ACKS_TO_COME                  0x16   // for bits [20:16]
> +    u32   pl_ep_status_2;
> +    u32   pl_ep_status_3; //0x828
> +    // Protocol Layer Endpoint Status 3
> +#define     PL_EP_STATUS_3                              0x828
> +#define     SEQUENCE_NUMBER                             0      // [7:0]
> +    u32   pl_ep_status_4;
> +    // Protocol Layer Endpoint Status 4
> +#define     PL_EP_STATUS_4                              0x82c
> +    u32   pl_ep_cfg_4;
> +    // Protocol Layer Endpoint Configuration 4
> +#define     PL_EP_CFG_4                                 0x830
> +#define     NON_CTRL_IN_TOLERATE_BAD_DIR                6
> +} __attribute__ ((packed));
> +
> +struct usb338x_factory_regs
> +{
> +    /* 0xB80 */
> +    u32   factory_test_only;
> +} __attribute__ ((packed));
> +
> +struct usb338x_phy_regs
> +{
> +    /* 0x0xBE0 */
> +    u32   phy_threshold;
> +} __attribute__ ((packed));
> +
> +/*-------------------------------------------------------------------------*/
> +
> +#define N_EPS_LEGCY    4 /* 4 endpoints in legacy mode */
> +#define N_EPS_ENHANCE  8 /* 8 endpoints in enhanced mode */
> +#define N_DMA_CHANNEL  4 /* Number of DMA channel */
> +
> +#define REG_DIAG      0x0
> +#define RETRY_COUNTER                                       16
> +#define FORCE_PCI_SERR                                      11
> +#define FORCE_PCI_INTERRUPT                                 10
> +#define FORCE_USB_INTERRUPT                                 9
> +#define FORCE_CPU_INTERRUPT                                 8
> +#define ILLEGAL_BYTE_ENABLES                                5
> +#define FAST_TIMES                                          4
> +#define FORCE_RECEIVE_ERROR                                 2
> +#define FORCE_TRANSMIT_CRC_ERROR                            0
> +#define REG_FRAME     0x02    /* from last sof */
> +#define REG_CHIPREV   0x03    /* in bcd */
> +#define REG_HS_NAK_RATE   0x0a  /* NAK per N uframes */
> +
> +#define CHIPREV_1   0x0100
> +#define CHIPREV_1A  0x0110
> +
> +/* ep 1-8 highspeed and fullspeed maxpacket, addresses
> + * computed from ep->num
> + */
> +#define REG_EP_MAXPKT(dev,num) (((num) + 1) * 0x10 + \
> +                                (((dev)->gadget.speed == USB_SPEED_HIGH) ? 0 : 1))
> +
> +/* DEFECT 7374 */
> +#define DEFECT_7374_NUMBEROF_MAX_WAIT_LOOPS         200
> +#define DEFECT_7374_PROCESSOR_WAIT_TIME             10
> +
> +/* ep0 max packet size */
> +#define EP0_SS_MAX_PACKET_SIZE  0x200   /* 512 */
> +#define EP0_HS_MAX_PACKET_SIZE  0x40    /* 64 */
> +/*-------------------------------------------------------------------------*/
> +
> +/* [8.3] for scatter/gather i/o
> + * use struct usb338x_dma_regs bitfields
> + */
> +struct usb338x_dma
> +{
> +    __le32      dmacount;
> +    __le32      dmaaddr;        /* the buffer */
> +    __le32      dmadesc;        /* next dma descriptor */
> +    __le32      _reserved;
> +} __attribute__ ((aligned (16)));
> +
> +/*-------------------------------------------------------------------------*/
> +
> +
> +/* DRIVER DATA STRUCTURES and UTILITIES */
> +
> +struct usb338x_ep
> +{
> +    struct usb_ep               ep;
> +    struct usb338x_ep_cfg       __iomem *cfg;
> +    struct usb338x_ep_regs      __iomem *regs;
> +    struct usb338x_dma_regs     __iomem *dma;
> +    struct usb338x_dma          *dummy;
> +    struct usb338x_fifo_regs    __iomem *fiforegs;
> +    dma_addr_t                  td_dma;     /* of dummy */
> +    struct usb338x              *dev;
> +    unsigned long               irqs;
> +    unsigned                    is_halt : 1,
> +                                dma_started : 1;
> +
> +    /* analogous to a host-side qh */
> +    struct list_head            queue;
> +    const struct usb_endpoint_descriptor    *desc;
> +    unsigned                num : 8,
> +                            fifo_size : 12,
> +                            in_fifo_validate : 1,
> +                            out_overflow : 1,
> +                            stopped : 1,
> +                            wedged : 1,
> +                            is_in : 1,
> +                            is_iso : 1,
> +                            responded : 1;
> +};
> +
> +
> +struct usb338x_request
> +{
> +    struct usb_request  req;
> +    struct usb338x_dma  *td;
> +    dma_addr_t          td_dma;
> +    struct list_head    queue;
> +    unsigned            mapped : 1,
> +                        valid : 1;
> +};
> +
> +
> +struct usb338x
> +{
> +    /* each pci device provides one gadget, several endpoints */
> +    struct usb_gadget   gadget;
> +    spinlock_t          lock;
> +    struct usb338x_ep   ep [9];
> +    struct usb_gadget_driver  *driver;
> +    unsigned            enabled : 1,
> +                        protocol_stall : 1,
> +                        softconnect : 1,
> +                        got_irq : 1,
> +                        region : 1,
> +                        u1_enable: 1,
> +                        u2_enable: 1,
> +                        ltm_enable: 1,
> +                        wakeup_enable: 1,
> +                        selfpowered: 1,
> +                        addressed_state: 1;
> +
> +    u16                 chiprev;
> +
> +    /* pci state used to access those endpoints */
> +    struct pci_dev              *pdev;
> +    struct usb338x_regs         __iomem *regs;
> +    struct usb338x_usb_regs     __iomem *usb;
> +    struct usb338x_pci_regs     __iomem *pci;
> +    struct usb338x_dma_regs     __iomem *dma;
> +    struct usb338x_dep_regs     __iomem *dep;
> +    struct usb338x_ep_cfg       __iomem *epcfg;
> +    struct usb338x_ep_regs      __iomem *epregs;
> +    struct usb338x_fifo_regs    __iomem *fiforegs;
> +    struct usb338x_ll_regs      __iomem *llregs;
> +    struct usb338x_ll_lfps_regs __iomem *ll_lfps_regs;
> +    struct usb338x_ll_tsn_regs  __iomem *ll_tsn_regs;
> +    struct usb338x_ll_chi_regs  __iomem *ll_chicken_reg;
> +    struct usb338x_pl_regs      __iomem *plregs;
> +    struct usb338x_factory_regs __iomem *factory_regs;
> +    struct usb338x_phy_regs     __iomem *phy_regs;
> +    struct pci_pool             *requests;
> +    // statistics...
> +};
> +
> +/*-------------------------------------------------------------------------*/
> +// DEFECT7374_FSM
> +/* FSM value for Defect 7374 (U1U2 Test) is managed in chip's SCRATCH register:
> + * Reg/Bit/Val      Reg /// Bit /// Val ////
> + */
> +#define DEFECT7374_FSM_FIELD    28  //31:28
> +
> +typedef enum _DEFECT7374_FSM
> +{
> +    /* A finite state machine for Defect 7374 workaround is managed
> +     * in the chip's SCRATCH register:
> +     *  - The nature of the Defect 7374 is that it must be executed only
> +     *    once, after the chip powers up.
> +     *  - Using a chip register allows the FSM state to persist even when
> +     *    the driver unloads and reloads.
> +     *  - Using a chip register allows the FSM state to automatically
> +     *    reset when the system recovers from hibernation.
> +     */
> +
> +    /* The FSM's reset state is the chip register's power-on value:
> +     *  - The FSM state is managed in SCRATCH[31:28]
> +     *  - The chip's SCRATCH register power-on value is 0xFEEDFACE
> +     */
> +    DEFECT7374_FSM_RESET = (0xFEEDFACE & (0xf << 28)),
> +
> +    // Undefined state applies to errors, debug and development.
> +    DEFECT7374_FSM_UNDEFINED = (0 << DEFECT7374_FSM_FIELD),
> +
> +    /* Waiting for Control Read:
> +     *  - A transition to this state indicates a fresh USB connection,
> +     *    before the first Setup Packet. The connection speed is not
> +     *    known. Firmware is waiting for the first Control Read.
> +     *  - Starting state: This state can be thought of as the FSM's typical
> +     *    starting state.
> +     *  - Tip: Upon the first SS Control Read the FSM never
> +     *    returns to this state.
> +     */
> +    DEFECT7374_FSM_WAITING_FOR_CONTROL_READ = (1 << DEFECT7374_FSM_FIELD),
> +
> +    /* Non-SS Control Read:
> +     *  - A transition to this state indicates detection of the first HS
> +     *    or FS Control Read.
> +     *  - Tip: Upon the first SS Control Read the FSM never
> +     *    returns to this state.
> +     */
> +    DEFECT7374_FSM_NON_SS_CONTROL_READ = (2 << DEFECT7374_FSM_FIELD),
> +
> +    /* SS Control Read:
> +     *  - A transition to this state indicates detection of the
> +     *    first SS Control Read.
> +     *  - This state indicates workaround completion. Workarounds no longer
> +     *    need to be applied (as long as the chip remains powered up).
> +     *  - Tip: Once in this state the FSM state does not change (until
> +     *    the chip's power is lost and restored).
> +     *  - This can be thought of as the final state of the FSM;
> +     *    the FSM 'locks-up' in this state until the chip loses power.
> +     */
> +    DEFECT7374_FSM_SS_CONTROL_READ = (3 << DEFECT7374_FSM_FIELD),
> +} DEFECT7374_FSM, * PDEFECT7374_FSM;
> +
> +/*-------------------------------------------------------------------------*/
> +
> +#define xprintk(dev,level,fmt,args...) \
> +    printk(level "     DEBUG: %s %s: " fmt , driver_name , \
> +           pci_name(dev->pdev) , ## args)
> +
> +#ifdef DEBUG
> +#undef DEBUG
> +#define DEBUG(dev,fmt,args...) \
> +    xprintk(dev , KERN_INFO , fmt , ## args)
> +#else
> +#define DEBUG(dev,fmt,args...) \
> +    do { } while (0)
> +#endif /* DEBUG */
> +
> +#ifdef VERBOSE
> +#define VDEBUG DEBUG
> +#else
> +#define VDEBUG(dev,fmt,args...) \
> +    do { } while (0)
> +#endif  /* VERBOSE */
> +
> +#define ERROR(dev,fmt,args...) \
> +    xprintk(dev , KERN_ERR , fmt , ## args)
> +#define WARNING(dev,fmt,args...) \
> +    xprintk(dev , KERN_WARNING , fmt , ## args)
> +#define INFO(dev,fmt,args...) \
> +    xprintk(dev , KERN_INFO , fmt , ## args)
> +
> +#endif
> +/*-------------------------------------------------------------------------*/
> \ No newline at end of file
> --
> 2.0.0.rc0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Ricardo Ribalda
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux