#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);
}
*/
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",
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;
* 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 =
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;
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",