summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2008-05-05 17:47:49 +0100
committerDaniel Drake <dsd@gentoo.org>2008-05-05 17:49:52 +0100
commitb27fff633843824744df7d334cb89ece329cafa6 (patch)
tree90a3f26f40c5af735036d8c1be5ce43656812746
parenta304eca71f22c6df7d70a901483b30f1b8e93378 (diff)
downloadlibusb-b27fff633843824744df7d334cb89ece329cafa6.tar.gz
move descriptor parsing into main library
OS modules now provide functionality for fetching device/config descriptors
-rw-r--r--libusb/core.c92
-rw-r--r--libusb/libusbi.h8
-rw-r--r--libusb/os/linux_usbfs.c201
3 files changed, 201 insertions, 100 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 2225106..0464bd8 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -232,6 +232,7 @@ static void discovered_devs_free(struct discovered_devs *discdevs)
free(discdevs);
}
+/* allocate a new device with reference count 1 */
struct libusb_device *usbi_alloc_device(unsigned long session_id)
{
size_t priv_size = usbi_backend->device_priv_size;
@@ -255,6 +256,97 @@ struct libusb_device *usbi_alloc_device(unsigned long session_id)
return dev;
}
+/* call the OS discovery routines to populate descriptors etc */
+int usbi_discover_device(struct libusb_device *dev)
+{
+ int r;
+ int i;
+ void *user_data;
+ unsigned char raw_desc[DEVICE_DESC_LENGTH];
+ size_t alloc_size;
+
+ dev->config = NULL;
+
+ r = usbi_backend->begin_discovery(dev, &user_data);
+ if (r < 0)
+ return r;
+
+ r = usbi_backend->get_device_descriptor(dev, raw_desc, user_data);
+ if (r < 0)
+ goto err;
+
+ usbi_parse_descriptor(raw_desc, "bbWbbbbWWWbbbb", &dev->desc);
+
+ if (dev->desc.bNumConfigurations > USB_MAXCONFIG) {
+ usbi_err("too many configurations");
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (dev->desc.bNumConfigurations < 1) {
+ usbi_dbg("no configurations?");
+ r = -EINVAL;
+ goto err;
+ }
+
+ alloc_size = dev->desc.bNumConfigurations
+ * sizeof(struct libusb_config_descriptor);
+ dev->config = malloc(alloc_size);
+ if (!dev->config) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+
+ memset(dev->config, 0, alloc_size);
+ for (i = 0; i < dev->desc.bNumConfigurations; i++) {
+ unsigned char tmp[8];
+ unsigned char *bigbuffer;
+ struct libusb_config_descriptor config;
+
+ r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
+ user_data);
+ if (r < 0)
+ goto err;
+
+ usbi_parse_descriptor(tmp, "bbw", &config);
+
+ bigbuffer = malloc(config.wTotalLength);
+ if (!bigbuffer) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+
+ r = usbi_backend->get_config_descriptor(dev, i, bigbuffer,
+ config.wTotalLength, user_data);
+ if (r < 0) {
+ free(bigbuffer);
+ goto err;
+ }
+
+ r = usbi_parse_configuration(&dev->config[i], bigbuffer);
+ free(bigbuffer);
+ if (r < 0) {
+ usbi_err("parse_configuration failed with code %d", r);
+ goto err;
+ } else if (r > 0) {
+ usbi_warn("descriptor data still left\n");
+ }
+ }
+
+ usbi_backend->end_discovery(dev, user_data);
+ return 0;
+
+err:
+ if (dev->config) {
+ usbi_clear_configurations(dev);
+ free(dev->config);
+ dev->config = NULL;
+ }
+
+ usbi_backend->end_discovery(dev, user_data);
+ return r;
+}
+
struct libusb_device *usbi_get_device_by_session_id(unsigned long session_id)
{
struct libusb_device *dev;
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 2f70053..ca44512 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -223,6 +223,7 @@ void usbi_io_init(void);
struct libusb_device *usbi_alloc_device(unsigned long session_id);
struct libusb_device *usbi_get_device_by_session_id(unsigned long session_id);
+int usbi_discover_device(struct libusb_device *dev);
void usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
enum libusb_transfer_status status);
@@ -273,6 +274,13 @@ struct usbi_os_backend {
int (*open)(struct libusb_device_handle *handle);
void (*close)(struct libusb_device_handle *handle);
+ int (*begin_discovery)(struct libusb_device *device, void **user_data);
+ int (*get_device_descriptor)(struct libusb_device *device,
+ unsigned char *buffer, void *user_data);
+ int (*get_config_descriptor)(struct libusb_device *device, int index,
+ unsigned char *buffer, size_t len, void *user_data);
+ void (*end_discovery)(struct libusb_device *device, void *user_data);
+
int (*set_configuration)(struct libusb_device_handle *handle, int config);
int (*claim_interface)(struct libusb_device_handle *handle, int iface);
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 22d6b6a..4e1cae1 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -133,132 +133,125 @@ static int op_init(void)
return 0;
}
-static int initialize_device(struct libusb_device *dev, uint8_t busnum,
- uint8_t devaddr)
+struct discovery_data {
+ int fd;
+};
+
+static int op_begin_discovery(struct libusb_device *dev, void **user_data)
{
struct linux_device_priv *priv = __device_priv(dev);
- char path[PATH_MAX + 1];
- unsigned char raw_desc[DEVICE_DESC_LENGTH];
- int fd = 0;
- int i;
- int r;
- int tmp;
-
- priv->nodepath = NULL;
- dev->config = NULL;
- dev->bus_number = busnum;
- dev->device_address = devaddr;
+ struct discovery_data *ddata = malloc(sizeof(*ddata));
+ if (!ddata)
+ return LIBUSB_ERROR_NO_MEM;
- snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, busnum, devaddr);
- usbi_dbg("%s", path);
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- usbi_dbg("open '%s' failed, ret=%d errno=%d", path, fd, errno);
- /* FIXME this might not be an error if the file has gone away due
- * to unplugging */
- r = -EIO;
- goto err;
+ ddata->fd = open(priv->nodepath, O_RDONLY);
+ if (ddata->fd < 0) {
+ usbi_dbg("open '%s' failed, ret=%d errno=%d", priv->nodepath,
+ ddata->fd, errno);
+ free(ddata);
+ return LIBUSB_ERROR_IO;
}
- /* FIXME: move config parsing into main lib */
- r = read(fd, raw_desc, DEVICE_DESC_LENGTH);
+ *user_data = ddata;
+ return 0;
+}
+
+static int op_get_device_descriptor(struct libusb_device *device,
+ unsigned char *buffer, void *user_data)
+{
+ struct discovery_data *ddata = user_data;
+ int r = read(ddata->fd, buffer, DEVICE_DESC_LENGTH);
if (r < 0) {
usbi_err("read failed ret=%d errno=%d", r, errno);
- goto err;
- }
- if (r < DEVICE_DESC_LENGTH) {
+ return LIBUSB_ERROR_IO;
+ } else if (r < DEVICE_DESC_LENGTH) {
usbi_err("short descriptor read %d/%d", r, DEVICE_DESC_LENGTH);
- r = -EIO;
- goto err;
- }
-
- usbi_parse_descriptor(raw_desc, "bbWbbbbWWWbbbb", &dev->desc);
-
- /* Now try to fetch the rest of the descriptors */
- if (dev->desc.bNumConfigurations > USB_MAXCONFIG) {
- usbi_err("too many configurations");
- r = -EINVAL;
- goto err;
+ return LIBUSB_ERROR_IO;
}
- if (dev->desc.bNumConfigurations < 1) {
- usbi_dbg("no configurations?");
- r = -EINVAL;
- goto err;
- }
+ return 0;
+}
- tmp = dev->desc.bNumConfigurations * sizeof(struct libusb_config_descriptor);
- dev->config = malloc(tmp);
- if (!dev->config) {
- r = -ENOMEM;
- goto err;
+static int op_get_config_descriptor(struct libusb_device *device,
+ int config_index, unsigned char *buffer, size_t len, void *user_data)
+{
+ struct discovery_data *ddata = user_data;
+ off_t off;
+ ssize_t r;
+ int fd = ddata->fd;
+
+ off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET);
+ if (off < 0) {
+ usbi_err("seek failed ret=%d errno=%d", off, errno);
+ return LIBUSB_ERROR_IO;
}
- memset(dev->config, 0, tmp);
- for (i = 0; i < dev->desc.bNumConfigurations; i++) {
- unsigned char buffer[8], *bigbuffer;
+ /* might need to skip some configuration descriptors to reach the
+ * requested index */
+ while (config_index > 0) {
+ unsigned char tmp[8];
struct libusb_config_descriptor config;
- /* Get the first 8 bytes to figure out what the total length is */
- r = read(fd, buffer, sizeof(buffer));
- if (r < sizeof(buffer)) {
- usbi_err("short descriptor read (%d/%d)", r, sizeof(buffer));
- r = -EIO;
- goto err;
+ /* read first 8 bytes of descriptor */
+ r = read(fd, tmp, sizeof(tmp));
+ if (r < 0) {
+ usbi_err("read failed ret=%d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r < sizeof(tmp)) {
+ usbi_err("short descriptor read %d/%d", r, sizeof(tmp));
+ return LIBUSB_ERROR_IO;
}
-
+
usbi_parse_descriptor(buffer, "bbw", &config);
- bigbuffer = malloc(config.wTotalLength);
- if (!bigbuffer) {
- r = -ENOMEM;
- goto err;
+ /* seek forward to end of config */
+ off = lseek(fd, config.wTotalLength - sizeof(tmp), SEEK_CUR);
+ if (off < 0) {
+ usbi_err("seek failed ret=%d errno=%d", off, errno);
+ return LIBUSB_ERROR_IO;
}
- /* Read the rest of the config descriptor */
- memcpy(bigbuffer, buffer, sizeof(buffer));
-
- tmp = config.wTotalLength - 8;
- r = read(fd, bigbuffer + 8, tmp);
- if (r < tmp) {
- usbi_err("short descriptor read (%d/%d)", r, tmp);
- free(bigbuffer);
- r = -EIO;
- goto err;
- }
-
- r = usbi_parse_configuration(&dev->config[i], bigbuffer);
- free(bigbuffer);
- if (r < 0) {
- usbi_err("parse_configuration failed with code %d", r);
- goto err;
- }
- if (r > 0)
- usbi_warn("descriptor data still left\n");
+ config_index--;
}
- priv->nodepath = strdup(path);
- if (!priv->nodepath) {
- r = -ENOMEM;
- goto err;
+ /* read the actual config */
+ r = read(fd, buffer, len);
+ if (r < 0) {
+ usbi_err("read failed ret=%d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r < len) {
+ usbi_err("short descriptor read %d/%d", r, len);
+ return LIBUSB_ERROR_IO;
}
- close(fd);
return 0;
+}
-err:
- if (fd)
- close(fd);
- if (dev->config) {
- usbi_clear_configurations(dev);
- free(dev->config);
- dev->config = NULL;
- }
- if (priv->nodepath) {
- free(priv->nodepath);
- priv->nodepath = NULL;
- }
- return r;
+static void op_end_discovery(struct libusb_device *device, void *user_data)
+{
+ struct discovery_data *ddata = user_data;
+ close(ddata->fd);
+ free(ddata);
+}
+
+static int initialize_device(struct libusb_device *dev, uint8_t busnum,
+ uint8_t devaddr)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+ char path[PATH_MAX + 1];
+
+ priv->nodepath = NULL;
+ dev->bus_number = busnum;
+ dev->device_address = devaddr;
+
+ snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, busnum, devaddr);
+ usbi_dbg("%s", path);
+
+ priv->nodepath = strdup(path);
+ if (!priv->nodepath)
+ return LIBUSB_ERROR_NO_MEM;
+
+ return 0;
}
/* open a device file, set up the libusb_device structure for it, and add it to
@@ -297,6 +290,9 @@ static int scan_device(struct discovered_devs **_discdevs, uint8_t busnum,
r = initialize_device(dev, busnum, devaddr);
if (r < 0)
goto out;
+ r = usbi_discover_device(dev);
+ if (r < 0)
+ goto out;
}
discdevs = discovered_devs_append(*_discdevs, dev);
@@ -1212,6 +1208,11 @@ const struct usbi_os_backend linux_usbfs_backend = {
.init = op_init,
.exit = NULL,
.get_device_list = op_get_device_list,
+ .begin_discovery = op_begin_discovery,
+ .get_device_descriptor = op_get_device_descriptor,
+ .get_config_descriptor = op_get_config_descriptor,
+ .end_discovery = op_end_discovery,
+
.open = op_open,
.close = op_close,
.set_configuration = op_set_configuration,