*/
#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/ctype.h>
#include <linux/device.h>
#include <asm/byteorder.h>
+#include <asm/scatterlist.h>
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
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. */
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",
+ 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");
- status = -ETIMEDOUT;
+ 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;
* @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 ()
*
* @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, 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);
}
/*-------------------------------------------------------------------*/
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);
struct scatterlist *sg,
int nents,
size_t length,
- int mem_flags
+ gfp_t mem_flags
)
{
int i;
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;
* (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
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) {
* 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;
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;
}
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
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);
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)
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);
*
* 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;
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.
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;
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;
}
* 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.
}
for (; n < nintf; ++n) {
- new_interfaces[n] = kmalloc(
+ new_interfaces[n] = kzalloc(
sizeof(struct usb_interface),
GFP_KERNEL);
if (!new_interfaces[n]) {
if (dev->state != USB_STATE_ADDRESS)
usb_disable_device (dev, 1); // Skip ep0
+ if (cp) {
+ 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 ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
+ NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0)
goto free_interfaces;
dev->actconfig = cp;
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;
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,
}
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
*/
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);
+ intf->cur_altsetting->desc.bInterfaceNumber);
ret = device_add (&intf->dev);
if (ret != 0) {
dev_err(&dev->dev,
}
}
- return ret;
+ 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