Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
[sfrench/cifs-2.6.git] / drivers / usb / core / message.c
index 25f63f1096b43d4d9a6da4e266e212cf09d48549..d8f7b089a8f0ad243f3218cbb50c78deed02301b 100644 (file)
 #include "hcd.h"       /* for usbcore internals */
 #include "usb.h"
 
+struct api_context {
+       struct completion       done;
+       int                     status;
+};
+
 static void usb_api_blocking_completion(struct urb *urb)
 {
-       complete((struct completion *)urb->context);
+       struct api_context *ctx = urb->context;
+
+       ctx->status = urb->status;
+       complete(&ctx->done);
 }
 
 
@@ -32,20 +40,21 @@ static void usb_api_blocking_completion(struct urb *urb)
  */
 static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
 { 
-       struct completion done;
+       struct api_context ctx;
        unsigned long expire;
        int retval;
-       int status = urb->status;
 
-       init_completion(&done);         
-       urb->context = &done;
+       init_completion(&ctx.done);
+       urb->context = &ctx;
        urb->actual_length = 0;
        retval = usb_submit_urb(urb, GFP_NOIO);
        if (unlikely(retval))
                goto out;
 
        expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
-       if (!wait_for_completion_timeout(&done, expire)) {
+       if (!wait_for_completion_timeout(&ctx.done, expire)) {
+               usb_kill_urb(urb);
+               retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
 
                dev_dbg(&urb->dev->dev,
                        "%s timed out on ep%d%s len=%d/%d\n",
@@ -54,11 +63,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
                        usb_pipein(urb->pipe) ? "in" : "out",
                        urb->actual_length,
                        urb->transfer_buffer_length);
-
-               usb_kill_urb(urb);
-               retval = status == -ENOENT ? -ETIMEDOUT : status;
        } else
-               retval = status;
+               retval = ctx.status;
 out:
        if (actual_length)
                *actual_length = urb->actual_length;
@@ -411,15 +417,22 @@ int usb_sg_init (
                 * Some systems need to revert to PIO when DMA is temporarily
                 * unavailable.  For their sakes, both transfer_buffer and
                 * transfer_dma are set when possible.  However this can only
-                * work on systems without HIGHMEM, since DMA buffers located
-                * in high memory are not directly addressable by the CPU for
-                * PIO ... so when HIGHMEM is in use, transfer_buffer is NULL
+                * work on systems without:
+                *
+                *  - HIGHMEM, since DMA buffers located in high memory are
+                *    not directly addressable by the CPU for PIO;
+                *
+                *  - IOMMU, since dma_map_sg() is allowed to use an IOMMU to
+                *    make virtually discontiguous buffers be "dma-contiguous"
+                *    so that PIO and DMA need diferent numbers of URBs.
+                *
+                * So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL
                 * to prevent stale pointers and to help spot bugs.
                 */
                if (dma) {
                        io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
                        len = sg_dma_len (sg + i);
-#ifdef CONFIG_HIGHMEM
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_IOMMU)
                        io->urbs[i]->transfer_buffer = NULL;
 #else
                        io->urbs[i]->transfer_buffer =
@@ -624,12 +637,12 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
        memset(buf,0,size);     // Make sure we parse really received data
 
        for (i = 0; i < 3; ++i) {
-               /* retry on length 0 or stall; some devices are flakey */
+               /* retry on length 0 or error; some devices are flakey */
                result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                                USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                                (type << 8) + index, 0, buf, size,
                                USB_CTRL_GET_TIMEOUT);
-               if (result == 0 || result == -EPIPE)
+               if (result <= 0 && result != -ETIMEDOUT)
                        continue;
                if (result > 1 && ((u8 *)buf)[1] != type) {
                        result = -EPROTO;
@@ -1345,6 +1358,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
        usb_dev = interface_to_usbdev(intf);
        alt = intf->cur_altsetting;
 
+#ifdef CONFIG_USB_DEVICEFS
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "DEVICE=/proc/bus/usb/%03d/%03d",
+                          usb_dev->bus->busnum, usb_dev->devnum))
+               return -ENOMEM;
+#endif
+
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "PRODUCT=%x/%x/%x",
+                          le16_to_cpu(usb_dev->descriptor.idVendor),
+                          le16_to_cpu(usb_dev->descriptor.idProduct),
+                          le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+               return -ENOMEM;
+
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "TYPE=%d/%d/%d",
+                          usb_dev->descriptor.bDeviceClass,
+                          usb_dev->descriptor.bDeviceSubClass,
+                          usb_dev->descriptor.bDeviceProtocol))
+               return -ENOMEM;
+
        if (add_uevent_var(envp, num_envp, &i,
                   buffer, buffer_size, &length,
                   "INTERFACE=%d/%d/%d",