summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO1
-rw-r--r--libusb/core.c17
-rw-r--r--libusb/descriptor.c103
-rw-r--r--libusb/libusb.h12
-rw-r--r--libusb/os/linux_usbfs.c67
5 files changed, 128 insertions, 72 deletions
diff --git a/TODO b/TODO
index f1e4345..84d3ab9 100644
--- a/TODO
+++ b/TODO
@@ -6,7 +6,6 @@ endianness of control setup, issues when resubmitting transfers
serialization of handle_events
internal docs for OS porters
check which messages are sent during open, claim interface, close, release
-unconfigured devices
1.0 API style/naming points to reconsider
=========================================
diff --git a/libusb/core.c b/libusb/core.c
index d94d7b8..572e6a3 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -460,15 +460,16 @@ API_EXPORTED int libusb_get_max_packet_size(libusb_device *dev,
unsigned char endpoint)
{
int iface_idx;
- struct libusb_config_descriptor *config =
- libusb_get_active_config_descriptor(dev);
- int r = LIBUSB_ERROR_NOT_FOUND;
-
- if (!config) {
+ struct libusb_config_descriptor *config;
+ int r;
+
+ r = libusb_get_active_config_descriptor(dev, &config);
+ if (r < 0) {
usbi_err("could not retrieve active config descriptor");
return LIBUSB_ERROR_OTHER;
}
+ r = LIBUSB_ERROR_NOT_FOUND;
for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
const struct libusb_interface *iface = &config->interface[iface_idx];
int altsetting_idx;
@@ -682,6 +683,10 @@ API_EXPORTED libusb_device *libusb_get_device(libusb_device_handle *dev_handle)
* must release all claimed interfaces using libusb_release_interface() before
* setting a new active configuration.
*
+ * A configuration value of -1 will put the device in unconfigured state.
+ * The USB specifications state that a configuration value of 0 does this,
+ * however buggy devices exist which actually have a configuration 0.
+ *
* You should always use this function rather than formulating your own
* SET_CONFIGURATION control request. This is because the underlying operating
* system needs to know when such changes happen.
@@ -690,7 +695,7 @@ API_EXPORTED libusb_device *libusb_get_device(libusb_device_handle *dev_handle)
*
* \param dev a device handle
* \param configuration the bConfigurationValue of the configuration you
- * wish to activate
+ * wish to activate, or -1 if you wish to put the device in unconfigured state
* \returns 0 on success
* \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist
* \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed
diff --git a/libusb/descriptor.c b/libusb/descriptor.c
index f545c7f..4a3be62 100644
--- a/libusb/descriptor.c
+++ b/libusb/descriptor.c
@@ -447,39 +447,43 @@ API_EXPORTED int libusb_get_device_descriptor(libusb_device *dev,
* sent to the device.
*
* \param dev a device
- * \returns the USB configuration descriptor which must be freed with
- * libusb_free_config_descriptor() when done
- * \returns NULL on error
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
+ * \returns another LIBUSB_ERROR code on error
* \see libusb_get_config_descriptor
*/
-API_EXPORTED
-struct libusb_config_descriptor *libusb_get_active_config_descriptor(
- libusb_device *dev)
+API_EXPORTED int libusb_get_active_config_descriptor(libusb_device *dev,
+ struct libusb_config_descriptor **config)
{
- struct libusb_config_descriptor *config = malloc(sizeof(*config));
+ struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
unsigned char tmp[8];
unsigned char *buf = NULL;
int r;
usbi_dbg("");
- if (!config)
- return NULL;
+ if (!_config)
+ return LIBUSB_ERROR_NO_MEM;
r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp));
if (r < 0)
goto err;
- usbi_parse_descriptor(tmp, "bbw", config);
- buf = malloc(config->wTotalLength);
- if (!buf)
+ usbi_parse_descriptor(tmp, "bbw", _config);
+ buf = malloc(_config->wTotalLength);
+ if (!buf) {
+ r = LIBUSB_ERROR_NO_MEM;
goto err;
+ }
r = usbi_backend->get_active_config_descriptor(dev, buf,
- config->wTotalLength);
+ _config->wTotalLength);
if (r < 0)
goto err;
- r = parse_configuration(config, buf);
+ r = parse_configuration(_config, buf);
if (r < 0) {
usbi_err("parse_configuration failed with error %d", r);
goto err;
@@ -487,13 +491,14 @@ struct libusb_config_descriptor *libusb_get_active_config_descriptor(
usbi_warn("descriptor data still left");
}
- return config;
+ *config = _config;
+ return 0;
err:
- free(config);
+ free(_config);
if (buf)
free(buf);
- return NULL;
+ return r;
}
/** \ingroup desc
@@ -503,44 +508,49 @@ err:
*
* \param dev a device
* \param config_index the index of the configuration you wish to retrieve
- * \returns the USB configuration descriptor which must be freed with
- * libusb_free_config_descriptor() when done
- * \returns NULL on error
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * \returns another LIBUSB_ERROR code on error
* \see libusb_get_active_config_descriptor()
* \see libusb_get_config_descriptor_by_value()
*/
-API_EXPORTED struct libusb_config_descriptor *libusb_get_config_descriptor(
- libusb_device *dev, uint8_t config_index)
+API_EXPORTED int libusb_get_config_descriptor(libusb_device *dev,
+ uint8_t config_index, struct libusb_config_descriptor **config)
{
- struct libusb_config_descriptor *config;
+ struct libusb_config_descriptor *_config;
unsigned char tmp[8];
unsigned char *buf = NULL;
int r;
usbi_dbg("index %d", config_index);
if (config_index >= dev->num_configurations)
- return NULL;
+ return LIBUSB_ERROR_NOT_FOUND;
- config = malloc(sizeof(*config));
- if (!config)
- return NULL;
+ _config = malloc(sizeof(*_config));
+ if (!_config)
+ return LIBUSB_ERROR_NO_MEM;
r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
sizeof(tmp));
if (r < 0)
goto err;
- usbi_parse_descriptor(tmp, "bbw", config);
- buf = malloc(config->wTotalLength);
- if (!buf)
+ usbi_parse_descriptor(tmp, "bbw", _config);
+ buf = malloc(_config->wTotalLength);
+ if (!buf) {
+ r = LIBUSB_ERROR_NO_MEM;
goto err;
+ }
r = usbi_backend->get_config_descriptor(dev, config_index, buf,
- config->wTotalLength);
+ _config->wTotalLength);
if (r < 0)
goto err;
- r = parse_configuration(config, buf);
+ r = parse_configuration(_config, buf);
if (r < 0) {
usbi_err("parse_configuration failed with error %d", r);
goto err;
@@ -548,13 +558,14 @@ API_EXPORTED struct libusb_config_descriptor *libusb_get_config_descriptor(
usbi_warn("descriptor data still left");
}
- return config;
+ *config = _config;
+ return 0;
err:
- free(config);
+ free(_config);
if (buf)
free(buf);
- return NULL;
+ return r;
}
/* iterate through all configurations, returning the index of the configuration
@@ -591,22 +602,26 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
* \param dev a device
* \param bConfigurationValue the bConfigurationValue of the configuration you
* wish to retrieve
- * \returns the USB configuration descriptor which must be freed with
- * libusb_free_config_descriptor() when done
- * \returns NULL on error
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * \returns another LIBUSB_ERROR code on error
* \see libusb_get_active_config_descriptor()
* \see libusb_get_config_descriptor()
*/
-API_EXPORTED
-struct libusb_config_descriptor *libusb_get_config_descriptor_by_value(
- libusb_device *dev, uint8_t bConfigurationValue)
+API_EXPORTED int libusb_get_config_descriptor_by_value(libusb_device *dev,
+ uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
{
int idx;
int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx);
- if (r < 0 || idx == -1)
- return NULL;
+ if (r < 0)
+ return r;
+ else if (idx == -1)
+ return LIBUSB_ERROR_NOT_FOUND;
else
- return libusb_get_config_descriptor(dev, idx);
+ return libusb_get_config_descriptor(dev, idx, config);
}
/** \ingroup desc
diff --git a/libusb/libusb.h b/libusb/libusb.h
index f946a27..a24fce3 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -667,12 +667,12 @@ void libusb_unref_device(libusb_device *dev);
int libusb_get_device_descriptor(libusb_device *dev,
struct libusb_device_descriptor *desc);
-struct libusb_config_descriptor *libusb_get_active_config_descriptor(
- libusb_device *dev);
-struct libusb_config_descriptor *libusb_get_config_descriptor(
- libusb_device *dev, uint8_t config_index);
-struct libusb_config_descriptor *libusb_get_config_descriptor_by_value(
- libusb_device *dev, uint8_t bConfigurationValue);
+int libusb_get_active_config_descriptor(libusb_device *dev,
+ struct libusb_config_descriptor **config);
+int libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index,
+ struct libusb_config_descriptor **config);
+int libusb_get_config_descriptor_by_value(libusb_device *dev,
+ uint8_t bConfigurationValue, struct libusb_config_descriptor **config);
void libusb_free_config_descriptor(struct libusb_config_descriptor *config);
uint8_t libusb_get_bus_number(libusb_device *dev);
uint8_t libusb_get_device_address(libusb_device *dev);
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 4c0fb41..e69578c 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -249,6 +249,9 @@ static int usbfs_get_active_config_descriptor(struct libusb_device *dev,
unsigned char *buffer, size_t len)
{
struct linux_device_priv *priv = __device_priv(dev);
+ if (!priv->config_descriptor)
+ return LIBUSB_ERROR_NOT_FOUND; /* device is unconfigured */
+
/* retrieve cached copy */
memcpy(buffer, priv->config_descriptor, len);
return 0;
@@ -280,6 +283,9 @@ static int sysfs_get_active_config_descriptor(struct libusb_device *dev,
if (r < 0) {
usbi_err("read failed, ret=%d errno=%d", fd, errno);
return LIBUSB_ERROR_IO;
+ } else if (r == 0) {
+ usbi_dbg("device is unconfigured");
+ return LIBUSB_ERROR_NOT_FOUND;
} else if (r < len) {
usbi_err("short read %d/%d", r, len);
return LIBUSB_ERROR_IO;
@@ -416,7 +422,7 @@ static int cache_active_config(struct libusb_device *dev, int fd,
}
/* read the bConfigurationValue for a device */
-static int sysfs_get_active_config(struct libusb_device *dev)
+static int sysfs_get_active_config(struct libusb_device *dev, int *config)
{
char *endptr;
char tmp[4] = {0, 0, 0, 0};
@@ -435,8 +441,9 @@ static int sysfs_get_active_config(struct libusb_device *dev)
r, errno);
return LIBUSB_ERROR_IO;
} else if (r == 0) {
- usbi_err("short bConfigurationValue read");
- return LIBUSB_ERROR_IO;
+ usbi_err("device unconfigured");
+ *config = -1;
+ return 0;
}
if (tmp[sizeof(tmp) - 1] != 0) {
@@ -453,7 +460,8 @@ static int sysfs_get_active_config(struct libusb_device *dev)
return LIBUSB_ERROR_IO;
}
- return (int) num;
+ *config = (int) num;
+ return 0;
}
/* send a control message to retrieve active configuration */
@@ -489,6 +497,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
char path[PATH_MAX + 1];
int fd;
int active_config = 0;
+ int device_configured = 1;
ssize_t r;
dev->bus_number = busnum;
@@ -507,9 +516,11 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
priv->config_descriptor = NULL;
if (sysfs_can_relate_devices) {
- active_config = sysfs_get_active_config(dev);
- if (active_config < 0)
- return active_config;
+ int tmp = sysfs_get_active_config(dev, &active_config);
+ if (tmp < 0)
+ return tmp;
+ if (active_config == -1)
+ device_configured = 0;
}
__get_usbfs_path(dev, path);
@@ -539,6 +550,14 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
if (active_config < 0) {
close(fd);
return active_config;
+ } else if (active_config == 0) {
+ /* some buggy devices have a configuration 0, but we're
+ * reaching into the corner of a corner case here, so let's
+ * not support buggy devices in these circumstances.
+ * stick to the specs: a configuration value of 0 means
+ * unconfigured. */
+ usbi_dbg("assuming unconfigured device");
+ device_configured = 0;
}
}
}
@@ -562,13 +581,20 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
return LIBUSB_ERROR_IO;
}
- r = cache_active_config(dev, fd, active_config);
- close(fd);
- if (r < 0) {
- free(dev_buf);
- return r;
+ /* bit of a hack: set num_configurations now because cache_active_config()
+ * calls usbi_get_config_index_by_value() which uses it */
+ dev->num_configurations = dev_buf[DEVICE_DESC_LENGTH - 1];
+
+ if (device_configured) {
+ r = cache_active_config(dev, fd, active_config);
+ if (r < 0) {
+ close(fd);
+ free(dev_buf);
+ return r;
+ }
}
+ close(fd);
priv->dev_descriptor = dev_buf;
return 0;
}
@@ -745,6 +771,8 @@ static int sysfs_scan_device(struct discovered_devs **_discdevs,
return LIBUSB_ERROR_IO;
}
+ sysfs_can_relate_devices = 1;
+
r = fscanf(fd, "%d", &busnum);
fclose(fd);
if (r != 1) {
@@ -859,6 +887,7 @@ static void op_close(struct libusb_device_handle *dev_handle)
static int op_set_configuration(struct libusb_device_handle *handle, int config)
{
+ struct linux_device_priv *priv = __device_priv(handle->dev);
int fd = __device_handle_priv(handle)->fd;
int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config);
if (r) {
@@ -873,9 +902,17 @@ static int op_set_configuration(struct libusb_device_handle *handle, int config)
if (!sysfs_has_descriptors) {
/* update our cached active config descriptor */
- r = cache_active_config(handle->dev, fd, config);
- if (r < 0)
- usbi_warn("failed to update cached config descriptor, error %d", r);
+ if (config == -1) {
+ if (priv->config_descriptor) {
+ free(priv->config_descriptor);
+ priv->config_descriptor = NULL;
+ }
+ } else {
+ r = cache_active_config(handle->dev, fd, config);
+ if (r < 0)
+ usbi_warn("failed to update cached config descriptor, "
+ "error %d", r);
+ }
}
return 0;