rndis_wlan: stop workers on rndis_wlan_stop() and restore on rndis_wlan_reset()
[safe/jmp/linux-2.6] / drivers / usb / gadget / net2280.c
index d954daa..9498be8 100644 (file)
@@ -53,9 +53,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
@@ -63,8 +61,8 @@
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -144,8 +142,8 @@ static char *type_string (u8 bmAttributes)
 
 #include "net2280.h"
 
-#define valid_bit      __constant_cpu_to_le32 (1 << VALID_BIT)
-#define dma_done_ie    __constant_cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
+#define valid_bit      cpu_to_le32 (1 << VALID_BIT)
+#define dma_done_ie    cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
 
 /*-------------------------------------------------------------------------*/
 
@@ -180,6 +178,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 
        /* ep_reset() has already been called */
        ep->stopped = 0;
+       ep->wedged = 0;
        ep->out_overflow = 0;
 
        /* set speed-dependent max packet; may kick in high bandwidth */
@@ -426,7 +425,7 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
                        return NULL;
                }
                td->dmacount = 0;       /* not VALID */
-               td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+               td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
                td->dmadesc = td->dmaaddr;
                req->td = td;
        }
@@ -452,100 +451,6 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck.  Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled:  alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-net2280_alloc_buffer (
-       struct usb_ep           *_ep,
-       unsigned                bytes,
-       dma_addr_t              *dma,
-       gfp_t                   gfp_flags
-)
-{
-       void                    *retval;
-       struct net2280_ep       *ep;
-
-       ep = container_of (_ep, struct net2280_ep, ep);
-       if (!_ep)
-               return NULL;
-       *dma = DMA_ADDR_INVALID;
-
-       if (ep->dma)
-               retval = dma_alloc_coherent(&ep->dev->pdev->dev,
-                               bytes, dma, gfp_flags);
-       else
-               retval = kmalloc(bytes, gfp_flags);
-       return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
-       struct list_head        list;
-       struct device           *dev;
-       unsigned                bytes;
-       dma_addr_t              dma;
-};
-
-static void do_free(unsigned long ignored)
-{
-       spin_lock_irq(&buflock);
-       while (!list_empty(&buffers)) {
-               struct free_record      *buf;
-
-               buf = list_entry(buffers.next, struct free_record, list);
-               list_del(&buf->list);
-               spin_unlock_irq(&buflock);
-
-               dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
-               spin_lock_irq(&buflock);
-       }
-       spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void
-net2280_free_buffer (
-       struct usb_ep *_ep,
-       void *address,
-       dma_addr_t dma,
-       unsigned bytes
-) {
-       /* free memory into the right allocator */
-       if (dma != DMA_ADDR_INVALID) {
-               struct net2280_ep       *ep;
-               struct free_record      *buf = address;
-               unsigned long           flags;
-
-               ep = container_of(_ep, struct net2280_ep, ep);
-               if (!_ep)
-                       return;
-
-               ep = container_of (_ep, struct net2280_ep, ep);
-               buf->dev = &ep->dev->pdev->dev;
-               buf->bytes = bytes;
-               buf->dma = dma;
-
-               spin_lock_irqsave(&buflock, flags);
-               list_add_tail(&buf->list, &buffers);
-               tasklet_schedule(&deferred_free);
-               spin_unlock_irqrestore(&buflock, flags);
-       } else
-               kfree (address);
-}
-
-/*-------------------------------------------------------------------------*/
-
 /* load a packet into the fifo we use for usb IN transfers.
  * works for all endpoints.
  *
@@ -764,7 +669,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
 
        /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
        wmb ();
-       td->dmacount = cpu_to_le32p (&dmacount);
+       td->dmacount = cpu_to_le32(dmacount);
 }
 
 static const u32 dmactl_default =
@@ -870,7 +775,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
        fill_dma_desc (ep, req, 1);
 
        if (!use_dma_chaining)
-               req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
+               req->td->dmacount |= cpu_to_le32 (1 << END_OF_CHAIN);
 
        start_queue (ep, tmp, req->td_dma);
 }
@@ -1040,6 +945,7 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        } /* else the irq handler advances the queue. */
 
+       ep->responded = 1;
        if (req)
                list_add_tail (&req->queue, &ep->queue);
 done:
@@ -1102,7 +1008,7 @@ static void scan_dma_completions (struct net2280_ep *ep)
                         * 0122, and 0124; not all cases trigger the warning.
                         */
                        if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
-                               WARN (ep->dev, "%s lost packet sync!\n",
+                               WARNING (ep->dev, "%s lost packet sync!\n",
                                                ep->ep.name);
                                req->req.status = -EOVERFLOW;
                        } else if ((tmp = readl (&ep->regs->ep_avail)) != 0) {
@@ -1313,7 +1219,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
 static int net2280_fifo_status (struct usb_ep *_ep);
 
 static int
-net2280_set_halt (struct usb_ep *_ep, int value)
+net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
 {
        struct net2280_ep       *ep;
        unsigned long           flags;
@@ -1334,16 +1240,21 @@ net2280_set_halt (struct usb_ep *_ep, int value)
        else if (ep->is_in && value && net2280_fifo_status (_ep) != 0)
                retval = -EAGAIN;
        else {
-               VDEBUG (ep->dev, "%s %s halt\n", _ep->name,
-                               value ? "set" : "clear");
+               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
                                set_halt (ep);
-               } else
+                       if (wedged)
+                               ep->wedged = 1;
+               } else {
                        clear_halt (ep);
+                       ep->wedged = 0;
+               }
                (void) readl (&ep->regs->ep_rsp);
        }
        spin_unlock_irqrestore (&ep->dev->lock, flags);
@@ -1352,6 +1263,20 @@ net2280_set_halt (struct usb_ep *_ep, int value)
 }
 
 static int
+net2280_set_halt(struct usb_ep *_ep, int value)
+{
+       return net2280_set_halt_and_wedge(_ep, value, 0);
+}
+
+static int
+net2280_set_wedge(struct usb_ep *_ep)
+{
+       if (!_ep || _ep->name == ep0name)
+               return -EINVAL;
+       return net2280_set_halt_and_wedge(_ep, 1, 1);
+}
+
+static int
 net2280_fifo_status (struct usb_ep *_ep)
 {
        struct net2280_ep       *ep;
@@ -1393,13 +1318,11 @@ static const struct usb_ep_ops net2280_ep_ops = {
        .alloc_request  = net2280_alloc_request,
        .free_request   = net2280_free_request,
 
-       .alloc_buffer   = net2280_alloc_buffer,
-       .free_buffer    = net2280_free_buffer,
-
        .queue          = net2280_queue,
        .dequeue        = net2280_dequeue,
 
        .set_halt       = net2280_set_halt,
+       .set_wedge      = net2280_set_wedge,
        .fifo_status    = net2280_fifo_status,
        .fifo_flush     = net2280_fifo_flush,
 };
@@ -1516,8 +1439,8 @@ show_function (struct device *_dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
 
-static ssize_t
-show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
+static ssize_t net2280_show_registers(struct device *_dev,
+                               struct device_attribute *attr, char *buf)
 {
        struct net2280          *dev;
        char                    *next;
@@ -1669,7 +1592,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
 
        return PAGE_SIZE - size;
 }
-static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+static DEVICE_ATTR(registers, S_IRUGO, net2280_show_registers, NULL);
 
 static ssize_t
 show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
@@ -1774,8 +1697,8 @@ static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
 
 #else
 
-#define device_create_file(a,b)        do {} while (0)
-#define device_remove_file     device_create_file
+#define device_create_file(a,b)        (0)
+#define device_remove_file(a,b)        do { } while (0)
 
 #endif
 
@@ -2019,7 +1942,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        if (!driver
                        || driver->speed != USB_SPEED_HIGH
                        || !driver->bind
-                       || !driver->unbind
                        || !driver->setup)
                return -EINVAL;
        if (!dev)
@@ -2044,8 +1966,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                return retval;
        }
 
-       device_create_file (&dev->pdev->dev, &dev_attr_function);
-       device_create_file (&dev->pdev->dev, &dev_attr_queues);
+       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.
@@ -2060,6 +1984,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 
        /* 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;
 }
 EXPORT_SYMBOL (usb_gadget_register_driver);
 
@@ -2096,7 +2028,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
        if (!dev)
                return -ENODEV;
-       if (!driver || driver != dev->driver)
+       if (!driver || driver != dev->driver || !driver->unbind)
                return -EINVAL;
 
        spin_lock_irqsave (&dev->lock, flags);
@@ -2178,7 +2110,8 @@ static void handle_ep_small (struct net2280_ep *ep)
                                        ep->stopped = 1;
                                        set_halt (ep);
                                        mode = 2;
-                               } else if (!req && !ep->stopped)
+                               } else if (ep->responded &&
+                                               !req && !ep->stopped)
                                        write_fifo (ep, NULL);
                        }
                } else {
@@ -2193,7 +2126,7 @@ static void handle_ep_small (struct net2280_ep *ep)
                        } else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT))
                                        && req
                                        && req->req.actual == req->req.length)
-                                       || !req) {
+                                       || (ep->responded && !req)) {
                                ep->dev->protocol_stall = 1;
                                set_halt (ep);
                                ep->stopped = 1;
@@ -2431,9 +2364,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
 
                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)
+#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)
 
                /* ack the irq */
                writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
@@ -2459,6 +2392,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                /* we made the hardware handle most lowlevel requests;
                 * everything else goes uplevel to the gadget code.
                 */
+               ep->responded = 1;
                switch (u.r.bRequest) {
                case USB_REQ_GET_STATUS: {
                        struct net2280_ep       *e;
@@ -2473,9 +2407,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
 
                        if (readl (&e->regs->ep_rsp)
                                        & (1 << SET_ENDPOINT_HALT))
-                               status = __constant_cpu_to_le32 (1);
+                               status = cpu_to_le32 (1);
                        else
-                               status = __constant_cpu_to_le32 (0);
+                               status = cpu_to_le32 (0);
 
                        /* don't bother with a request object! */
                        writel (0, &dev->epregs [0].ep_irqenb);
@@ -2497,9 +2431,14 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                                goto do_stall;
                        if ((e = get_ep_by_addr (dev, w_index)) == 0)
                                goto do_stall;
-                       clear_halt (e);
+                       if (e->wedged) {
+                               VDEBUG(dev, "%s wedged, halt not cleared\n",
+                                               ep->ep.name);
+                       } else {
+                               VDEBUG(dev, "%s clear halt\n", ep->ep.name);
+                               clear_halt(e);
+                       }
                        allow_status (ep);
-                       VDEBUG (dev, "%s clear halt\n", ep->ep.name);
                        goto next_endpoints;
                        }
                        break;
@@ -2514,6 +2453,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                                goto do_stall;
                        if ((e = get_ep_by_addr (dev, w_index)) == 0)
                                goto do_stall;
+                       if (e->ep.name == ep0name)
+                               goto do_stall;
                        set_halt (e);
                        allow_status (ep);
                        VDEBUG (dev, "%s set halt\n", ep->ep.name);
@@ -2522,11 +2463,12 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        break;
                default:
 delegate:
-                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
+                       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->regs->ep_cfg));
+                       ep->responded = 0;
                        spin_unlock (&dev->lock);
                        tmp = dev->driver->setup (&dev->gadget, &u.r);
                        spin_lock (&dev->lock);
@@ -2725,7 +2667,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
                                req = list_entry (ep->queue.next,
                                                struct net2280_request, queue);
                                dmacount = req->td->dmacount;
-                               dmacount &= __constant_cpu_to_le32 (
+                               dmacount &= cpu_to_le32 (
                                                (1 << VALID_BIT)
                                                | DMA_BYTE_COUNT_MASK);
                                if (dmacount && (dmacount & valid_bit) == 0)
@@ -2789,13 +2731,7 @@ static void net2280_remove (struct pci_dev *pdev)
 {
        struct net2280          *dev = pci_get_drvdata (pdev);
 
-       /* start with the driver above us */
-       if (dev->driver) {
-               /* should have been done already by driver model core */
-               WARN (dev, "pci remove, driver '%s' is still registered\n",
-                               dev->driver->driver.name);
-               usb_gadget_unregister_driver (dev->driver);
-       }
+       BUG_ON(dev->driver);
 
        /* then clean up the resources we allocated during probe() */
        net2280_led_shutdown (dev);
@@ -2847,7 +2783,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        /* alloc, and start init */
-       dev = kzalloc (sizeof *dev, SLAB_KERNEL);
+       dev = kzalloc (sizeof *dev, GFP_KERNEL);
        if (dev == NULL){
                retval = -ENOMEM;
                goto done;
@@ -2860,7 +2796,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
        dev->gadget.is_dualspeed = 1;
 
        /* the "gadget" abstracts/virtualizes the controller */
-       strcpy (dev->gadget.dev.bus_id, "gadget");
+       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;
@@ -2945,7 +2881,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                        goto done;
                }
                td->dmacount = 0;       /* not VALID */
-               td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+               td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
                td->dmadesc = td->dmaaddr;
                dev->ep [i].dummy = td;
        }
@@ -2959,7 +2895,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                        , &dev->pci->pcimstctl);
        /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */
        pci_set_master (pdev);
-       pci_set_mwi (pdev);
+       pci_try_set_mwi (pdev);
 
        /* ... also flushes any posted pci writes */
        dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
@@ -2974,8 +2910,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                                : "disabled");
        the_controller = dev;
 
-       device_register (&dev->gadget.dev);
-       device_create_file (&pdev->dev, &dev_attr_registers);
+       retval = device_register (&dev->gadget.dev);
+       if (retval) goto done;
+       retval = device_create_file (&pdev->dev, &dev_attr_registers);
+       if (retval) goto done;
 
        return 0;