Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / usb / gadget / net2280.c
index 880b1f7..0924323 100644 (file)
@@ -1,19 +1,16 @@
 /*
- * Driver for the NetChip 2280 USB device controller.
- * Specs and errata are available from <http://www.netchip.com>.
+ * Driver for the PLX NET2280 USB device controller.
+ * Specs and errata are available from <http://www.plxtech.com>.
  *
- * NetChip Technology Inc. supported the development of this driver.
+ * PLX Technology Inc. (formerly NetChip Technology) supported the 
+ * development of this driver.
  *
  *
  * CODE STATUS HIGHLIGHTS
  *
- * Used with a gadget driver like "zero.c" this enumerates fine to Windows
- * or Linux hosts; handles disconnect, reconnect, and reset, for full or
- * high speed operation; and passes USB-IF "chapter 9" tests.
- *
- * Handles standard stress loads from the Linux "usbtest" driver, with
- * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}.  Testing
- * with "ttcp" (and the "ether.c" driver) behaves nicely too.
+ * This driver should work well with most "gadget" drivers, including
+ * the File Storage, Serial, and Ethernet/RNDIS gadget drivers
+ * as well as Gadget Zero and Gadgetfs.
  *
  * DMA is enabled by default.  Drivers using transfer queues might use
  * DMA chaining to remove IRQ latencies between transfers.  (Except when
@@ -27,7 +24,9 @@
 
 /*
  * Copyright (C) 2003 David Brownell
- * Copyright (C) 2003 NetChip Technologies
+ * Copyright (C) 2003-2005 PLX Technology, Inc.
+ *
+ * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,9 +46,9 @@
 #undef DEBUG           /* messages on error and most fault paths */
 #undef VERBOSE         /* extra debug messages (success too) */
 
-#include <linux/config.h>
 #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 <asm/unaligned.h>
 
 
-#define        DRIVER_DESC             "NetChip 2280 USB Peripheral Controller"
-#define        DRIVER_VERSION          "2004 Jan 14"
+#define        DRIVER_DESC             "PLX NET228x USB Peripheral Controller"
+#define        DRIVER_VERSION          "2005 Sept 27"
 
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 #define        EP_DONTUSE              13      /* nonzero */
 
 #define USE_RDK_LEDS           /* GPIO pins control three LEDs */
-#define USE_SYSFS_DEBUG_FILES
 
 
 static const char driver_name [] = "net2280";
@@ -118,10 +116,20 @@ static ushort fifo_mode = 0;
 /* "modprobe net2280 fifo_mode=1" etc */
 module_param (fifo_mode, ushort, 0644);
 
+/* enable_suspend -- When enabled, the driver will respond to
+ * USB suspend requests by powering down the NET2280.  Otherwise,
+ * USB suspend requests will be ignored.  This is acceptible for
+ * self-powered devices
+ */
+static int enable_suspend = 0;
+
+/* "modprobe net2280 enable_suspend=1" etc */
+module_param (enable_suspend, bool, S_IRUGO);
+
 
 #define        DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 
-#if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG)
+#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG)
 static char *type_string (u8 bmAttributes)
 {
        switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
@@ -216,6 +224,11 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        ep->is_in = (tmp & USB_DIR_IN) != 0;
        if (!ep->is_in)
                writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+       else if (dev->pdev->device != 0x2280) {
+               /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
+               writel ((1 << CLEAR_NAK_OUT_PACKETS)
+                       | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
+       }
 
        writel (tmp, &ep->regs->ep_cfg);
 
@@ -225,8 +238,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                writel (tmp, &dev->regs->pciirqenb0);
 
                tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
-                       | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
-                       | readl (&ep->regs->ep_irqenb);
+                       | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE);
+               if (dev->pdev->device == 0x2280)
+                       tmp |= readl (&ep->regs->ep_irqenb);
                writel (tmp, &ep->regs->ep_irqenb);
        } else {                                /* dma, per-request */
                tmp = (1 << (8 + ep->num));     /* completion */
@@ -257,7 +271,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        return 0;
 }
 
-static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
 {
        u32     result;
 
@@ -276,7 +290,7 @@ static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
 
 static struct usb_ep_ops net2280_ep_ops;
 
-static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep)
+static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
 {
        u32             tmp;
 
@@ -307,24 +321,38 @@ static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep)
        /* init to our chosen defaults, notably so that we NAK OUT
         * packets until the driver queues a read (+note erratum 0112)
         */
-       writel (  (1 << SET_NAK_OUT_PACKETS_MODE)
+       if (!ep->is_in || ep->dev->pdev->device == 0x2280) {
+               tmp = (1 << SET_NAK_OUT_PACKETS_MODE)
                | (1 << SET_NAK_OUT_PACKETS)
                | (1 << CLEAR_EP_HIDE_STATUS_PHASE)
-               | (1 << CLEAR_INTERRUPT_MODE)
-               | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
-               | (1 << CLEAR_ENDPOINT_TOGGLE)
-               | (1 << CLEAR_ENDPOINT_HALT)
-               , &ep->regs->ep_rsp);
+               | (1 << CLEAR_INTERRUPT_MODE);
+       } else {
+               /* added for 2282 */
+               tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+               | (1 << CLEAR_NAK_OUT_PACKETS)
+               | (1 << CLEAR_EP_HIDE_STATUS_PHASE)
+               | (1 << CLEAR_INTERRUPT_MODE);
+       }
+
+       if (ep->num != 0) {
+               tmp |= (1 << CLEAR_ENDPOINT_TOGGLE)
+                       | (1 << CLEAR_ENDPOINT_HALT);
+       }
+       writel (tmp, &ep->regs->ep_rsp);
 
        /* scrub most status bits, and flush any fifo state */
-       writel (  (1 << TIMEOUT)
+       if (ep->dev->pdev->device == 0x2280)
+               tmp = (1 << FIFO_OVERFLOW)
+                       | (1 << FIFO_UNDERFLOW);
+       else
+               tmp = 0;
+
+       writel (tmp | (1 << TIMEOUT)
                | (1 << USB_STALL_SENT)
                | (1 << USB_IN_NAK_SENT)
                | (1 << USB_IN_ACK_RCVD)
                | (1 << USB_OUT_PING_NAK_SENT)
                | (1 << USB_OUT_ACK_SENT)
-               | (1 << FIFO_OVERFLOW)
-               | (1 << FIFO_UNDERFLOW)
                | (1 << FIFO_FLUSH)
                | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
                | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
@@ -368,7 +396,7 @@ static int net2280_disable (struct usb_ep *_ep)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_request *
-net2280_alloc_request (struct usb_ep *_ep, int gfp_flags)
+net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
 {
        struct net2280_ep       *ep;
        struct net2280_request  *req;
@@ -377,11 +405,10 @@ net2280_alloc_request (struct usb_ep *_ep, int gfp_flags)
                return NULL;
        ep = container_of (_ep, struct net2280_ep, ep);
 
-       req = kmalloc (sizeof *req, gfp_flags);
+       req = kzalloc(sizeof(*req), gfp_flags);
        if (!req)
                return NULL;
 
-       memset (req, 0, sizeof *req);
        req->req.dma = DMA_ADDR_INVALID;
        INIT_LIST_HEAD (&req->queue);
 
@@ -440,7 +467,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
 #elif  defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
 #define USE_KMALLOC
 
-#elif  defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif  defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
 #define USE_KMALLOC
 
 /* FIXME there are other cases, including an x86-64 one ...  */
@@ -455,7 +482,7 @@ net2280_alloc_buffer (
        struct usb_ep           *_ep,
        unsigned                bytes,
        dma_addr_t              *dma,
-       int                     gfp_flags
+       gfp_t                   gfp_flags
 )
 {
        void                    *retval;
@@ -517,7 +544,7 @@ net2280_free_buffer (
 static void
 write_fifo (struct net2280_ep *ep, struct usb_request *req)
 {
-       struct net2280_ep_regs  *regs = ep->regs;
+       struct net2280_ep_regs  __iomem *regs = ep->regs;
        u8                      *buf;
        u32                     tmp;
        unsigned                count, total;
@@ -577,7 +604,8 @@ write_fifo (struct net2280_ep *ep, struct usb_request *req)
  */
 static void out_flush (struct net2280_ep *ep)
 {
-       u32     *statp, tmp;
+       u32     __iomem *statp;
+       u32     tmp;
 
        ASSERT_OUT_NAKING (ep);
 
@@ -610,7 +638,7 @@ static void out_flush (struct net2280_ep *ep)
 static int
 read_fifo (struct net2280_ep *ep, struct net2280_request *req)
 {
-       struct net2280_ep_regs  *regs = ep->regs;
+       struct net2280_ep_regs  __iomem *regs = ep->regs;
        u8                      *buf = req->req.buf + req->req.actual;
        unsigned                count, tmp, is_short;
        unsigned                cleanup = 0, prevent = 0;
@@ -678,7 +706,7 @@ read_fifo (struct net2280_ep *ep, struct net2280_request *req)
        }
        if (count) {
                tmp = readl (&regs->ep_data);
-               cpu_to_le32s (&tmp);
+               /* LE conversion is implicit here: */
                do {
                        *buf++ = (u8) tmp;
                        tmp >>= 8;
@@ -709,7 +737,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
         */
        if (ep->is_in)
                dmacount |= (1 << DMA_DIRECTION);
-       else if ((dmacount % ep->ep.maxpacket) != 0)
+       if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
                dmacount |= (1 << END_OF_CHAIN);
 
        req->valid = valid;
@@ -719,7 +747,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
                dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
 
        /* td->dmadesc = previously set by caller */
-       td->dmaaddr = cpu_to_le32p (&req->req.dma);
+       td->dmaaddr = cpu_to_le32 (req->req.dma);
 
        /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
        wmb ();
@@ -737,12 +765,12 @@ static const u32 dmactl_default =
                /* erratum 0116 workaround part 2 (no AUTOSTART) */
                | (1 << DMA_ENABLE);
 
-static inline void spin_stop_dma (struct net2280_dma_regs *dma)
+static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma)
 {
        handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50);
 }
 
-static inline void stop_dma (struct net2280_dma_regs *dma)
+static inline void stop_dma (struct net2280_dma_regs __iomem *dma)
 {
        writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl);
        spin_stop_dma (dma);
@@ -750,10 +778,13 @@ static inline void stop_dma (struct net2280_dma_regs *dma)
 
 static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma)
 {
-       struct net2280_dma_regs *dma = ep->dma;
+       struct net2280_dma_regs __iomem *dma = ep->dma;
+       unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION);
 
-       writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION),
-                       &dma->dmacount);
+       if (ep->dev->pdev->device != 0x2280)
+               tmp |= (1 << END_OF_CHAIN);
+
+       writel (tmp, &dma->dmacount);
        writel (readl (&dma->dmastat), &dma->dmastat);
 
        writel (td_dma, &dma->dmadesc);
@@ -771,7 +802,7 @@ static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma)
 static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
 {
        u32                     tmp;
-       struct net2280_dma_regs *dma = ep->dma;
+       struct net2280_dma_regs __iomem *dma = ep->dma;
 
        /* FIXME can't use DMA for ZLPs */
 
@@ -888,7 +919,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status)
 /*-------------------------------------------------------------------------*/
 
 static int
-net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 {
        struct net2280_request  *req;
        struct net2280_ep       *ep;
@@ -1104,7 +1135,7 @@ static void restart_dma (struct net2280_ep *ep)
                if (ep->in_fifo_validate)
                        dmactl |= (1 << DMA_FIFO_VALIDATE);
                list_for_each_entry (entry, &ep->queue, queue) {
-                       u32             dmacount;
+                       __le32          dmacount;
 
                        if (entry == req)
                                continue;
@@ -1229,7 +1260,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
                                &ep->dma->dmadesc);
                        if (req->td->dmacount & dma_done_ie)
                                writel (readl (&ep->dma->dmacount)
-                                               | dma_done_ie,
+                                               | le32_to_cpu(dma_done_ie),
                                        &ep->dma->dmacount);
                } else {
                        struct net2280_request  *prev;
@@ -1261,7 +1292,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
        }
 
        spin_unlock_irqrestore (&ep->dev->lock, flags);
-       return req ? 0 : -EOPNOTSUPP;
+       return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1419,19 +1450,48 @@ static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value)
        return 0;
 }
 
+static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
+{
+       struct net2280  *dev;
+       u32             tmp;
+       unsigned long   flags;
+
+       if (!_gadget)
+               return -ENODEV;
+       dev = container_of (_gadget, struct net2280, 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 const struct usb_gadget_ops net2280_ops = {
        .get_frame      = net2280_get_frame,
        .wakeup         = net2280_wakeup,
        .set_selfpowered = net2280_set_selfpowered,
+       .pullup         = net2280_pullup,
 };
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef USE_SYSFS_DEBUG_FILES
+#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, char *buf)
+show_function (struct device *_dev, struct device_attribute *attr, char *buf)
 {
        struct net2280  *dev = dev_get_drvdata (_dev);
 
@@ -1444,7 +1504,7 @@ show_function (struct device *_dev, char *buf)
 static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 
 static ssize_t
-show_registers (struct device *_dev, char *buf)
+show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
 {
        struct net2280          *dev;
        char                    *next;
@@ -1452,7 +1512,7 @@ show_registers (struct device *_dev, char *buf)
        unsigned long           flags;
        int                     i;
        u32                     t1, t2;
-       char                    *s;
+       const char              *s;
 
        dev = dev_get_drvdata (_dev);
        next = buf;
@@ -1599,7 +1659,7 @@ show_registers (struct device *_dev, char *buf)
 static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
 
 static ssize_t
-show_queues (struct device *_dev, char *buf)
+show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
 {
        struct net2280          *dev;
        char                    *next;
@@ -1680,8 +1740,10 @@ show_queues (struct device *_dev, char *buf)
                                td = req->td;
                                t = scnprintf (next, size, "\t    td %08x "
                                        " count %08x buf %08x desc %08x\n",
-                                       req->td_dma, td->dmacount,
-                                       td->dmaaddr, td->dmadesc);
+                                       (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;
@@ -1739,6 +1801,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
        list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
 }
 
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
 /**
  * net2280_set_fifo_mode - change allocation of fifo buffers
  * @gadget: access to the net2280 device that will be updated
@@ -1807,8 +1872,6 @@ static void usb_reset (struct net2280 *dev)
 {
        u32     tmp;
 
-       /* force immediate bus disconnect, and synch through pci */
-       writel (0, &dev->usb->usbctl);
        dev->gadget.speed = USB_SPEED_UNKNOWN;
        (void) readl (&dev->usb->usbctl);
 
@@ -1902,10 +1965,8 @@ static void ep0_start (struct net2280 *dev)
                , &dev->usb->stdrsp);
        writel (  (1 << USB_ROOT_PORT_WAKEUP_ENABLE)
                | (1 << SELF_POWERED_USB_DEVICE)
-               /* erratum 0102 workaround */
-               | ((dev->chiprev == 0100) ? 0 : 1) << SUSPEND_IMMEDIATELY
                | (1 << REMOTE_WAKEUP_SUPPORT)
-               | (1 << USB_DETECT_ENABLE)
+               | (dev->softconnect << USB_DETECT_ENABLE)
                | (1 << SELF_POWERED_STATUS)
                , &dev->usb->usbctl);
 
@@ -1957,6 +2018,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                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;
@@ -2028,6 +2090,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        stop_activity (dev, driver);
        spin_unlock_irqrestore (&dev->lock, flags);
 
+       net2280_pullup (&dev->gadget, 0);
+
        driver->unbind (&dev->gadget);
        dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
@@ -2068,7 +2132,11 @@ static void handle_ep_small (struct net2280_ep *ep)
        VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",
                        ep->ep.name, t, req ? &req->req : 0);
 #endif
-       writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);
+       if (!ep->is_in || ep->dev->pdev->device == 0x2280)
+               writel (t & ~(1 << NAK_OUT_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.
@@ -2097,7 +2165,7 @@ static void handle_ep_small (struct net2280_ep *ep)
                                        ep->stopped = 1;
                                        set_halt (ep);
                                        mode = 2;
-                               } else if (!req && ep->stopped)
+                               } else if (!req && !ep->stopped)
                                        write_fifo (ep, NULL);
                        }
                } else {
@@ -2172,7 +2240,8 @@ static void handle_ep_small (struct net2280_ep *ep)
                        if (likely (req)) {
                                req->td->dmacount = 0;
                                t = readl (&ep->regs->ep_avail);
-                               dma_done (ep, req, count, t);
+                               dma_done (ep, req, count,
+                                       (ep->out_overflow || t) ? -EOVERFLOW : 0);
                        }
 
                        /* also flush to prevent erratum 0106 trouble */
@@ -2210,9 +2279,7 @@ static void handle_ep_small (struct net2280_ep *ep)
                /* if we wrote it all, we're usually done */
                if (req->req.actual == req->req.length) {
                        if (ep->num == 0) {
-                               /* wait for control status */
-                               if (mode != 2)
-                                       req = NULL;
+                               /* send zlps until the status stage */
                        } else if (!req->req.zero || len != ep->ep.maxpacket)
                                mode = 2;
                }
@@ -2295,7 +2362,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        u32                     raw [2];
                        struct usb_ctrlrequest  r;
                } u;
-               int                             tmp = 0;
+               int                             tmp;
                struct net2280_request          *req;
 
                if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
@@ -2322,14 +2389,19 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                }
                ep->stopped = 0;
                dev->protocol_stall = 0;
-               writel (  (1 << TIMEOUT)
+
+               if (ep->dev->pdev->device == 0x2280)
+                       tmp = (1 << FIFO_OVERFLOW)
+                               | (1 << FIFO_UNDERFLOW);
+               else
+                       tmp = 0;
+
+               writel (tmp | (1 << TIMEOUT)
                        | (1 << USB_STALL_SENT)
                        | (1 << USB_IN_NAK_SENT)
                        | (1 << USB_IN_ACK_RCVD)
                        | (1 << USB_OUT_PING_NAK_SENT)
                        | (1 << USB_OUT_ACK_SENT)
-                       | (1 << FIFO_OVERFLOW)
-                       | (1 << FIFO_UNDERFLOW)
                        | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
                        | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
                        | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
@@ -2343,9 +2415,11 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                cpu_to_le32s (&u.raw [0]);
                cpu_to_le32s (&u.raw [1]);
 
-               le16_to_cpus (&u.r.wValue);
-               le16_to_cpus (&u.r.wIndex);
-               le16_to_cpus (&u.r.wLength);
+               tmp = 0;
+
+#define        w_value         le16_to_cpup (&u.r.wValue)
+#define        w_index         le16_to_cpup (&u.r.wIndex)
+#define        w_length        le16_to_cpup (&u.r.wLength)
 
                /* ack the irq */
                writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
@@ -2374,25 +2448,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                switch (u.r.bRequest) {
                case USB_REQ_GET_STATUS: {
                        struct net2280_ep       *e;
-                       u16                     status;
+                       __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, u.r.wIndex)) == 0
-                                       || u.r.wLength > 2)
+                       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 = __constant_cpu_to_le16 (1);
+                               status = __constant_cpu_to_le32 (1);
                        else
-                               status = __constant_cpu_to_le16 (0);
+                               status = __constant_cpu_to_le32 (0);
 
                        /* don't bother with a request object! */
                        writel (0, &dev->epregs [0].ep_irqenb);
-                       set_fifo_bytecount (ep, u.r.wLength);
-                       writel (status, &dev->epregs [0].ep_data);
+                       set_fifo_bytecount (ep, w_length);
+                       writel ((__force u32)status, &dev->epregs [0].ep_data);
                        allow_status (ep);
                        VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status);
                        goto next_endpoints;
@@ -2404,10 +2478,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        /* hw handles device features */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+                       if ((e = get_ep_by_addr (dev, w_index)) == 0)
                                goto do_stall;
                        clear_halt (e);
                        allow_status (ep);
@@ -2421,10 +2495,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        /* hw handles device features */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+                       if ((e = get_ep_by_addr (dev, w_index)) == 0)
                                goto do_stall;
                        set_halt (e);
                        allow_status (ep);
@@ -2434,10 +2508,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        break;
                default:
 delegate:
-                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
+                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
                                "ep_cfg %08x\n",
                                u.r.bRequestType, u.r.bRequest,
-                               u.r.wValue, u.r.wIndex,
+                               w_value, w_index, w_length,
                                readl (&ep->regs->ep_cfg));
                        spin_unlock (&dev->lock);
                        tmp = dev->driver->setup (&dev->gadget, &u.r);
@@ -2458,6 +2532,10 @@ do_stall:
                 */
        }
 
+#undef w_value
+#undef w_index
+#undef w_length
+
 next_endpoints:
        /* endpoint data irq ? */
        scratch = stat & 0x7f;
@@ -2492,15 +2570,23 @@ next_endpoints:
 static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
 {
        struct net2280_ep       *ep;
-       u32                     tmp, num, scratch;
+       u32                     tmp, num, mask, scratch;
 
        /* after disconnect there's nothing else to do! */
        tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
+       mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED);
+
+       /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
+        * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
+        * both HIGH_SPEED and FULL_SPEED 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)) != 0
-                       || (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0
-                       ) && dev->gadget.speed != USB_SPEED_UNKNOWN) {
+               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);
@@ -2525,8 +2611,8 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
                if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
                        if (dev->driver->suspend)
                                dev->driver->suspend (&dev->gadget);
-                       /* we use SUSPEND_IMMEDIATELY */
-                       stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
+                       if (!enable_suspend)
+                               stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
                } else {
                        if (dev->driver->resume)
                                dev->driver->resume (&dev->gadget);
@@ -2540,10 +2626,17 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
                writel (stat, &dev->regs->irqstat1);
 
        /* some status we can just ignore */
-       stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
-                       | (1 << SUSPEND_REQUEST_INTERRUPT)
-                       | (1 << RESUME_INTERRUPT)
-                       | (1 << SOF_INTERRUPT));
+       if (dev->pdev->device == 0x2280)
+               stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+                         | (1 << SUSPEND_REQUEST_INTERRUPT)
+                         | (1 << RESUME_INTERRUPT)
+                         | (1 << SOF_INTERRUPT));
+       else
+               stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+                         | (1 << RESUME_INTERRUPT)
+                         | (1 << SOF_DOWN_INTERRUPT)
+                         | (1 << SOF_INTERRUPT));
+
        if (!stat)
                return;
        // DEBUG (dev, "irqstat1 %08x\n", stat);
@@ -2553,7 +2646,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
        stat &= ~DMA_INTERRUPTS;
        scratch >>= 9;
        for (num = 0; scratch; num++) {
-               struct net2280_dma_regs *dma;
+               struct net2280_dma_regs __iomem *dma;
 
                tmp = 1 << num;
                if ((tmp & scratch) == 0)
@@ -2606,7 +2699,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
                                restart_dma (ep);
                        else if (ep->is_in && use_dma_chaining) {
                                struct net2280_request  *req;
-                               u32                     dmacount;
+                               __le32                  dmacount;
 
                                /* the descriptor at the head of the chain
                                 * may still have VALID_BIT clear; that's
@@ -2648,6 +2741,10 @@ static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r)
 {
        struct net2280          *dev = _dev;
 
+       /* shared interrupt, not ours */
+       if (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED)))
+               return IRQ_NONE;
+
        spin_lock (&dev->lock);
 
        /* handle disconnect, dma, and more */
@@ -2722,9 +2819,8 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct net2280          *dev;
        unsigned long           resource, len;
-       void                    *base = NULL;
+       void                    __iomem *base = NULL;
        int                     retval, i;
-       char                    buf [8], *bufp;
 
        /* if you want to support more than one controller in a system,
         * usb_gadget_driver_{register,unregister}() must change.
@@ -2735,13 +2831,13 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* alloc, and start init */
-       dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+       dev = kzalloc (sizeof *dev, SLAB_KERNEL);
        if (dev == NULL){
                retval = -ENOMEM;
                goto done;
        }
 
-       memset (dev, 0, sizeof *dev);
+       pci_set_drvdata (pdev, dev);
        spin_lock_init (&dev->lock);
        dev->pdev = pdev;
        dev->gadget.ops = &net2280_ops;
@@ -2780,14 +2876,15 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                retval = -EFAULT;
                goto done;
        }
-       dev->regs = (struct net2280_regs *) base;
-       dev->usb = (struct net2280_usb_regs *) (base + 0x0080);
-       dev->pci = (struct net2280_pci_regs *) (base + 0x0100);
-       dev->dma = (struct net2280_dma_regs *) (base + 0x0180);
-       dev->dep = (struct net2280_dep_regs *) (base + 0x0200);
-       dev->epregs = (struct net2280_ep_regs *) (base + 0x0300);
+       dev->regs = (struct net2280_regs __iomem *) base;
+       dev->usb = (struct net2280_usb_regs __iomem *) (base + 0x0080);
+       dev->pci = (struct net2280_pci_regs __iomem *) (base + 0x0100);
+       dev->dma = (struct net2280_dma_regs __iomem *) (base + 0x0180);
+       dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200);
+       dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300);
 
        /* put into initial config, link up all endpoints */
+       writel (0, &dev->usb->usbctl);
        usb_reset (dev);
        usb_reinit (dev);
 
@@ -2797,21 +2894,17 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                retval = -ENODEV;
                goto done;
        }
-#ifndef __sparc__
-       scnprintf (buf, sizeof buf, "%d", pdev->irq);
-       bufp = buf;
-#else
-       bufp = __irq_itoa(pdev->irq);
-#endif
-       if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev)
+
+       if (request_irq (pdev->irq, net2280_irq, IRQF_SHARED, driver_name, dev)
                        != 0) {
-               ERROR (dev, "request interrupt %s failed\n", bufp);
+               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 net2280_dma),
                0 /* no alignment requirements */,
@@ -2852,10 +2945,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
        dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
 
        /* done */
-       pci_set_drvdata (pdev, dev);
        INFO (dev, "%s\n", driver_desc);
-       INFO (dev, "irq %s, pci mem %p, chip rev %04x\n",
-                       bufp, base, dev->chiprev);
+       INFO (dev, "irq %d, pci mem %p, chip rev %04x\n",
+                       pdev->irq, base, dev->chiprev);
        INFO (dev, "version: " DRIVER_VERSION "; dma %s\n",
                        use_dma
                                ? (use_dma_chaining ? "chaining" : "enabled")
@@ -2873,6 +2965,22 @@ done:
        return retval;
 }
 
+/* make sure the board is quiescent; otherwise it will continue
+ * generating IRQs across the upcoming reboot.
+ */
+
+static void net2280_shutdown (struct pci_dev *pdev)
+{
+       struct net2280          *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);
+}
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -2883,6 +2991,13 @@ static struct pci_device_id pci_ids [] = { {
        .device =       0x2280,
        .subvendor =    PCI_ANY_ID,
        .subdevice =    PCI_ANY_ID,
+}, {
+       .class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+       .class_mask =   ~0,
+       .vendor =       0x17cc,
+       .device =       0x2282,
+       .subvendor =    PCI_ANY_ID,
+       .subdevice =    PCI_ANY_ID,
 
 }, { /* end: all zeroes */ }
 };
@@ -2895,6 +3010,7 @@ static struct pci_driver net2280_pci_driver = {
 
        .probe =        net2280_probe,
        .remove =       net2280_remove,
+       .shutdown =     net2280_shutdown,
 
        /* FIXME add power management support */
 };
@@ -2907,7 +3023,7 @@ static int __init init (void)
 {
        if (!use_dma)
                use_dma_chaining = 0;
-       return pci_module_init (&net2280_pci_driver);
+       return pci_register_driver (&net2280_pci_driver);
 }
 module_init (init);