X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Fmessage.c;h=149aa8bfb1fe4e2bb353ae49f490e7dc081ea48a;hb=refs%2Fheads%2Fvserver;hp=e0165ae9cfc0f4ba10b4f76bf181d015d162672f;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index e0165ae9c..149aa8bfb 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -2,14 +2,6 @@ * message.c - synchronous message handling */ -#include - -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif - #include /* for scatterlist macros */ #include #include @@ -20,72 +12,65 @@ #include #include #include +#include #include "hcd.h" /* for usbcore internals */ #include "usb.h" -static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) +static void usb_api_blocking_completion(struct urb *urb) { complete((struct completion *)urb->context); } -static void timeout_kill(unsigned long data) -{ - struct urb *urb = (struct urb *) data; - - usb_unlink_urb(urb); -} - -// Starts urb and waits for completion or timeout -// note that this call is NOT interruptible, while -// many device driver i/o requests should be interruptible -static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) +/* + * Starts urb and waits for completion or timeout. Note that this call + * is NOT interruptible. Many device driver i/o requests should be + * interruptible and therefore these drivers should implement their + * own interruptible routines. + */ +static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) { - struct completion done; - struct timer_list timer; - int status; + struct completion done; + unsigned long expire; + int status; init_completion(&done); urb->context = &done; - urb->transfer_flags |= URB_ASYNC_UNLINK; urb->actual_length = 0; status = usb_submit_urb(urb, GFP_NOIO); - - if (status == 0) { - if (timeout > 0) { - init_timer(&timer); - timer.expires = jiffies + timeout; - timer.data = (unsigned long)urb; - timer.function = timeout_kill; - /* grr. timeout _should_ include submit delays. */ - add_timer(&timer); - } - wait_for_completion(&done); + if (unlikely(status)) + goto out; + + expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; + if (!wait_for_completion_timeout(&done, expire)) { + + dev_dbg(&urb->dev->dev, + "%s timed out on ep%d%s len=%d/%d\n", + current->comm, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->actual_length, + urb->transfer_buffer_length); + + usb_kill_urb(urb); + status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; + } else status = urb->status; - /* note: HCDs return ETIMEDOUT for other reasons too */ - if (status == -ECONNRESET) { - dev_warn(&urb->dev->dev, - "%s timed out on ep%d%s\n", - current->comm, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out"); - status = -ETIMEDOUT; - } - if (timeout > 0) - del_timer_sync(&timer); - } - +out: if (actual_length) *actual_length = urb->actual_length; + usb_free_urb(urb); return status; } /*-------------------------------------------------------------------*/ // returns status (negative) or length (positive) -int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, - struct usb_ctrlrequest *cmd, void *data, int len, int timeout) +static int usb_internal_control_msg(struct usb_device *usb_dev, + unsigned int pipe, + struct usb_ctrlrequest *cmd, + void *data, int len, int timeout) { struct urb *urb; int retv; @@ -115,7 +100,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, * @index: USB message index value * @data: pointer to the data to send * @size: length in bytes of the data to send - * @timeout: time in jiffies to wait for the message to complete before + * @timeout: time in msecs to wait for the message to complete before * timing out (if 0 the wait is forever) * Context: !in_interrupt () * @@ -156,6 +141,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u } +/** + * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion + * @usb_dev: pointer to the usb device to send the message to + * @pipe: endpoint "pipe" to send the message to + * @data: pointer to the data to send + * @len: length in bytes of the data to send + * @actual_length: pointer to a location to put the actual length transferred in bytes + * @timeout: time in msecs to wait for the message to complete before + * timing out (if 0 the wait is forever) + * Context: !in_interrupt () + * + * This function sends a simple interrupt message to a specified endpoint and + * waits for the message to complete, or timeout. + * + * If successful, it returns 0, otherwise a negative error number. The number + * of actual bytes transferred will be stored in the actual_length paramater. + * + * Don't use this function from within an interrupt context, like a bottom half + * handler. If you need an asynchronous message, or need to send a message + * from within interrupt context, use usb_submit_urb() If a thread in your + * driver uses this call, make sure your disconnect() method can wait for it to + * complete. Since you don't have a handle on the URB used, you can't cancel + * the request. + */ +int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) +{ + return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout); +} +EXPORT_SYMBOL_GPL(usb_interrupt_msg); + /** * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion * @usb_dev: pointer to the usb device to send the message to @@ -163,7 +179,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u * @data: pointer to the data to send * @len: length in bytes of the data to send * @actual_length: pointer to a location to put the actual length transferred in bytes - * @timeout: time in jiffies to wait for the message to complete before + * @timeout: time in msecs to wait for the message to complete before * timing out (if 0 the wait is forever) * Context: !in_interrupt () * @@ -180,23 +196,39 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u * If a thread in your driver uses this call, make sure your disconnect() * method can wait for it to complete. Since you don't have a handle on * the URB used, you can't cancel the request. + * + * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT + * ioctl, users are forced to abuse this routine by using it to submit + * URBs for interrupt endpoints. We will take the liberty of creating + * an interrupt URB (with the default interval) if the target is an + * interrupt endpoint. */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) { struct urb *urb; + struct usb_host_endpoint *ep; - if (len < 0) + ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out) + [usb_pipeendpoint(pipe)]; + if (!ep || len < 0) return -EINVAL; - urb=usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; - usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, - usb_api_blocking_completion, NULL); - - return usb_start_wait_urb(urb,timeout,actual_length); + if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT) { + pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); + usb_fill_int_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL, + ep->desc.bInterval); + } else + usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, + usb_api_blocking_completion, NULL); + + return usb_start_wait_urb(urb, timeout, actual_length); } /*-------------------------------------------------------------------*/ @@ -214,9 +246,9 @@ static void sg_clean (struct usb_sg_request *io) io->dev = NULL; } -static void sg_complete (struct urb *urb, struct pt_regs *regs) +static void sg_complete (struct urb *urb) { - struct usb_sg_request *io = (struct usb_sg_request *) urb->context; + struct usb_sg_request *io = urb->context; spin_lock (&io->lock); @@ -258,7 +290,9 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs) continue; if (found) { status = usb_unlink_urb (io->urbs [i]); - if (status != -EINPROGRESS && status != -EBUSY) + if (status != -EINPROGRESS + && status != -ENODEV + && status != -EBUSY) dev_err (&io->dev->dev, "%s, unlink --> %d\n", __FUNCTION__, status); @@ -312,7 +346,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - int mem_flags + gfp_t mem_flags ) { int i; @@ -349,8 +383,7 @@ int usb_sg_init ( if (!io->urbs) goto nomem; - urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP - | URB_NO_INTERRUPT; + urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; @@ -423,7 +456,7 @@ nomem: * (2) error, where io->status is a negative errno value. The number * of io->bytes transferred before the error is usually less * than requested, and can be nonzero. - * (3) cancelation, a type of error with status -ECONNRESET that + * (3) cancellation, a type of error with status -ECONNRESET that * is initiated by usb_sg_cancel(). * * When this function returns, all memory allocated through usb_sg_init() or @@ -455,7 +488,7 @@ void usb_sg_wait (struct usb_sg_request *io) int retval; io->urbs [i]->dev = io->dev; - retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC); + retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC); /* after we submit, let completions or cancelations fire; * we handshake using io->status. @@ -579,7 +612,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); if (result == 0 || result == -EPIPE) continue; if (result > 1 && ((u8 *)buf)[1] != type) { @@ -613,8 +646,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_string(struct usb_device *dev, unsigned short langid, - unsigned char index, void *buf, int size) +static int usb_get_string(struct usb_device *dev, unsigned short langid, + unsigned char index, void *buf, int size) { int i; int result; @@ -624,7 +657,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + index, langid, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); if (!(result == 0 || result == -EPIPE)) break; } @@ -731,7 +764,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = -EINVAL; goto errout; } else { - dev->have_langid = -1; + dev->have_langid = 1; dev->string_langid = tbuf[2] | (tbuf[3]<< 8); /* always use the first langid listed */ dev_dbg (&dev->dev, "default language 0x%04x\n", @@ -763,6 +796,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) return err; } +/** + * usb_cache_string - read a string descriptor and cache it for later use + * @udev: the device whose string descriptor is being read + * @index: the descriptor index + * + * Returns a pointer to a kmalloc'ed buffer containing the descriptor string, + * or NULL if the index is 0 or the string could not be read. + */ +char *usb_cache_string(struct usb_device *udev, int index) +{ + char *buf; + char *smallbuf = NULL; + int len; + + if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) { + if ((len = usb_string(udev, index, buf, 256)) > 0) { + if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL) + return buf; + memcpy(smallbuf, buf, len); + } + kfree(buf); + } + return smallbuf; +} + /* * usb_get_device_descriptor - (re)reads the device descriptor (usbcore) * @dev: the device whose device descriptor is being updated @@ -770,10 +828,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, - * which dedicates space for this purpose. Note that several fields are - * converted to the host CPU's byte order: the USB version (bcdUSB), and - * vendors product and version fields (idVendor, idProduct, and bcdDevice). - * That lets device drivers compare against non-byteswapped constants. + * which dedicates space for this purpose. * * Not exported, only for use by the core. If drivers really want to read * the device descriptor directly, they can call usb_get_descriptor() with @@ -834,7 +889,7 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data) ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status, - sizeof(*status), HZ * USB_CTRL_GET_TIMEOUT); + sizeof(*status), USB_CTRL_GET_TIMEOUT); *(u16 *)data = *status; kfree(status); @@ -879,7 +934,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, USB_ENDPOINT_HALT, endp, NULL, 0, - HZ * USB_CTRL_SET_TIMEOUT); + USB_CTRL_SET_TIMEOUT); /* don't un-halt or force to DATA0 except on success */ if (result < 0) @@ -926,8 +981,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) ep = dev->ep_in[epnum]; dev->ep_in[epnum] = NULL; } - if (ep && dev->bus && dev->bus->op && dev->bus->op->disable) - dev->bus->op->disable(dev, ep); + if (ep && dev->bus) + usb_hcd_endpoint_disable(dev, ep); } /** @@ -977,8 +1032,10 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *interface; - /* remove this interface */ + /* remove this interface if it has been registered */ interface = dev->actconfig->interface[i]; + if (!device_is_registered(&interface->dev)) + continue; dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); usb_remove_sysfs_intf_files(interface); @@ -1033,8 +1090,8 @@ usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) * * Enables all the endpoints for the interface's current altsetting. */ -void usb_enable_interface(struct usb_device *dev, - struct usb_interface *intf) +static void usb_enable_interface(struct usb_device *dev, + struct usb_interface *intf) { struct usb_host_interface *alt = intf->cur_altsetting; int i; @@ -1101,7 +1158,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - alternate, interface, NULL, 0, HZ * 5); + alternate, interface, NULL, 0, 5000); /* 9.4.10 says devices don't need this and are free to STALL the * request if the interface only has one alternate setting. @@ -1121,6 +1178,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) */ /* prevent submissions using previous endpoint settings */ + if (device_is_registered(&iface->dev)) + usb_remove_sysfs_intf_files(iface); usb_disable_interface(dev, iface); iface->cur_altsetting = alt; @@ -1156,6 +1215,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * (Likewise, EP0 never "halts" on well designed devices.) */ usb_enable_interface(dev, iface); + if (device_is_registered(&iface->dev)) + usb_create_sysfs_intf_files(iface); return 0; } @@ -1173,7 +1234,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * * Because this affects multiple interfaces, avoid using this with composite * (multi-interface) devices. Instead, the driver for each interface may - * use usb_set_interface() on the interfaces it claims. Resetting the whole + * use usb_set_interface() on the interfaces it claims. Be careful though; + * some devices don't support the SET_INTERFACE request, and others won't + * reset all the interface state (notably data toggles). Resetting the whole * configuration would affect other drivers' interfaces. * * The caller must own the device lock. @@ -1202,11 +1265,9 @@ int usb_reset_configuration(struct usb_device *dev) retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, config->desc.bConfigurationValue, 0, - NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); - if (retval < 0) { - usb_set_device_state(dev, USB_STATE_ADDRESS); + NULL, 0, USB_CTRL_SET_TIMEOUT); + if (retval < 0) return retval; - } dev->toggle[0] = dev->toggle[1] = 0; @@ -1215,6 +1276,8 @@ int usb_reset_configuration(struct usb_device *dev) struct usb_interface *intf = config->interface[i]; struct usb_host_interface *alt; + if (device_is_registered(&intf->dev)) + usb_remove_sysfs_intf_files(intf); alt = usb_altnum_to_altsetting(intf, 0); /* No altsetting 0? We'll assume the first altsetting. @@ -1227,6 +1290,8 @@ int usb_reset_configuration(struct usb_device *dev) intf->cur_altsetting = alt; usb_enable_interface(dev, intf); + if (device_is_registered(&intf->dev)) + usb_create_sysfs_intf_files(intf); } return 0; } @@ -1270,7 +1335,7 @@ static void release_interface(struct device *dev) * bus rwsem; usb device driver probe() methods cannot use this routine. * * Returns zero on success, or else the status code returned by the - * underlying call that failed. On succesful completion, each interface + * underlying call that failed. On successful completion, each interface * in the original device configuration has been destroyed, and each one * in the new configuration has been probed by all relevant usb device * drivers currently known to the kernel. @@ -1298,9 +1363,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ n = nintf = 0; @@ -1314,7 +1376,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) } for (; n < nintf; ++n) { - new_interfaces[n] = kmalloc( + new_interfaces[n] = kzalloc( sizeof(struct usb_interface), GFP_KERNEL); if (!new_interfaces[n]) { @@ -1327,8 +1389,19 @@ free_interfaces: return ret; } } + + i = dev->bus_mA - cp->desc.bMaxPower * 2; + if (i < 0) + dev_warn(&dev->dev, "new config #%d exceeds power " + "limit by %dmA\n", + configuration, -i); } + /* Wake up the device so we can send it the Set-Config request */ + ret = usb_autoresume_device(dev); + if (ret) + goto free_interfaces; + /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ @@ -1337,84 +1410,149 @@ free_interfaces: if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) - goto free_interfaces; + NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { + + /* All the old state is gone, so what else can we do? + * The device is probably useless now anyway. + */ + cp = NULL; + } dev->actconfig = cp; - if (!cp) + if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); - else { - usb_set_device_state(dev, USB_STATE_CONFIGURED); + usb_autosuspend_device(dev); + goto free_interfaces; + } + usb_set_device_state(dev, USB_STATE_CONFIGURED); - /* Initialize the new interface structures and the - * hc/hcd/usbcore interface/endpoint state. - */ - for (i = 0; i < nintf; ++i) { - struct usb_interface_cache *intfc; - struct usb_interface *intf; - struct usb_host_interface *alt; - - cp->interface[i] = intf = new_interfaces[i]; - memset(intf, 0, sizeof(*intf)); - intfc = cp->intf_cache[i]; - intf->altsetting = intfc->altsetting; - intf->num_altsetting = intfc->num_altsetting; - kref_get(&intfc->ref); - - alt = usb_altnum_to_altsetting(intf, 0); - - /* No altsetting 0? We'll assume the first altsetting. - * We could use a GetInterface call, but if a device is - * so non-compliant that it doesn't have altsetting 0 - * then I wouldn't trust its reply anyway. - */ - if (!alt) - alt = &intf->altsetting[0]; - - intf->cur_altsetting = alt; - usb_enable_interface(dev, intf); - intf->dev.parent = &dev->dev; - intf->dev.driver = NULL; - intf->dev.bus = &usb_bus_type; - intf->dev.dma_mask = dev->dev.dma_mask; - intf->dev.release = release_interface; - device_initialize (&intf->dev); - sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", - dev->bus->busnum, dev->devpath, - configuration, - alt->desc.bInterfaceNumber); - } - kfree(new_interfaces); + /* Initialize the new interface structures and the + * hc/hcd/usbcore interface/endpoint state. + */ + for (i = 0; i < nintf; ++i) { + struct usb_interface_cache *intfc; + struct usb_interface *intf; + struct usb_host_interface *alt; + + cp->interface[i] = intf = new_interfaces[i]; + intfc = cp->intf_cache[i]; + intf->altsetting = intfc->altsetting; + intf->num_altsetting = intfc->num_altsetting; + kref_get(&intfc->ref); - /* Now that all the interfaces are set up, register them - * to trigger binding of drivers to interfaces. probe() - * routines may install different altsettings and may - * claim() any interfaces not yet bound. Many class drivers - * need that: CDC, audio, video, etc. + alt = usb_altnum_to_altsetting(intf, 0); + + /* No altsetting 0? We'll assume the first altsetting. + * We could use a GetInterface call, but if a device is + * so non-compliant that it doesn't have altsetting 0 + * then I wouldn't trust its reply anyway. */ - for (i = 0; i < nintf; ++i) { - struct usb_interface *intf = cp->interface[i]; - struct usb_interface_descriptor *desc; - - desc = &intf->altsetting [0].desc; - dev_dbg (&dev->dev, - "adding %s (config #%d, interface %d)\n", - intf->dev.bus_id, configuration, - desc->bInterfaceNumber); - ret = device_add (&intf->dev); - if (ret != 0) { - dev_err(&dev->dev, - "device_add(%s) --> %d\n", - intf->dev.bus_id, - ret); - continue; - } - usb_create_sysfs_intf_files (intf); + if (!alt) + alt = &intf->altsetting[0]; + + intf->cur_altsetting = alt; + usb_enable_interface(dev, intf); + intf->dev.parent = &dev->dev; + intf->dev.driver = NULL; + intf->dev.bus = &usb_bus_type; + intf->dev.dma_mask = dev->dev.dma_mask; + intf->dev.release = release_interface; + device_initialize (&intf->dev); + mark_quiesced(intf); + sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", + dev->bus->busnum, dev->devpath, + configuration, alt->desc.bInterfaceNumber); + } + kfree(new_interfaces); + + if (cp->string == NULL) + cp->string = usb_cache_string(dev, cp->desc.iConfiguration); + + /* Now that all the interfaces are set up, register them + * to trigger binding of drivers to interfaces. probe() + * routines may install different altsettings and may + * claim() any interfaces not yet bound. Many class drivers + * need that: CDC, audio, video, etc. + */ + for (i = 0; i < nintf; ++i) { + struct usb_interface *intf = cp->interface[i]; + + dev_dbg (&dev->dev, + "adding %s (config #%d, interface %d)\n", + intf->dev.bus_id, configuration, + intf->cur_altsetting->desc.bInterfaceNumber); + ret = device_add (&intf->dev); + if (ret != 0) { + dev_err(&dev->dev, "device_add(%s) --> %d\n", + intf->dev.bus_id, ret); + continue; } + usb_create_sysfs_intf_files (intf); } - return ret; + usb_autosuspend_device(dev); + return 0; +} + +struct set_config_request { + struct usb_device *udev; + int config; + struct work_struct work; +}; + +/* Worker routine for usb_driver_set_configuration() */ +static void driver_set_config_work(struct work_struct *work) +{ + struct set_config_request *req = + container_of(work, struct set_config_request, work); + + usb_lock_device(req->udev); + usb_set_configuration(req->udev, req->config); + usb_unlock_device(req->udev); + usb_put_dev(req->udev); + kfree(req); +} + +/** + * usb_driver_set_configuration - Provide a way for drivers to change device configurations + * @udev: the device whose configuration is being updated + * @config: the configuration being chosen. + * Context: In process context, must be able to sleep + * + * Device interface drivers are not allowed to change device configurations. + * This is because changing configurations will destroy the interface the + * driver is bound to and create new ones; it would be like a floppy-disk + * driver telling the computer to replace the floppy-disk drive with a + * tape drive! + * + * Still, in certain specialized circumstances the need may arise. This + * routine gets around the normal restrictions by using a work thread to + * submit the change-config request. + * + * Returns 0 if the request was succesfully queued, error code otherwise. + * The caller has no way to know whether the queued request will eventually + * succeed. + */ +int usb_driver_set_configuration(struct usb_device *udev, int config) +{ + struct set_config_request *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + req->udev = udev; + req->config = config; + INIT_WORK(&req->work, driver_set_config_work); + + usb_get_dev(udev); + if (!schedule_work(&req->work)) { + usb_put_dev(udev); + kfree(req); + return -EINVAL; + } + return 0; } +EXPORT_SYMBOL_GPL(usb_driver_set_configuration); // synchronous request completion model EXPORT_SYMBOL(usb_control_msg); @@ -1427,7 +1565,6 @@ EXPORT_SYMBOL(usb_sg_wait); // synchronous control message convenience routines EXPORT_SYMBOL(usb_get_descriptor); EXPORT_SYMBOL(usb_get_status); -EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_string); // synchronous calls that also maintain usbcore state