* message.c - synchronous message handling
*/
-#include <linux/config.h>
-
-#ifdef CONFIG_USB_DEBUG
- #define DEBUG
-#else
- #undef DEBUG
-#endif
-
#include <linux/pci.h> /* for scatterlist macros */
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
#include <asm/byteorder.h>
+#include <asm/scatterlist.h>
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
{
struct urb *urb = (struct urb *) data;
- dev_warn(&urb->dev->dev, "%s timeout on ep%d%s\n",
- usb_pipecontrol(urb->pipe) ? "control" : "bulk",
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out");
usb_unlink_urb(urb);
}
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.expires = jiffies + msecs_to_jiffies(timeout);
timer.data = (unsigned long)urb;
timer.function = timeout_kill;
/* grr. timeout _should_ include submit delays. */
wait_for_completion(&done);
status = urb->status;
/* note: HCDs return ETIMEDOUT for other reasons too */
- if (status == -ECONNRESET)
- status = -ETIMEDOUT;
+ if (status == -ECONNRESET) {
+ 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
+ );
+ if (urb->actual_length > 0)
+ status = 0;
+ else
+ status = -ETIMEDOUT;
+ }
if (timeout > 0)
del_timer_sync(&timer);
}
/*-------------------------------------------------------------------*/
// 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;
if (!urb)
return -ENOMEM;
- usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
- usb_api_blocking_completion, 0);
+ usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
+ len, usb_api_blocking_completion, NULL);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
* @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 ()
*
}
+/**
+ * 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
* @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 ()
*
* 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, 0);
-
- 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);
}
/*-------------------------------------------------------------------*/
while (io->entries--)
usb_free_urb (io->urbs [io->entries]);
kfree (io->urbs);
- io->urbs = 0;
+ io->urbs = NULL;
}
- if (io->dev->dev.dma_mask != 0)
+ if (io->dev->dev.dma_mask != NULL)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
- io->dev = 0;
+ io->dev = NULL;
}
static void sg_complete (struct urb *urb, struct pt_regs *regs)
// BUG ();
}
- if (urb->status && urb->status != -ECONNRESET) {
+ if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
int i, found, status;
io->status = urb->status;
/* the previous urbs, and this one, completed already.
* unlink pending urbs so they won't rx/tx bad data.
+ * careful: unlink can sometimes be synchronous...
*/
+ spin_unlock (&io->lock);
for (i = 0, found = 0; i < io->entries; i++) {
- if (!io->urbs [i])
+ if (!io->urbs [i] || !io->urbs [i]->dev)
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);
} else if (urb == io->urbs [i])
found = 1;
}
+ spin_lock (&io->lock);
}
- urb->dev = 0;
+ urb->dev = NULL;
/* on the last completion, signal usb_sg_wait() */
io->bytes += urb->actual_length;
struct scatterlist *sg,
int nents,
size_t length,
- int mem_flags
+ gfp_t mem_flags
)
{
int i;
/* not all host controllers use DMA (like the mainstream pci ones);
* they can use PIO (sl811) or be software over another transport.
*/
- dma = (dev->dev.dma_mask != 0);
+ dma = (dev->dev.dma_mask != NULL);
if (dma)
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
else
if (io->entries <= 0)
return io->entries;
- io->count = 0;
+ io->count = io->entries;
io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
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;
- for (i = 0; i < io->entries; i++, io->count = i) {
+ for (i = 0; i < io->entries; i++) {
unsigned len;
io->urbs [i] = usb_alloc_urb (0, mem_flags);
goto nomem;
}
- io->urbs [i]->dev = 0;
+ io->urbs [i]->dev = NULL;
io->urbs [i]->pipe = pipe;
io->urbs [i]->interval = period;
io->urbs [i]->transfer_flags = urb_flags;
* (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
case -ENXIO: // hc didn't queue this one
case -EAGAIN:
case -ENOMEM:
- io->urbs [i]->dev = 0;
+ io->urbs[i]->dev = NULL;
retval = 0;
i--;
yield ();
/* fail any uncompleted urbs */
default:
- spin_lock_irq (&io->lock);
- io->count -= entries - i;
- if (io->status == -EINPROGRESS)
- io->status = retval;
- if (io->count == 0)
- complete (&io->complete);
- spin_unlock_irq (&io->lock);
-
- io->urbs [i]->dev = 0;
+ io->urbs [i]->dev = NULL;
io->urbs [i]->status = retval;
dev_dbg (&io->dev->dev, "%s, submit --> %d\n",
__FUNCTION__, retval);
usb_sg_cancel (io);
}
spin_lock_irq (&io->lock);
- if (retval && io->status == -ECONNRESET)
+ if (retval && (io->status == 0 || io->status == -ECONNRESET))
io->status = retval;
}
+ io->count -= entries - i;
+ if (io->count == 0)
+ complete (&io->complete);
spin_unlock_irq (&io->lock);
/* OK, yes, this could be packaged as non-blocking.
int i;
io->status = -ECONNRESET;
+ spin_unlock (&io->lock);
for (i = 0; i < io->entries; i++) {
int retval;
dev_warn (&io->dev->dev, "%s, unlink --> %d\n",
__FUNCTION__, retval);
}
+ spin_lock (&io->lock);
}
spin_unlock_irqrestore (&io->lock, flags);
}
*
* Gets a USB descriptor. Convenience functions exist to simplify
* getting some types of descriptors. Use
- * usb_get_device_descriptor() for USB_DT_DEVICE (not exported),
- * and usb_get_string() or usb_string() for USB_DT_STRING.
+ * usb_get_string() or usb_string() for USB_DT_STRING.
* Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG)
* are part of the device structure.
* In addition to a number of USB-standard descriptors, some
*/
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{
- int i = 5;
+ int i;
int result;
memset(buf,0,size); // Make sure we parse really received data
- while (i--) {
+ for (i = 0; i < 3; ++i) {
/* retry on length 0 or stall; some devices are flakey */
- if ((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)) > 0
- || result != -EPIPE)
- break;
-
- dev_dbg (&dev->dev, "RETRY descriptor, result %d\n", result);
- result = -ENOMSG;
+ 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)
+ continue;
+ if (result > 1 && ((u8 *)buf)[1] != type) {
+ result = -EPROTO;
+ continue;
+ }
+ break;
}
return result;
}
* 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;
+
+ for (i = 0; i < 3; ++i) {
+ /* retry on length 0 or stall; some devices are flakey */
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+ (USB_DT_STRING << 8) + index, langid, buf, size,
+ USB_CTRL_GET_TIMEOUT);
+ if (!(result == 0 || result == -EPIPE))
+ break;
+ }
+ return result;
+}
+
+static void usb_try_string_workarounds(unsigned char *buf, int *length)
+{
+ int newlength, oldlength = *length;
+
+ for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
+ if (!isprint(buf[newlength]) || buf[newlength + 1])
+ break;
+
+ if (newlength > 2) {
+ buf[0] = newlength;
+ *length = newlength;
+ }
+}
+
+static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+ unsigned int index, unsigned char *buf)
+{
+ int rc;
+
+ /* Try to read the string descriptor by asking for the maximum
+ * possible number of bytes */
+ rc = usb_get_string(dev, langid, index, buf, 255);
+
+ /* If that failed try to read the descriptor length, then
+ * ask for just that many bytes */
+ if (rc < 2) {
+ rc = usb_get_string(dev, langid, index, buf, 2);
+ if (rc == 2)
+ rc = usb_get_string(dev, langid, index, buf, buf[0]);
+ }
+
+ if (rc >= 2) {
+ if (!buf[0] && !buf[1])
+ usb_try_string_workarounds(buf, &rc);
+
+ /* There might be extra junk at the end of the descriptor */
+ if (buf[0] < rc)
+ rc = buf[0];
+
+ rc = rc - (rc & 1); /* force a multiple of two */
+ }
+
+ if (rc < 2)
+ rc = (rc < 0 ? rc : -EINVAL);
+
+ return rc;
+}
+
+/**
+ * usb_string - returns ISO 8859-1 version of a string descriptor
+ * @dev: the device whose string descriptor is being retrieved
+ * @index: the number of the descriptor
+ * @buf: where to put the string
+ * @size: how big is "buf"?
+ * Context: !in_interrupt ()
+ *
+ * This converts the UTF-16LE encoded strings returned by devices, from
+ * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
+ * that are more usable in most kernel contexts. Note that all characters
+ * in the chosen descriptor that can't be encoded using ISO-8859-1
+ * are converted to the question mark ("?") character, and this function
+ * chooses strings in the first language supported by the device.
+ *
+ * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
+ * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
+ * and is appropriate for use many uses of English and several other
+ * Western European languages. (But it doesn't include the "Euro" symbol.)
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Returns length of the string (>= 0) or usb_control_msg status (< 0).
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
- return 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);
+ unsigned char *tbuf;
+ int err;
+ unsigned int u, idx;
+
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+ if (size <= 0 || !buf || !index)
+ return -EINVAL;
+ buf[0] = 0;
+ tbuf = kmalloc(256, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+
+ /* get langid for strings if it's not yet known */
+ if (!dev->have_langid) {
+ err = usb_string_sub(dev, 0, 0, tbuf);
+ if (err < 0) {
+ dev_err (&dev->dev,
+ "string descriptor 0 read error: %d\n",
+ err);
+ goto errout;
+ } else if (err < 4) {
+ dev_err (&dev->dev, "string descriptor 0 too short\n");
+ err = -EINVAL;
+ goto errout;
+ } else {
+ 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",
+ dev->string_langid);
+ }
+ }
+
+ err = usb_string_sub(dev, dev->string_langid, index, tbuf);
+ if (err < 0)
+ goto errout;
+
+ size--; /* leave room for trailing NULL char in output buffer */
+ for (idx = 0, u = 2; u < err; u += 2) {
+ if (idx >= size)
+ break;
+ if (tbuf[u+1]) /* high byte */
+ buf[idx++] = '?'; /* non ISO-8859-1 character */
+ else
+ buf[idx++] = tbuf[u];
+ }
+ buf[idx] = 0;
+ err = idx;
+
+ if (tbuf[1] != USB_DT_STRING)
+ dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf);
+
+ errout:
+ kfree(tbuf);
+ return err;
}
/**
- * usb_get_device_descriptor - (re)reads the device descriptor
+ * 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
* @size: how much of the descriptor to read
* Context: !in_interrupt ()
return -ENOMEM;
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
- if (ret >= 0) {
- le16_to_cpus(&desc->bcdUSB);
- le16_to_cpus(&desc->idVendor);
- le16_to_cpus(&desc->idProduct);
- le16_to_cpus(&desc->bcdDevice);
+ if (ret >= 0)
memcpy(&dev->descriptor, desc, size);
- }
kfree(desc);
return ret;
}
*/
int usb_get_status(struct usb_device *dev, int type, int target, void *data)
{
- return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2,
- HZ * USB_CTRL_GET_TIMEOUT);
+ int ret;
+ u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+
+ if (!status)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
+ sizeof(*status), USB_CTRL_GET_TIMEOUT);
+
+ *(u16 *)data = *status;
+ kfree(status);
+ return ret;
}
/**
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)
* the copy in usb-storage, for as long as we need two copies.
*/
- /* toggle was reset by the clear, then ep was reactivated */
+ /* toggle was reset by the clear */
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
- usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
return 0;
}
* Deallocates hcd/hardware state for this endpoint ... and nukes all
* pending urbs.
*
- * If the HCD hasn't registered a disable() function, this marks the
- * endpoint as halted and sets its maxpacket size to 0 to prevent
- * further submissions.
+ * If the HCD hasn't registered a disable() function, this sets the
+ * endpoint's maxpacket size to 0 to prevent further submissions.
*/
void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
{
- if (dev && dev->bus && dev->bus->op && dev->bus->op->disable)
- dev->bus->op->disable(dev, epaddr);
- else {
- unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-
- if (usb_endpoint_out(epaddr)) {
- usb_endpoint_halt(dev, epnum, 1);
- dev->epmaxpacketout[epnum] = 0;
- } else {
- usb_endpoint_halt(dev, epnum, 0);
- dev->epmaxpacketin[epnum] = 0;
- }
+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
+ struct usb_host_endpoint *ep;
+
+ if (!dev)
+ return;
+
+ if (usb_endpoint_out(epaddr)) {
+ ep = dev->ep_out[epnum];
+ dev->ep_out[epnum] = NULL;
+ } else {
+ 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);
}
/**
}
}
-static void release_interface(struct device *dev)
-{
-}
-
/*
* usb_disable_device - Disable all the endpoints for a USB device
* @dev: the device whose endpoints are being disabled
usb_disable_endpoint(dev, i + USB_DIR_IN);
}
dev->toggle[0] = dev->toggle[1] = 0;
- dev->halted[0] = dev->halted[1] = 0;
/* getting rid of interfaces will disconnect
* any drivers bound to them (a key side effect)
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);
- device_unregister (&interface->dev);
+ usb_remove_sysfs_intf_files(interface);
+ device_del (&interface->dev);
+ }
+
+ /* Now that the interfaces are unbound, nobody should
+ * try to access them.
+ */
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ put_device (&dev->actconfig->interface[i]->dev);
+ dev->actconfig->interface[i] = NULL;
}
- dev->actconfig = 0;
+ dev->actconfig = NULL;
if (dev->state == USB_STATE_CONFIGURED)
- dev->state = USB_STATE_ADDRESS;
+ usb_set_device_state(dev, USB_STATE_ADDRESS);
}
}
/*
* usb_enable_endpoint - Enable an endpoint for USB communications
* @dev: the device whose interface is being enabled
- * @epd: pointer to the endpoint descriptor
+ * @ep: the endpoint
*
- * Marks the endpoint as running, resets its toggle, and stores
- * its maxpacket value. For control endpoints, both the input
- * and output sides are handled.
+ * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
+ * For control endpoints, both the input and output sides are handled.
*/
-void usb_enable_endpoint(struct usb_device *dev,
- struct usb_endpoint_descriptor *epd)
+static void
+usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
- int maxsize = epd->wMaxPacketSize;
- unsigned int epaddr = epd->bEndpointAddress;
+ unsigned int epaddr = ep->desc.bEndpointAddress;
unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
- int is_control = ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
- USB_ENDPOINT_XFER_CONTROL);
+ int is_control;
+ is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_CONTROL);
if (usb_endpoint_out(epaddr) || is_control) {
- usb_endpoint_running(dev, epnum, 1);
usb_settoggle(dev, epnum, 1, 0);
- dev->epmaxpacketout[epnum] = maxsize;
+ dev->ep_out[epnum] = ep;
}
if (!usb_endpoint_out(epaddr) || is_control) {
- usb_endpoint_running(dev, epnum, 0);
usb_settoggle(dev, epnum, 0, 0);
- dev->epmaxpacketin[epnum] = maxsize;
+ dev->ep_in[epnum] = 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;
for (i = 0; i < alt->desc.bNumEndpoints; ++i)
- usb_enable_endpoint(dev, &alt->endpoint[i].desc);
+ usb_enable_endpoint(dev, &alt->endpoint[i]);
}
/**
int ret;
int manual = 0;
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+
iface = usb_ifnum_to_if(dev, interface);
if (!iface) {
dev_dbg(&dev->dev, "selecting invalid interface %d\n",
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.
*/
/* 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;
* (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;
}
*
* 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.
+ *
* Returns zero on success, else a negative error code.
*/
int usb_reset_configuration(struct usb_device *dev)
int i, retval;
struct usb_host_config *config;
- /* caller must own dev->serialize (config won't change)
- * and the usb bus readlock (so driver bindings are stable);
- * so calls during probe() are fine
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
+
+ /* caller must have locked the device and must own
+ * the usb bus readlock (so driver bindings are stable);
+ * calls during probe() are fine
*/
for (i = 1; i < 16; ++i) {
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) {
- dev->state = USB_STATE_ADDRESS;
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (retval < 0)
return retval;
- }
dev->toggle[0] = dev->toggle[1] = 0;
- dev->halted[0] = dev->halted[1] = 0;
/* re-init hc/hcd interface/endpoint state */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
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.
intf->cur_altsetting = alt;
usb_enable_interface(dev, intf);
+ if (device_is_registered(&intf->dev))
+ usb_create_sysfs_intf_files(intf);
}
return 0;
}
+static void release_interface(struct device *dev)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_interface_cache *intfc =
+ altsetting_to_usb_interface_cache(intf->altsetting);
+
+ kref_put(&intfc->ref, usb_release_interface_cache);
+ kfree(intf);
+}
+
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
* @configuration: the configuration being chosen.
- * Context: !in_interrupt(), caller holds dev->serialize
+ * Context: !in_interrupt(), caller owns the device lock
*
* This is used to enable non-default device modes. Not all devices
* use this kind of configurability; many devices only have one
* usb_set_interface().
*
* This call is synchronous. The calling context must be able to sleep,
- * and must not hold the driver model lock for USB; usb device driver
- * probe() methods may not use this routine.
+ * must own the device lock, and must not hold the driver model's USB
+ * 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.
{
int i, ret;
struct usb_host_config *cp = NULL;
-
- /* dev->serialize guards all config changes */
+ struct usb_interface **new_interfaces = NULL;
+ int n, nintf;
- for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue == configuration) {
cp = &dev->config[i];
break;
}
}
- if ((!cp && configuration != 0)) {
- ret = -EINVAL;
- goto out;
- }
+ if ((!cp && configuration != 0))
+ return -EINVAL;
/* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0,
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;
+ if (cp) {
+ nintf = cp->desc.bNumInterfaces;
+ new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
+ GFP_KERNEL);
+ if (!new_interfaces) {
+ dev_err(&dev->dev, "Out of memory");
+ return -ENOMEM;
+ }
+
+ for (; n < nintf; ++n) {
+ new_interfaces[n] = kzalloc(
+ sizeof(struct usb_interface),
+ GFP_KERNEL);
+ if (!new_interfaces[n]) {
+ dev_err(&dev->dev, "Out of memory");
+ ret = -ENOMEM;
+free_interfaces:
+ while (--n >= 0)
+ kfree(new_interfaces[n]);
+ kfree(new_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);
+ }
+
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
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 out;
+ NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
- dev->actconfig = cp;
- if (!cp)
- dev->state = USB_STATE_ADDRESS;
- else {
- dev->state = USB_STATE_CONFIGURED;
-
- /* re-initialize hc/hcd/usbcore interface/endpoint state.
- * this triggers binding of drivers to interfaces; and
- * maybe probe() calls will choose different altsettings.
+ /* All the old state is gone, so what else can we do?
+ * The device is probably useless now anyway.
*/
- for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
- struct usb_interface *intf = cp->interface[i];
- struct usb_host_interface *alt;
-
- 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);
- }
-
- /* Now that all interfaces are setup, probe() calls
- * may claim() any interface that's not yet bound.
- * Many class drivers need that: CDC, audio, video, etc.
- */
- for (i = 0; i < cp->desc.bNumInterfaces; ++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_driverfs_intf_files (intf);
- }
+ cp = NULL;
}
-out:
- return ret;
-}
+ dev->actconfig = cp;
+ if (!cp) {
+ usb_set_device_state(dev, USB_STATE_ADDRESS);
+ goto free_interfaces;
+ }
+ usb_set_device_state(dev, USB_STATE_CONFIGURED);
-/**
- * usb_string - returns ISO 8859-1 version of a string descriptor
- * @dev: the device whose string descriptor is being retrieved
- * @index: the number of the descriptor
- * @buf: where to put the string
- * @size: how big is "buf"?
- * Context: !in_interrupt ()
- *
- * This converts the UTF-16LE encoded strings returned by devices, from
- * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
- * that are more usable in most kernel contexts. Note that all characters
- * in the chosen descriptor that can't be encoded using ISO-8859-1
- * are converted to the question mark ("?") character, and this function
- * chooses strings in the first language supported by the device.
- *
- * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
- * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
- * and is appropriate for use many uses of English and several other
- * Western European languages. (But it doesn't include the "Euro" symbol.)
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Returns length of the string (>= 0) or usb_control_msg status (< 0).
- */
-int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
-{
- unsigned char *tbuf;
- int err, len;
- unsigned int u, idx;
+ /* 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;
- if (size <= 0 || !buf || !index)
- return -EINVAL;
- buf[0] = 0;
- tbuf = kmalloc(256, GFP_KERNEL);
- if (!tbuf)
- return -ENOMEM;
+ 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);
- /* get langid for strings if it's not yet known */
- if (!dev->have_langid) {
- err = usb_get_descriptor(dev, USB_DT_STRING, 0, tbuf, 4);
- if (err < 0) {
- dev_err (&dev->dev,
- "string descriptor 0 read error: %d\n",
- err);
- goto errout;
- } else if (err < 4 || tbuf[0] < 4) {
- dev_err (&dev->dev, "string descriptor 0 too short\n");
- err = -EINVAL;
- goto errout;
- } else {
- 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",
- dev->string_langid);
- }
- }
+ alt = usb_altnum_to_altsetting(intf, 0);
- /*
- * ask for the length of the string
- */
+ /* 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];
- err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);
- if (err == -EPIPE) {
- dev_dbg(&dev->dev, "RETRY string %d read/%d\n", index, 2);
- err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);
- }
- if(err<2)
- goto errout;
- len=tbuf[0];
-
- err = usb_get_string(dev, dev->string_langid, index, tbuf, len);
- if (err == -EPIPE) {
- dev_dbg(&dev->dev, "RETRY string %d read/%d\n", index, len);
- err = usb_get_string(dev, dev->string_langid, index, tbuf, len);
+ 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);
}
- if (err < 0)
- goto errout;
+ kfree(new_interfaces);
- size--; /* leave room for trailing NULL char in output buffer */
- for (idx = 0, u = 2; u < err; u += 2) {
- if (idx >= size)
- break;
- if (tbuf[u+1]) /* high byte */
- buf[idx++] = '?'; /* non ISO-8859-1 character */
- else
- buf[idx++] = tbuf[u];
+ 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);
}
- buf[idx] = 0;
- err = idx;
- errout:
- kfree(tbuf);
- return err;
+ return 0;
}
// synchronous request completion model
// 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