Commit 1a2f7297 authored by Patrick Mochel's avatar Patrick Mochel

USB: Move synchronous message passing code from usb.c to message.c

parent 76c05fd6
......@@ -2,9 +2,9 @@
# Makefile for USB Core files and filesystem
#
export-objs := usb.o hcd.o urb.o
export-objs := usb.o hcd.o urb.o message.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o
ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += devio.o inode.o drivers.o devices.o
......
/*
* message.c - synchronous message handling
*/
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/byteorder.h>
struct usb_api_data {
wait_queue_head_t wqh;
int done;
};
static void usb_api_blocking_completion(struct urb *urb)
{
struct usb_api_data *awd = (struct usb_api_data *)urb->context;
awd->done = 1;
wmb();
wake_up(&awd->wqh);
}
// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
DECLARE_WAITQUEUE(wait, current);
struct usb_api_data awd;
int status;
init_waitqueue_head(&awd.wqh);
awd.done = 0;
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait);
urb->context = &awd;
status = usb_submit_urb(urb, GFP_KERNEL);
if (status) {
// something went wrong
usb_free_urb(urb);
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
return status;
}
while (timeout && !awd.done)
{
timeout = schedule_timeout(timeout);
set_current_state(TASK_UNINTERRUPTIBLE);
rmb();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
if (!timeout && !awd.done) {
if (urb->status != -EINPROGRESS) { /* No callback?!! */
printk(KERN_ERR "usb: raced timeout, "
"pipe 0x%x status %d time left %d\n",
urb->pipe, urb->status, timeout);
status = urb->status;
} else {
printk("usb_control/bulk_msg: timeout\n");
usb_unlink_urb(urb); // remove urb safely
status = -ETIMEDOUT;
}
} else
status = urb->status;
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)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
usb_api_blocking_completion, 0);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
/**
* usb_control_msg - Builds a control urb, sends it off and waits for completion
* @dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @request: USB message request value
* @requesttype: USB message request type value
* @value: USB message value
* @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
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
* This function sends a simple control message to a specified endpoint
* and waits for the message to complete, or timeout.
*
* If successful, it returns the number of bytes transferred, otherwise a negative error number.
*
* 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()
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
int ret;
if (!dr)
return -ENOMEM;
dr->bRequestType= requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
dr->wIndex = cpu_to_le16p(&index);
dr->wLength = cpu_to_le16p(&size);
//dbg("usb_control_msg");
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
/**
* 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
* @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 jiffies to wait for the message to complete before
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
* This function sends a simple bulk 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()
*/
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
if (len < 0)
return -EINVAL;
urb=usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
FILL_BULK_URB(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, 0);
return usb_start_wait_urb(urb,timeout,actual_length);
}
/**
* usb_get_descriptor - issues a generic GET_DESCRIPTOR request
* @dev: the device whose descriptor is being retrieved
* @type: the descriptor type (USB_DT_*)
* @index: the number of the descriptor
* @buf: where to put the descriptor
* @size: how big is "buf"?
* Context: !in_interrupt ()
*
* Gets a USB descriptor. Convenience functions exist to simplify
* getting some types of descriptors. Use
* usb_get_device_descriptor() for USB_DT_DEVICE,
* and usb_get_string() or usb_string() for USB_DT_STRING.
* Configuration descriptors (USB_DT_CONFIG) are part of the device
* structure, at least for the current configuration.
* In addition to a number of USB-standard descriptors, some
* devices also use class-specific or vendor-specific descriptors.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{
int i = 5;
int result;
memset(buf,0,size); // Make sure we parse really received data
while (i--) {
/* retries if the returned length was 0; flakey device */
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;
}
return result;
}
/**
* usb_get_string - gets a string descriptor
* @dev: the device whose string descriptor is being retrieved
* @langid: code for language chosen (from string descriptor zero)
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
* Context: !in_interrupt ()
*
* Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
* in little-endian byte order).
* The usb_string() function will often be a convenient way to turn
* these strings into kernel-printable form.
*
* Strings may be referenced in device, configuration, interface, or other
* descriptors, and could also be used in vendor-specific ways.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* 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)
{
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);
}
/**
* usb_get_device_descriptor - (re)reads the device descriptor
* @dev: the device whose device descriptor is being updated
* 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.
*
* There's normally no need to use this call, although some devices
* will change their descriptors after events like updating firmware.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
int usb_get_device_descriptor(struct usb_device *dev)
{
int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
sizeof(dev->descriptor));
if (ret >= 0) {
le16_to_cpus(&dev->descriptor.bcdUSB);
le16_to_cpus(&dev->descriptor.idVendor);
le16_to_cpus(&dev->descriptor.idProduct);
le16_to_cpus(&dev->descriptor.bcdDevice);
}
return ret;
}
/**
* usb_get_status - issues a GET_STATUS call
* @dev: the device whose status is being checked
* @type: USB_RECIP_*; for device, interface, or endpoint
* @target: zero (for device), else interface or endpoint number
* @data: pointer to two bytes of bitmap data
* Context: !in_interrupt ()
*
* Returns device, interface, or endpoint status. Normally only of
* interest to see if the device is self powered, or has enabled the
* remote wakeup facility; or whether a bulk or interrupt endpoint
* is halted ("stalled").
*
* Bits in these status bitmaps are set using the SET_FEATURE request,
* and cleared using the CLEAR_FEATURE request. The usb_clear_halt()
* function should be used to clear halt ("stall") status.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
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);
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally, for config/altsetting reconfig.
void usb_set_maxpacket(struct usb_device *dev)
{
int i, b;
for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *ifp = dev->actconfig->interface + i;
struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
struct usb_endpoint_descriptor *ep = as->endpoint;
int e;
for (e=0; e<as->bNumEndpoints; e++) {
b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
}
else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
}
else {
if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
}
}
}
}
/**
* usb_clear_halt - tells device to clear endpoint halt/stall condition
* @dev: device whose endpoint is halted
* @pipe: endpoint "pipe" being cleared
* Context: !in_interrupt ()
*
* This is used to clear halt conditions for bulk and interrupt endpoints,
* as reported by URB completion status. Endpoints that are halted are
* sometimes referred to as being "stalled". Such endpoints are unable
* to transmit or receive data until the halt status is cleared. Any URBs
* queued queued for such an endpoint should normally be unlinked before
* clearing the halt condition.
*
* Note that control and isochronous endpoints don't halt, although control
* endpoints report "protocol stall" (for unsupported requests) using the
* same status code used to report a true stall.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_clear_halt(struct usb_device *dev, int pipe)
{
int result;
__u16 status;
unsigned char *buffer;
int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
/*
if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp)))
return 0;
*/
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0,
HZ * USB_CTRL_SET_TIMEOUT);
/* don't clear if failed */
if (result < 0)
return result;
buffer = kmalloc(sizeof(status), GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return -ENOMEM;
}
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
// FIXME USB_CTRL_GET_TIMEOUT, yes? why not usb_get_status() ?
buffer, sizeof(status), HZ * USB_CTRL_SET_TIMEOUT);
memcpy(&status, buffer, sizeof(status));
kfree(buffer);
if (result < 0)
return result;
if (le16_to_cpu(status) & 1)
return -EPIPE; /* still halted */
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
/* toggle is reset on clear */
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
return 0;
}
/**
* usb_set_interface - Makes a particular alternate setting be current
* @dev: the device whose interface is being updated
* @interface: the interface being updated
* @alternate: the setting being chosen.
* Context: !in_interrupt ()
*
* This is used to enable data transfers on interfaces that may not
* be enabled by default. Not all devices support such configurability.
*
* Within any given configuration, each interface may have several
* alternative settings. These are often used to control levels of
* bandwidth consumption. For example, the default setting for a high
* speed interrupt endpoint may not send more than about 4KBytes per
* microframe, and isochronous endpoints may never be part of a an
* interface's default setting. To access such bandwidth, alternate
* interface setting must be made current.
*
* Note that in the Linux USB subsystem, bandwidth associated with
* an endpoint in a given alternate setting is not reserved until an
* is submitted that needs that bandwidth. Some other operating systems
* allocate bandwidth early, when a configuration is chosen.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
struct usb_interface *iface;
struct usb_interface_descriptor *iface_as;
int i, ret;
iface = usb_ifnum_to_if(dev, interface);
if (!iface) {
warn("selecting invalid interface %d", interface);
return -EINVAL;
}
/* 9.4.10 says devices don't need this, if the interface
only has one alternate setting */
if (iface->num_altsetting == 1) {
dbg("ignoring set_interface for dev %d, iface %d, alt %d",
dev->devnum, interface, alternate);
return 0;
}
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
interface, NULL, 0, HZ * 5)) < 0)
return ret;
iface->act_altsetting = alternate;
/* 9.1.1.5: reset toggles for all endpoints affected by this iface-as
*
* Note:
* Despite EP0 is always present in all interfaces/AS, the list of
* endpoints from the descriptor does not contain EP0. Due to its
* omnipresence one might expect EP0 being considered "affected" by
* any SetInterface request and hence assume toggles need to be reset.
* However, EP0 toggles are re-synced for every individual transfer
* during the SETUP stage - hence EP0 toggles are "don't care" here.
*/
iface_as = &iface->altsetting[alternate];
for (i = 0; i < iface_as->bNumEndpoints; i++) {
u8 ep = iface_as->endpoint[i].bEndpointAddress;
usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0);
}
/* usb_set_maxpacket() sets the maxpacket size for all EP in all
* interfaces but it shouldn't do any harm here: we have changed
* the AS for the requested interface only, hence for unaffected
* interfaces it's just re-application of still-valid values.
*/
usb_set_maxpacket(dev);
return 0;
}
/**
* 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 ()
*
* This is used to enable non-default device modes. Not all devices
* support this kind of configurability. By default, configuration
* zero is selected after enumeration; many devices only have a single
* configuration.
*
* USB devices may support one or more configurations, which affect
* power consumption and the functionality available. For example,
* the default configuration is limited to using 100mA of bus power,
* so that when certain device functionality requires more power,
* and the device is bus powered, that functionality will be in some
* non-default device configuration. Other device modes may also be
* reflected as configuration options, such as whether two ISDN
* channels are presented as independent 64Kb/s interfaces or as one
* bonded 128Kb/s interface.
*
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_config_descriptor *cp = NULL;
for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].bConfigurationValue == configuration) {
cp = &dev->config[i];
break;
}
}
if (!cp) {
warn("selecting invalid configuration %d", configuration);
return -EINVAL;
}
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)
return ret;
dev->actconfig = cp;
dev->toggle[0] = 0;
dev->toggle[1] = 0;
usb_set_maxpacket(dev);
return 0;
}
/**
* 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;
unsigned int u, idx;
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_get_string(dev, 0, 0, tbuf, 4);
if (err < 0) {
err("error getting string descriptor 0 (error=%d)", err);
goto errout;
} else if (tbuf[0] < 4) {
err("string descriptor 0 too short");
err = -EINVAL;
goto errout;
} else {
dev->have_langid = -1;
dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
/* always use the first langid listed */
dbg("USB device number %d default language ID 0x%x",
dev->devnum, dev->string_langid);
}
}
/*
* Just ask for a maximum length string and then take the length
* that was returned.
*/
err = usb_get_string(dev, dev->string_langid, index, tbuf, 255);
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;
errout:
kfree(tbuf);
return err;
}
// synchronous request completion model
EXPORT_SYMBOL(usb_control_msg);
EXPORT_SYMBOL(usb_bulk_msg);
// synchronous control message convenience routines
EXPORT_SYMBOL(usb_get_descriptor);
EXPORT_SYMBOL(usb_get_device_descriptor);
EXPORT_SYMBOL(usb_get_status);
EXPORT_SYMBOL(usb_get_string);
EXPORT_SYMBOL(usb_string);
EXPORT_SYMBOL(usb_clear_halt);
EXPORT_SYMBOL(usb_set_configuration);
EXPORT_SYMBOL(usb_set_interface);
......@@ -1015,189 +1015,6 @@ void usb_free_dev(struct usb_device *dev)
}
/*-------------------------------------------------------------------*
* SYNCHRONOUS CALLS *
*-------------------------------------------------------------------*/
struct usb_api_data {
wait_queue_head_t wqh;
int done;
};
static void usb_api_blocking_completion(struct urb *urb)
{
struct usb_api_data *awd = (struct usb_api_data *)urb->context;
awd->done = 1;
wmb();
wake_up(&awd->wqh);
}
// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{
DECLARE_WAITQUEUE(wait, current);
struct usb_api_data awd;
int status;
init_waitqueue_head(&awd.wqh);
awd.done = 0;
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait);
urb->context = &awd;
status = usb_submit_urb(urb, GFP_KERNEL);
if (status) {
// something went wrong
usb_free_urb(urb);
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
return status;
}
while (timeout && !awd.done)
{
timeout = schedule_timeout(timeout);
set_current_state(TASK_UNINTERRUPTIBLE);
rmb();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
if (!timeout && !awd.done) {
if (urb->status != -EINPROGRESS) { /* No callback?!! */
printk(KERN_ERR "usb: raced timeout, "
"pipe 0x%x status %d time left %d\n",
urb->pipe, urb->status, timeout);
status = urb->status;
} else {
printk("usb_control/bulk_msg: timeout\n");
usb_unlink_urb(urb); // remove urb safely
status = -ETIMEDOUT;
}
} else
status = urb->status;
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)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
usb_api_blocking_completion, 0);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
/**
* usb_control_msg - Builds a control urb, sends it off and waits for completion
* @dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @request: USB message request value
* @requesttype: USB message request type value
* @value: USB message value
* @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
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
* This function sends a simple control message to a specified endpoint
* and waits for the message to complete, or timeout.
*
* If successful, it returns the number of bytes transferred, otherwise a negative error number.
*
* 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()
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
int ret;
if (!dr)
return -ENOMEM;
dr->bRequestType= requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16p(&value);
dr->wIndex = cpu_to_le16p(&index);
dr->wLength = cpu_to_le16p(&size);
//dbg("usb_control_msg");
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
/**
* 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
* @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 jiffies to wait for the message to complete before
* timing out (if 0 the wait is forever)
* Context: !in_interrupt ()
*
* This function sends a simple bulk 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()
*/
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
if (len < 0)
return -EINVAL;
urb=usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
FILL_BULK_URB(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, 0);
return usb_start_wait_urb(urb,timeout,actual_length);
}
/**
* usb_get_current_frame_number - return current bus frame number
* @dev: the device whose bus is being queried
......@@ -1801,382 +1618,6 @@ int usb_set_address(struct usb_device *dev)
0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_GET_TIMEOUT);
}
/**
* usb_get_descriptor - issues a generic GET_DESCRIPTOR request
* @dev: the device whose descriptor is being retrieved
* @type: the descriptor type (USB_DT_*)
* @index: the number of the descriptor
* @buf: where to put the descriptor
* @size: how big is "buf"?
* Context: !in_interrupt ()
*
* Gets a USB descriptor. Convenience functions exist to simplify
* getting some types of descriptors. Use
* usb_get_device_descriptor() for USB_DT_DEVICE,
* and usb_get_string() or usb_string() for USB_DT_STRING.
* Configuration descriptors (USB_DT_CONFIG) are part of the device
* structure, at least for the current configuration.
* In addition to a number of USB-standard descriptors, some
* devices also use class-specific or vendor-specific descriptors.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{
int i = 5;
int result;
memset(buf,0,size); // Make sure we parse really received data
while (i--) {
/* retries if the returned length was 0; flakey device */
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;
}
return result;
}
/**
* usb_get_string - gets a string descriptor
* @dev: the device whose string descriptor is being retrieved
* @langid: code for language chosen (from string descriptor zero)
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
* Context: !in_interrupt ()
*
* Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
* in little-endian byte order).
* The usb_string() function will often be a convenient way to turn
* these strings into kernel-printable form.
*
* Strings may be referenced in device, configuration, interface, or other
* descriptors, and could also be used in vendor-specific ways.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* 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)
{
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);
}
/**
* usb_get_device_descriptor - (re)reads the device descriptor
* @dev: the device whose device descriptor is being updated
* 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.
*
* There's normally no need to use this call, although some devices
* will change their descriptors after events like updating firmware.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
int usb_get_device_descriptor(struct usb_device *dev)
{
int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
sizeof(dev->descriptor));
if (ret >= 0) {
le16_to_cpus(&dev->descriptor.bcdUSB);
le16_to_cpus(&dev->descriptor.idVendor);
le16_to_cpus(&dev->descriptor.idProduct);
le16_to_cpus(&dev->descriptor.bcdDevice);
}
return ret;
}
/**
* usb_get_status - issues a GET_STATUS call
* @dev: the device whose status is being checked
* @type: USB_RECIP_*; for device, interface, or endpoint
* @target: zero (for device), else interface or endpoint number
* @data: pointer to two bytes of bitmap data
* Context: !in_interrupt ()
*
* Returns device, interface, or endpoint status. Normally only of
* interest to see if the device is self powered, or has enabled the
* remote wakeup facility; or whether a bulk or interrupt endpoint
* is halted ("stalled").
*
* Bits in these status bitmaps are set using the SET_FEATURE request,
* and cleared using the CLEAR_FEATURE request. The usb_clear_halt()
* function should be used to clear halt ("stall") status.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call.
*/
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);
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally, for config/altsetting reconfig.
void usb_set_maxpacket(struct usb_device *dev)
{
int i, b;
for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *ifp = dev->actconfig->interface + i;
struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
struct usb_endpoint_descriptor *ep = as->endpoint;
int e;
for (e=0; e<as->bNumEndpoints; e++) {
b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL) { /* Control => bidirectional */
dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
}
else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
}
else {
if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
}
}
}
}
/**
* usb_clear_halt - tells device to clear endpoint halt/stall condition
* @dev: device whose endpoint is halted
* @pipe: endpoint "pipe" being cleared
* Context: !in_interrupt ()
*
* This is used to clear halt conditions for bulk and interrupt endpoints,
* as reported by URB completion status. Endpoints that are halted are
* sometimes referred to as being "stalled". Such endpoints are unable
* to transmit or receive data until the halt status is cleared. Any URBs
* queued queued for such an endpoint should normally be unlinked before
* clearing the halt condition.
*
* Note that control and isochronous endpoints don't halt, although control
* endpoints report "protocol stall" (for unsupported requests) using the
* same status code used to report a true stall.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_clear_halt(struct usb_device *dev, int pipe)
{
int result;
__u16 status;
unsigned char *buffer;
int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
/*
if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp)))
return 0;
*/
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0,
HZ * USB_CTRL_SET_TIMEOUT);
/* don't clear if failed */
if (result < 0)
return result;
buffer = kmalloc(sizeof(status), GFP_KERNEL);
if (!buffer) {
err("unable to allocate memory for configuration descriptors");
return -ENOMEM;
}
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
// FIXME USB_CTRL_GET_TIMEOUT, yes? why not usb_get_status() ?
buffer, sizeof(status), HZ * USB_CTRL_SET_TIMEOUT);
memcpy(&status, buffer, sizeof(status));
kfree(buffer);
if (result < 0)
return result;
if (le16_to_cpu(status) & 1)
return -EPIPE; /* still halted */
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
/* toggle is reset on clear */
usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
return 0;
}
/**
* usb_set_interface - Makes a particular alternate setting be current
* @dev: the device whose interface is being updated
* @interface: the interface being updated
* @alternate: the setting being chosen.
* Context: !in_interrupt ()
*
* This is used to enable data transfers on interfaces that may not
* be enabled by default. Not all devices support such configurability.
*
* Within any given configuration, each interface may have several
* alternative settings. These are often used to control levels of
* bandwidth consumption. For example, the default setting for a high
* speed interrupt endpoint may not send more than about 4KBytes per
* microframe, and isochronous endpoints may never be part of a an
* interface's default setting. To access such bandwidth, alternate
* interface setting must be made current.
*
* Note that in the Linux USB subsystem, bandwidth associated with
* an endpoint in a given alternate setting is not reserved until an
* is submitted that needs that bandwidth. Some other operating systems
* allocate bandwidth early, when a configuration is chosen.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
struct usb_interface *iface;
struct usb_interface_descriptor *iface_as;
int i, ret;
iface = usb_ifnum_to_if(dev, interface);
if (!iface) {
warn("selecting invalid interface %d", interface);
return -EINVAL;
}
/* 9.4.10 says devices don't need this, if the interface
only has one alternate setting */
if (iface->num_altsetting == 1) {
dbg("ignoring set_interface for dev %d, iface %d, alt %d",
dev->devnum, interface, alternate);
return 0;
}
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
interface, NULL, 0, HZ * 5)) < 0)
return ret;
iface->act_altsetting = alternate;
/* 9.1.1.5: reset toggles for all endpoints affected by this iface-as
*
* Note:
* Despite EP0 is always present in all interfaces/AS, the list of
* endpoints from the descriptor does not contain EP0. Due to its
* omnipresence one might expect EP0 being considered "affected" by
* any SetInterface request and hence assume toggles need to be reset.
* However, EP0 toggles are re-synced for every individual transfer
* during the SETUP stage - hence EP0 toggles are "don't care" here.
*/
iface_as = &iface->altsetting[alternate];
for (i = 0; i < iface_as->bNumEndpoints; i++) {
u8 ep = iface_as->endpoint[i].bEndpointAddress;
usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0);
}
/* usb_set_maxpacket() sets the maxpacket size for all EP in all
* interfaces but it shouldn't do any harm here: we have changed
* the AS for the requested interface only, hence for unaffected
* interfaces it's just re-application of still-valid values.
*/
usb_set_maxpacket(dev);
return 0;
}
/**
* 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 ()
*
* This is used to enable non-default device modes. Not all devices
* support this kind of configurability. By default, configuration
* zero is selected after enumeration; many devices only have a single
* configuration.
*
* USB devices may support one or more configurations, which affect
* power consumption and the functionality available. For example,
* the default configuration is limited to using 100mA of bus power,
* so that when certain device functionality requires more power,
* and the device is bus powered, that functionality will be in some
* non-default device configuration. Other device modes may also be
* reflected as configuration options, such as whether two ISDN
* channels are presented as independent 64Kb/s interfaces or as one
* bonded 128Kb/s interface.
*
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns zero on success, or else the status code returned by the
* underlying usb_control_msg() call.
*/
int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_config_descriptor *cp = NULL;
for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].bConfigurationValue == configuration) {
cp = &dev->config[i];
break;
}
}
if (!cp) {
warn("selecting invalid configuration %d", configuration);
return -EINVAL;
}
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)
return ret;
dev->actconfig = cp;
dev->toggle[0] = 0;
dev->toggle[1] = 0;
usb_set_maxpacket(dev);
return 0;
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
......@@ -2280,87 +1721,6 @@ int usb_get_configuration(struct usb_device *dev)
return result;
}
/**
* 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;
unsigned int u, idx;
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_get_string(dev, 0, 0, tbuf, 4);
if (err < 0) {
err("error getting string descriptor 0 (error=%d)", err);
goto errout;
} else if (tbuf[0] < 4) {
err("string descriptor 0 too short");
err = -EINVAL;
goto errout;
} else {
dev->have_langid = -1;
dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
/* always use the first langid listed */
dbg("USB device number %d default language ID 0x%x",
dev->devnum, dev->string_langid);
}
}
/*
* Just ask for a maximum length string and then take the length
* that was returned.
*/
err = usb_get_string(dev, dev->string_langid, index, tbuf, 255);
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;
errout:
kfree(tbuf);
return err;
}
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
......@@ -2616,18 +1976,5 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_get_current_frame_number);
// synchronous request completion model
EXPORT_SYMBOL(usb_control_msg);
EXPORT_SYMBOL(usb_bulk_msg);
// synchronous control message convenience routines
EXPORT_SYMBOL(usb_get_descriptor);
EXPORT_SYMBOL(usb_get_device_descriptor);
EXPORT_SYMBOL(usb_get_status);
EXPORT_SYMBOL(usb_get_string);
EXPORT_SYMBOL(usb_string);
EXPORT_SYMBOL(usb_clear_halt);
EXPORT_SYMBOL(usb_set_configuration);
EXPORT_SYMBOL(usb_set_interface);
EXPORT_SYMBOL(usb_devfs_handle);
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment