init: move setup of nr_cpu_ids to as early as possible
[safe/jmp/linux-2.6] / drivers / usb / core / urb.c
index 1a64a6a..9d7e632 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include "hcd.h"
@@ -38,10 +39,10 @@ void usb_init_urb(struct urb *urb)
        if (urb) {
                memset(urb, 0, sizeof(*urb));
                kref_init(&urb->kref);
-               spin_lock_init(&urb->lock);
                INIT_LIST_HEAD(&urb->anchor_list);
        }
 }
+EXPORT_SYMBOL_GPL(usb_init_urb);
 
 /**
  * usb_alloc_urb - creates a new urb for a USB driver to use
@@ -73,6 +74,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
        usb_init_urb(urb);
        return urb;
 }
+EXPORT_SYMBOL_GPL(usb_alloc_urb);
 
 /**
  * usb_free_urb - frees the memory used by a urb when all users of it are finished
@@ -89,6 +91,7 @@ void usb_free_urb(struct urb *urb)
        if (urb)
                kref_put(&urb->kref, urb_destroy);
 }
+EXPORT_SYMBOL_GPL(usb_free_urb);
 
 /**
  * usb_get_urb - increments the reference count of the urb
@@ -100,12 +103,13 @@ void usb_free_urb(struct urb *urb)
  *
  * A pointer to the urb with the incremented reference counter is returned.
  */
-struct urb * usb_get_urb(struct urb *urb)
+struct urb *usb_get_urb(struct urb *urb)
 {
        if (urb)
                kref_get(&urb->kref);
        return urb;
 }
+EXPORT_SYMBOL_GPL(usb_get_urb);
 
 /**
  * usb_anchor_urb - anchors an URB while it is processed
@@ -172,7 +176,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  * describing that request to the USB subsystem.  Request completion will
  * be indicated later, asynchronously, by calling the completion handler.
  * The three types of completion are success, error, and unlink
- * (a software-induced fault, also called "request cancellation").  
+ * (a software-induced fault, also called "request cancellation").
  *
  * URBs may be submitted in interrupt context.
  *
@@ -255,7 +259,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  *       semaphores), or
  *   (c) current->state != TASK_RUNNING, this is the case only after
  *       you've changed it.
- * 
+ *
  * GFP_NOIO is used in the block io path and error handling of storage
  * devices.
  *
@@ -284,13 +288,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        if (!urb || urb->hcpriv || !urb->complete)
                return -EINVAL;
-       if (!(dev = urb->dev) ||
-           (dev->state < USB_STATE_DEFAULT) ||
-           (!dev->bus) || (dev->devnum <= 0))
+       dev = urb->dev;
+       if ((!dev) || (dev->state < USB_STATE_DEFAULT))
                return -ENODEV;
-       if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
-                       || dev->state == USB_STATE_SUSPENDED)
-               return -EHOSTUNREACH;
 
        /* For now, get the endpoint from the pipe.  Eventually drivers
         * will be required to set urb->ep directly and we will eliminate
@@ -352,11 +352,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        max *= mult;
                }
 
-               if (urb->number_of_packets <= 0)                    
+               if (urb->number_of_packets <= 0)
                        return -EINVAL;
                for (n = 0; n < urb->number_of_packets; n++) {
                        len = urb->iso_frame_desc[n].length;
-                       if (len < 0 || len > max) 
+                       if (len < 0 || len > max)
                                return -EMSGSIZE;
                        urb->iso_frame_desc[n].status = -EXDEV;
                        urb->iso_frame_desc[n].actual_length = 0;
@@ -377,7 +377,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        /* enforce simple/standard policy */
        allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-                       URB_NO_INTERRUPT | URB_DIR_MASK);
+                       URB_NO_INTERRUPT | URB_DIR_MASK | URB_FREE_BUFFER);
        switch (xfertype) {
        case USB_ENDPOINT_XFER_BULK:
                if (is_out)
@@ -421,7 +421,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                /* too big? */
                switch (dev->speed) {
                case USB_SPEED_HIGH:    /* units are microframes */
-                       // NOTE usb handles 2^15
+                       /* NOTE usb handles 2^15 */
                        if (urb->interval > (1024 * 8))
                                urb->interval = 1024 * 8;
                        max = 1024 * 8;
@@ -431,26 +431,25 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        if (xfertype == USB_ENDPOINT_XFER_INT) {
                                if (urb->interval > 255)
                                        return -EINVAL;
-                               // NOTE ohci only handles up to 32
+                               /* NOTE ohci only handles up to 32 */
                                max = 128;
                        } else {
                                if (urb->interval > 1024)
                                        urb->interval = 1024;
-                               // NOTE usb and ohci handle up to 2^15
+                               /* NOTE usb and ohci handle up to 2^15 */
                                max = 1024;
                        }
                        break;
                default:
                        return -EINVAL;
                }
-               /* power of two? */
-               while (max > urb->interval)
-                       max >>= 1;
-               urb->interval = max;
+               /* Round down to a power of 2, no more than max */
+               urb->interval = min(max, 1 << ilog2(urb->interval));
        }
 
        return usb_hcd_submit_urb(urb, mem_flags);
 }
+EXPORT_SYMBOL_GPL(usb_submit_urb);
 
 /*-------------------------------------------------------------------*/
 
@@ -515,10 +514,13 @@ int usb_unlink_urb(struct urb *urb)
 {
        if (!urb)
                return -EINVAL;
-       if (!(urb->dev && urb->dev->bus))
+       if (!urb->dev)
                return -ENODEV;
+       if (!urb->ep)
+               return -EIDRM;
        return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
+EXPORT_SYMBOL_GPL(usb_unlink_urb);
 
 /**
  * usb_kill_urb - cancel a transfer request and wait for it to finish
@@ -542,20 +544,23 @@ int usb_unlink_urb(struct urb *urb)
  */
 void usb_kill_urb(struct urb *urb)
 {
+       static DEFINE_MUTEX(reject_mutex);
+
        might_sleep();
-       if (!(urb && urb->dev && urb->dev->bus))
+       if (!(urb && urb->dev && urb->ep))
                return;
-       spin_lock_irq(&urb->lock);
+       mutex_lock(&reject_mutex);
        ++urb->reject;
-       spin_unlock_irq(&urb->lock);
+       mutex_unlock(&reject_mutex);
 
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
-       spin_lock_irq(&urb->lock);
+       mutex_lock(&reject_mutex);
        --urb->reject;
-       spin_unlock_irq(&urb->lock);
+       mutex_unlock(&reject_mutex);
 }
+EXPORT_SYMBOL_GPL(usb_kill_urb);
 
 /**
  * usb_kill_anchored_urbs - cancel transfer requests en masse
@@ -570,7 +575,8 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor)
 
        spin_lock_irq(&anchor->lock);
        while (!list_empty(&anchor->urb_list)) {
-               victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
+               victim = list_entry(anchor->urb_list.prev, struct urb,
+                                   anchor_list);
                /* we must make sure the URB isn't freed before we kill it*/
                usb_get_urb(victim);
                spin_unlock_irq(&anchor->lock);
@@ -598,11 +604,3 @@ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
                                  msecs_to_jiffies(timeout));
 }
 EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
-
-EXPORT_SYMBOL(usb_init_urb);
-EXPORT_SYMBOL(usb_alloc_urb);
-EXPORT_SYMBOL(usb_free_urb);
-EXPORT_SYMBOL(usb_get_urb);
-EXPORT_SYMBOL(usb_submit_urb);
-EXPORT_SYMBOL(usb_unlink_urb);
-EXPORT_SYMBOL(usb_kill_urb);