diff options
author | Daniel Drake <dsd@gentoo.org> | 2008-05-05 17:47:49 +0100 |
---|---|---|
committer | Daniel Drake <dsd@gentoo.org> | 2008-05-05 17:49:52 +0100 |
commit | b27fff633843824744df7d334cb89ece329cafa6 (patch) | |
tree | 90a3f26f40c5af735036d8c1be5ce43656812746 | |
parent | a304eca71f22c6df7d70a901483b30f1b8e93378 (diff) | |
download | libusb-b27fff633843824744df7d334cb89ece329cafa6.tar.gz |
move descriptor parsing into main library
OS modules now provide functionality for fetching device/config
descriptors
-rw-r--r-- | libusb/core.c | 92 | ||||
-rw-r--r-- | libusb/libusbi.h | 8 | ||||
-rw-r--r-- | libusb/os/linux_usbfs.c | 201 |
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, |