USB: replace flush_workqueue with cancel_sync_work
[pandora-kernel.git] / drivers / usb / core / hcd.c
index 10064af..8969e42 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 #include <linux/platform_device.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb.h>
 
@@ -45,8 +46,6 @@
 #include "hub.h"
 
 
-// #define USB_BANDWIDTH_MESSAGES
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -546,6 +545,8 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
        unsigned long   flags;
        char            buffer[4];      /* Any root hubs with > 31 ports? */
 
+       if (unlikely(!hcd->rh_registered))
+               return;
        if (!hcd->uses_new_polling && !hcd->status_urb)
                return;
 
@@ -891,136 +892,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
 }
 EXPORT_SYMBOL (usb_calc_bus_time);
 
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-       unsigned int    pipe = urb->pipe;
-       long            bustime;
-       int             is_in = usb_pipein (pipe);
-       int             is_iso = usb_pipeisoc (pipe);
-       int             old_alloc = dev->bus->bandwidth_allocated;
-       int             new_alloc;
-
-
-       bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
-                       usb_maxpacket (dev, pipe, !is_in)));
-       if (is_iso)
-               bustime /= urb->number_of_packets;
-
-       new_alloc = old_alloc + (int) bustime;
-       if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef DEBUG
-               char    *mode = 
-#ifdef CONFIG_USB_BANDWIDTH
-                       "";
-#else
-                       "would have ";
-#endif
-               dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
-                       mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
-               bustime = -ENOSPC;      /* report error */
-#endif
-       }
-
-       return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-       dev->bus->bandwidth_allocated += bustime;
-       if (isoc)
-               dev->bus->bandwidth_isoc_reqs++;
-       else
-               dev->bus->bandwidth_int_reqs++;
-       urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-       dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
-               bustime,
-               isoc ? "ISOC" : "INTR",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
-       dev->bus->bandwidth_allocated -= urb->bandwidth;
-       if (isoc)
-               dev->bus->bandwidth_isoc_reqs--;
-       else
-               dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-       dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
-               urb->bandwidth,
-               isoc ? "ISOC" : "INTR",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-       urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1034,11 +905,6 @@ static void urb_unlink (struct urb *urb)
 {
        unsigned long           flags;
 
-       /* Release any periodic transfer bandwidth */
-       if (urb->bandwidth)
-               usb_release_bandwidth (urb->dev, urb,
-                       usb_pipeisoc (urb->pipe));
-
        /* clear all state linking urb to this dev (and hcd) */
 
        spin_lock_irqsave (&hcd_data_lock, flags);
@@ -1152,8 +1018,8 @@ done:
                atomic_dec (&urb->use_count);
                if (urb->reject)
                        wake_up (&usb_kill_urb_queue);
-               usb_put_urb (urb);
                usbmon_urb_submit_error(&hcd->self, urb, status);
+               usb_put_urb (urb);
        }
        return status;
 }
@@ -1309,10 +1175,6 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
        struct urb              *urb;
 
        hcd = bus_to_hcd(udev->bus);
-
-       WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
-                       udev->state != USB_STATE_NOTATTACHED);
-
        local_irq_disable ();
 
        /* ep is already gone from udev->ep_{in,out}[]; no more submits */
@@ -1433,14 +1295,26 @@ int hcd_bus_resume (struct usb_bus *bus)
        return status;
 }
 
+/* Workqueue routine for root-hub remote wakeup */
+static void hcd_resume_work(struct work_struct *work)
+{
+       struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);
+       struct usb_device *udev = hcd->self.root_hub;
+
+       usb_lock_device(udev);
+       usb_mark_last_busy(udev);
+       usb_external_resume_device(udev);
+       usb_unlock_device(udev);
+}
+
 /**
  * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
  * @hcd: host controller for this root hub
  *
  * The USB host controller calls this function when its root hub is
  * suspended (with the remote wakeup feature enabled) and a remote
- * wakeup request is received.  It queues a request for khubd to
- * resume the root hub (that is, manage its downstream ports again).
+ * wakeup request is received.  The routine submits a workqueue request
+ * to resume the root hub (that is, manage its downstream ports again).
  */
 void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 {
@@ -1448,7 +1322,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
        if (hcd->rh_registered)
-               usb_resume_root_hub (hcd->self.root_hub);
+               queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
        spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
@@ -1637,6 +1511,9 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
        init_timer(&hcd->rh_timer);
        hcd->rh_timer.function = rh_timer_func;
        hcd->rh_timer.data = (unsigned long) hcd;
+#ifdef CONFIG_PM
+       INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
+#endif
 
        hcd->driver = driver;
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@@ -1803,16 +1680,20 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        hcd->rh_registered = 0;
        spin_unlock_irq (&hcd_root_hub_lock);
 
+#ifdef CONFIG_PM
+       cancel_work_sync(&hcd->wakeup_work);
+#endif
+
        mutex_lock(&usb_bus_list_lock);
        usb_disconnect(&hcd->self.root_hub);
        mutex_unlock(&usb_bus_list_lock);
 
-       hcd->poll_rh = 0;
-       del_timer_sync(&hcd->rh_timer);
-
        hcd->driver->stop(hcd);
        hcd->state = HC_STATE_HALT;
 
+       hcd->poll_rh = 0;
+       del_timer_sync(&hcd->rh_timer);
+
        if (hcd->irq >= 0)
                free_irq(hcd->irq, hcd);
        usb_deregister_bus(&hcd->self);