summaryrefslogtreecommitdiff
path: root/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb.c')
-rw-r--r--usb.c1192
1 files changed, 0 insertions, 1192 deletions
diff --git a/usb.c b/usb.c
deleted file mode 100644
index 141bd41..0000000
--- a/usb.c
+++ /dev/null
@@ -1,1192 +0,0 @@
-/*
- * libiio - Library for interfacing industrial I/O (IIO) devices
- *
- * Copyright (C) 2015 Analog Devices, Inc.
- * Author: Paul Cercueil <paul.cercueil@analog.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * */
-
-#include "iio-lock.h"
-#include "iio-private.h"
-#include "iiod-client.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <libusb-1.0/libusb.h>
-#include <stdbool.h>
-#include <string.h>
-
-#ifdef ERROR
-#undef ERROR
-#endif
-
-#include "debug.h"
-
-#define DEFAULT_TIMEOUT_MS 5000
-
-/* Endpoint for non-streaming operations */
-#define EP_OPS 1
-
-#define IIO_INTERFACE_NAME "IIO"
-
-struct iio_usb_ep_couple {
- unsigned char addr_in, addr_out;
- unsigned int pipe_id;
- bool in_use;
-
- struct iio_mutex *lock;
-};
-
-struct iio_usb_io_context {
- struct iio_usb_ep_couple *ep;
-
- struct iio_mutex *lock;
- bool cancelled;
- struct libusb_transfer *transfer;
-};
-
-struct iio_context_pdata {
- libusb_context *ctx;
- libusb_device_handle *hdl;
- unsigned int interface;
-
- struct iiod_client *iiod_client;
-
- /* Lock for non-streaming operations */
- struct iio_mutex *lock;
-
- /* Lock for endpoint reservation */
- struct iio_mutex *ep_lock;
-
- struct iio_usb_ep_couple *io_endpoints;
- unsigned int nb_ep_couples;
-
- unsigned int timeout_ms;
-
- struct iio_usb_io_context io_ctx;
-};
-
-struct iio_device_pdata {
- struct iio_mutex *lock;
-
- bool opened;
- struct iio_usb_io_context io_ctx;
-};
-
-static const unsigned int libusb_to_errno_codes[] = {
- [- LIBUSB_ERROR_INVALID_PARAM] = EINVAL,
- [- LIBUSB_ERROR_ACCESS] = EACCES,
- [- LIBUSB_ERROR_NO_DEVICE] = ENODEV,
- [- LIBUSB_ERROR_NOT_FOUND] = ENXIO,
- [- LIBUSB_ERROR_BUSY] = EBUSY,
- [- LIBUSB_ERROR_TIMEOUT] = ETIMEDOUT,
- [- LIBUSB_ERROR_OVERFLOW] = EIO,
- [- LIBUSB_ERROR_PIPE] = EPIPE,
- [- LIBUSB_ERROR_INTERRUPTED] = EINTR,
- [- LIBUSB_ERROR_NO_MEM] = ENOMEM,
- [- LIBUSB_ERROR_NOT_SUPPORTED] = ENOSYS,
-};
-
-static unsigned int libusb_to_errno(int error)
-{
- switch ((enum libusb_error) error) {
- case LIBUSB_ERROR_INVALID_PARAM:
- case LIBUSB_ERROR_ACCESS:
- case LIBUSB_ERROR_NO_DEVICE:
- case LIBUSB_ERROR_NOT_FOUND:
- case LIBUSB_ERROR_BUSY:
- case LIBUSB_ERROR_TIMEOUT:
- case LIBUSB_ERROR_PIPE:
- case LIBUSB_ERROR_INTERRUPTED:
- case LIBUSB_ERROR_NO_MEM:
- case LIBUSB_ERROR_NOT_SUPPORTED:
- return libusb_to_errno_codes[- (int) error];
- case LIBUSB_ERROR_IO:
- case LIBUSB_ERROR_OTHER:
- case LIBUSB_ERROR_OVERFLOW:
- default:
- return EIO;
- }
-}
-
-static int usb_io_context_init(struct iio_usb_io_context *io_ctx)
-{
- io_ctx->lock = iio_mutex_create();
- if (!io_ctx->lock)
- return -ENOMEM;
-
- return 0;
-}
-
-static void usb_io_context_exit(struct iio_usb_io_context *io_ctx)
-{
- if (io_ctx->lock) {
- iio_mutex_destroy(io_ctx->lock);
- io_ctx->lock = NULL;
- }
-}
-
-static int usb_get_version(const struct iio_context *ctx,
- unsigned int *major, unsigned int *minor, char git_tag[8])
-{
- return iiod_client_get_version(ctx->pdata->iiod_client,
- &ctx->pdata->io_ctx, major, minor, git_tag);
-}
-
-static unsigned int usb_calculate_remote_timeout(unsigned int timeout)
-{
- /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
- * by the remote. Is there something better to do here? */
- return timeout / 2;
-}
-
-#define USB_PIPE_CTRL_TIMEOUT 1000 /* These should not take long */
-
-#define IIO_USD_CMD_RESET_PIPES 0
-#define IIO_USD_CMD_OPEN_PIPE 1
-#define IIO_USD_CMD_CLOSE_PIPE 2
-
-static int usb_reset_pipes(struct iio_context_pdata *pdata)
-{
- int ret;
-
- ret = libusb_control_transfer(pdata->hdl, LIBUSB_REQUEST_TYPE_VENDOR |
- LIBUSB_RECIPIENT_INTERFACE, IIO_USD_CMD_RESET_PIPES,
- 0, pdata->interface, NULL, 0, USB_PIPE_CTRL_TIMEOUT);
- if (ret < 0)
- return -(int) libusb_to_errno(ret);
- return 0;
-}
-
-static int usb_open_pipe(struct iio_context_pdata *pdata, unsigned int pipe_id)
-{
- int ret;
-
- ret = libusb_control_transfer(pdata->hdl, LIBUSB_REQUEST_TYPE_VENDOR |
- LIBUSB_RECIPIENT_INTERFACE, IIO_USD_CMD_OPEN_PIPE,
- pipe_id, pdata->interface, NULL, 0, USB_PIPE_CTRL_TIMEOUT);
- if (ret < 0)
- return -(int) libusb_to_errno(ret);
- return 0;
-}
-
-static int usb_close_pipe(struct iio_context_pdata *pdata, unsigned int pipe_id)
-{
- int ret;
-
- ret = libusb_control_transfer(pdata->hdl, LIBUSB_REQUEST_TYPE_VENDOR |
- LIBUSB_RECIPIENT_INTERFACE, IIO_USD_CMD_CLOSE_PIPE,
- pipe_id, pdata->interface, NULL, 0, USB_PIPE_CTRL_TIMEOUT);
- if (ret < 0)
- return -(int) libusb_to_errno(ret);
- return 0;
-}
-
-static int usb_reserve_ep_unlocked(const struct iio_device *dev)
-{
- struct iio_context_pdata *pdata = dev->ctx->pdata;
- unsigned int i;
-
- for (i = 0; i < pdata->nb_ep_couples; i++) {
- struct iio_usb_ep_couple *ep = &pdata->io_endpoints[i];
-
- if (!ep->in_use) {
- ep->in_use = true;
-
- dev->pdata->io_ctx.ep = ep;
- dev->pdata->lock = ep->lock;
- return 0;
- }
- }
-
- return -EBUSY;
-}
-
-static void usb_free_ep_unlocked(const struct iio_device *dev)
-{
- struct iio_context_pdata *pdata = dev->ctx->pdata;
- unsigned int i;
-
- for (i = 0; i < pdata->nb_ep_couples; i++) {
- struct iio_usb_ep_couple *ep = &pdata->io_endpoints[i];
-
- if (ep->lock == dev->pdata->lock) {
- ep->in_use = false;
- return;
- }
- }
-}
-
-static int usb_open(const struct iio_device *dev,
- size_t samples_count, bool cyclic)
-{
- struct iio_context_pdata *ctx_pdata = dev->ctx->pdata;
- struct iio_device_pdata *pdata = dev->pdata;
- int ret = -EBUSY;
-
- iio_mutex_lock(ctx_pdata->ep_lock);
-
- pdata->io_ctx.cancelled = false;
-
- if (pdata->opened)
- goto out_unlock;
-
- ret = usb_reserve_ep_unlocked(dev);
- if (ret)
- goto out_unlock;
-
- ret = usb_open_pipe(ctx_pdata, pdata->io_ctx.ep->pipe_id);
- if (ret) {
- char err_str[1024];
-
- iio_strerror(-ret, err_str, sizeof(err_str));
- ERROR("Failed to open pipe: %s\n", err_str);
- usb_free_ep_unlocked(dev);
- goto out_unlock;
- }
-
- iio_mutex_lock(pdata->lock);
-
- ret = iiod_client_open_unlocked(ctx_pdata->iiod_client, &pdata->io_ctx,
- dev, samples_count, cyclic);
-
- if (!ret) {
- unsigned int remote_timeout =
- usb_calculate_remote_timeout(ctx_pdata->timeout_ms);
-
- ret = iiod_client_set_timeout(ctx_pdata->iiod_client,
- &pdata->io_ctx, remote_timeout);
- }
-
- pdata->opened = !ret;
-
- iio_mutex_unlock(pdata->lock);
-
- if (ret) {
- usb_close_pipe(ctx_pdata, pdata->io_ctx.ep->pipe_id);
- usb_free_ep_unlocked(dev);
- }
-
-out_unlock:
- iio_mutex_unlock(ctx_pdata->ep_lock);
- return ret;
-}
-
-static int usb_close(const struct iio_device *dev)
-{
- struct iio_context_pdata *ctx_pdata = dev->ctx->pdata;
- struct iio_device_pdata *pdata = dev->pdata;
- int ret = -EBADF;
-
- iio_mutex_lock(ctx_pdata->ep_lock);
- if (!pdata->opened)
- goto out_unlock;
-
- iio_mutex_lock(pdata->lock);
- ret = iiod_client_close_unlocked(ctx_pdata->iiod_client, &pdata->io_ctx,
- dev);
- pdata->opened = false;
-
- iio_mutex_unlock(pdata->lock);
-
- usb_close_pipe(ctx_pdata, pdata->io_ctx.ep->pipe_id);
-
- usb_free_ep_unlocked(dev);
-
-out_unlock:
- iio_mutex_unlock(ctx_pdata->ep_lock);
- return ret;
-}
-
-static ssize_t usb_read(const struct iio_device *dev, void *dst, size_t len,
- uint32_t *mask, size_t words)
-{
- struct iio_device_pdata *pdata = dev->pdata;
- ssize_t ret;
-
- iio_mutex_lock(pdata->lock);
- ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
- &pdata->io_ctx, dev, dst, len, mask, words);
- iio_mutex_unlock(pdata->lock);
-
- return ret;
-}
-
-static ssize_t usb_write(const struct iio_device *dev,
- const void *src, size_t len)
-{
- struct iio_device_pdata *pdata = dev->pdata;
- ssize_t ret;
-
- iio_mutex_lock(pdata->lock);
- ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
- &pdata->io_ctx, dev, src, len);
- iio_mutex_unlock(pdata->lock);
-
- return ret;
-}
-
-static ssize_t usb_read_dev_attr(const struct iio_device *dev,
- const char *attr, char *dst, size_t len, enum iio_attr_type type)
-{
- struct iio_context_pdata *pdata = dev->ctx->pdata;
-
- return iiod_client_read_attr(pdata->iiod_client,
- &pdata->io_ctx, dev, NULL, attr,
- dst, len, type);
-}
-
-static ssize_t usb_write_dev_attr(const struct iio_device *dev,
- const char *attr, const char *src, size_t len, enum iio_attr_type type)
-{
- struct iio_context_pdata *pdata = dev->ctx->pdata;
-
- return iiod_client_write_attr(pdata->iiod_client,
- &pdata->io_ctx, dev, NULL, attr,
- src, len, type);
-}
-
-static ssize_t usb_read_chn_attr(const struct iio_channel *chn,
- const char *attr, char *dst, size_t len)
-{
- struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
-
- return iiod_client_read_attr(pdata->iiod_client,
- &pdata->io_ctx, chn->dev, chn, attr,
- dst, len, false);
-}
-
-static ssize_t usb_write_chn_attr(const struct iio_channel *chn,
- const char *attr, const char *src, size_t len)
-{
- struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
-
- return iiod_client_write_attr(pdata->iiod_client,
- &pdata->io_ctx, chn->dev, chn, attr,
- src, len, false);
-}
-
-static int usb_set_kernel_buffers_count(const struct iio_device *dev,
- unsigned int nb_blocks)
-{
- struct iio_context_pdata *pdata = dev->ctx->pdata;
-
- return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
- &pdata->io_ctx, dev, nb_blocks);
-}
-
-static int usb_set_timeout(struct iio_context *ctx, unsigned int timeout)
-{
- struct iio_context_pdata *pdata = ctx->pdata;
- unsigned int remote_timeout = usb_calculate_remote_timeout(timeout);
- int ret;
-
- ret = iiod_client_set_timeout(pdata->iiod_client,
- &pdata->io_ctx, remote_timeout);
- if (!ret)
- pdata->timeout_ms = timeout;
-
- return ret;
-}
-
-static void usb_shutdown(struct iio_context *ctx)
-{
- unsigned int i;
-
- usb_io_context_exit(&ctx->pdata->io_ctx);
-
- for (i = 0; i < ctx->nb_devices; i++)
- usb_close(ctx->devices[i]);
-
- iio_mutex_destroy(ctx->pdata->lock);
- iio_mutex_destroy(ctx->pdata->ep_lock);
-
- for (i = 0; i < ctx->pdata->nb_ep_couples; i++)
- if (ctx->pdata->io_endpoints[i].lock)
- iio_mutex_destroy(ctx->pdata->io_endpoints[i].lock);
- if (ctx->pdata->io_endpoints)
- free(ctx->pdata->io_endpoints);
-
- for (i = 0; i < ctx->nb_devices; i++) {
- struct iio_device *dev = ctx->devices[i];
-
- usb_io_context_exit(&dev->pdata->io_ctx);
- free(dev->pdata);
- }
-
- iiod_client_destroy(ctx->pdata->iiod_client);
-
- usb_reset_pipes(ctx->pdata); /* Close everything */
-
- libusb_close(ctx->pdata->hdl);
- libusb_exit(ctx->pdata->ctx);
- free(ctx->pdata);
-}
-
-static int iio_usb_match_interface(const struct libusb_config_descriptor *desc,
- struct libusb_device_handle *hdl, unsigned int interface)
-{
- const struct libusb_interface *iface;
- unsigned int i;
-
- if (interface >= desc->bNumInterfaces)
- return -EINVAL;
-
- iface = &desc->interface[interface];
-
- for (i = 0; i < (unsigned int) iface->num_altsetting; i++) {
- const struct libusb_interface_descriptor *idesc =
- &iface->altsetting[i];
- char name[64];
- int ret;
-
- if (idesc->iInterface == 0)
- continue;
-
- ret = libusb_get_string_descriptor_ascii(hdl, idesc->iInterface,
- (unsigned char *) name, sizeof(name));
- if (ret < 0)
- return -(int) libusb_to_errno(ret);
-
- if (!strcmp(name, IIO_INTERFACE_NAME))
- return (int) i;
- }
-
- return -EPERM;
-}
-
-static int iio_usb_match_device(struct libusb_device *dev,
- struct libusb_device_handle *hdl,
- unsigned int *interface)
-{
- struct libusb_config_descriptor *desc;
- unsigned int i;
- int ret;
-
- ret = libusb_get_active_config_descriptor(dev, &desc);
- if (ret)
- return -(int) libusb_to_errno(ret);
-
- for (i = 0, ret = -EPERM; ret == -EPERM &&
- i < desc->bNumInterfaces; i++)
- ret = iio_usb_match_interface(desc, hdl, i);
-
- libusb_free_config_descriptor(desc);
- if (ret < 0)
- return ret;
-
- DEBUG("Found IIO interface on device %u:%u using interface %u\n",
- libusb_get_bus_number(dev),
- libusb_get_device_address(dev), i - 1);
-
- *interface = i - 1;
- return ret;
-}
-
-static void usb_cancel(const struct iio_device *dev)
-{
- struct iio_device_pdata *ppdata = dev->pdata;
-
- iio_mutex_lock(ppdata->io_ctx.lock);
- if (ppdata->io_ctx.transfer && !ppdata->io_ctx.cancelled)
- libusb_cancel_transfer(ppdata->io_ctx.transfer);
- ppdata->io_ctx.cancelled = true;
- iio_mutex_unlock(ppdata->io_ctx.lock);
-}
-
-static const struct iio_backend_ops usb_ops = {
- .get_version = usb_get_version,
- .open = usb_open,
- .close = usb_close,
- .read = usb_read,
- .write = usb_write,
- .read_device_attr = usb_read_dev_attr,
- .read_channel_attr = usb_read_chn_attr,
- .write_device_attr = usb_write_dev_attr,
- .write_channel_attr = usb_write_chn_attr,
- .set_kernel_buffers_count = usb_set_kernel_buffers_count,
- .set_timeout = usb_set_timeout,
- .shutdown = usb_shutdown,
-
- .cancel = usb_cancel,
-};
-
-static void LIBUSB_CALL sync_transfer_cb(struct libusb_transfer *transfer)
-{
- int *completed = transfer->user_data;
- *completed = 1;
-}
-
-static int usb_sync_transfer(struct iio_context_pdata *pdata,
- struct iio_usb_io_context *io_ctx, unsigned int ep_type,
- char *data, size_t len, int *transferred)
-{
- unsigned int ep;
- struct libusb_transfer *transfer;
- int completed = 0;
- int ret;
-
- /*
- * If the size of the data to transfer is too big, the
- * IOCTL_USBFS_SUBMITURB ioctl (called by libusb) might fail with
- * errno set to ENOMEM, as the kernel might use contiguous allocation
- * for the URB if the driver doesn't support scatter-gather.
- * To prevent that, we support URBs of 1 MiB maximum. The iiod-client
- * code will handle this properly and ask for a new transfer.
- */
- if (len > 1 * 1024 * 1024)
- len = 1 * 1024 * 1024;
-
- if (ep_type == LIBUSB_ENDPOINT_IN)
- ep = io_ctx->ep->addr_in;
- else
- ep = io_ctx->ep->addr_out;
-
- /*
- * For cancellation support the check whether the buffer has already been
- * cancelled and the allocation as well as the assignment of the new
- * transfer needs to happen in one atomic step. Otherwise it is possible
- * that the cancellation is missed and transfer is not aborted.
- */
- iio_mutex_lock(io_ctx->lock);
- if (io_ctx->cancelled) {
- ret = -EBADF;
- goto unlock;
- }
-
- transfer = libusb_alloc_transfer(0);
- if (!transfer) {
- ret = -ENOMEM;
- goto unlock;
- }
-
- transfer->user_data = &completed;
-
- libusb_fill_bulk_transfer(transfer, pdata->hdl, ep,
- (unsigned char *) data, (int) len, sync_transfer_cb,
- &completed, pdata->timeout_ms);
- transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
-
- ret = libusb_submit_transfer(transfer);
- if (ret) {
- ret = -(int) libusb_to_errno(ret);
- libusb_free_transfer(transfer);
- goto unlock;
- }
-
- io_ctx->transfer = transfer;
-unlock:
- iio_mutex_unlock(io_ctx->lock);
- if (ret)
- return ret;
-
- while (!completed) {
- ret = libusb_handle_events_completed(pdata->ctx, &completed);
- if (ret < 0) {
- if (ret == LIBUSB_ERROR_INTERRUPTED)
- continue;
- libusb_cancel_transfer(transfer);
- continue;
- }
- }
-
- switch (transfer->status) {
- case LIBUSB_TRANSFER_COMPLETED:
- *transferred = transfer->actual_length;
- ret = 0;
- break;
- case LIBUSB_TRANSFER_TIMED_OUT:
- ret = -ETIMEDOUT;
- break;
- case LIBUSB_TRANSFER_STALL:
- ret = -EPIPE;
- break;
- case LIBUSB_TRANSFER_NO_DEVICE:
- ret = -ENODEV;
- break;
- case LIBUSB_TRANSFER_CANCELLED:
- ret = -EBADF;
- break;
- default:
- ret = -EIO;
- break;
- }
-
- /* Same as above. This needs to be atomic in regards to usb_cancel(). */
- iio_mutex_lock(io_ctx->lock);
- io_ctx->transfer = NULL;
- iio_mutex_unlock(io_ctx->lock);
-
- libusb_free_transfer(transfer);
-
- return ret;
-}
-
-static ssize_t write_data_sync(struct iio_context_pdata *pdata,
- void *ep, const char *data, size_t len)
-{
- int transferred, ret;
-
- ret = usb_sync_transfer(pdata, ep, LIBUSB_ENDPOINT_OUT, (char *) data,
- len, &transferred);
- if (ret)
- return ret;
- else
- return (ssize_t) transferred;
-}
-
-static ssize_t read_data_sync(struct iio_context_pdata *pdata,
- void *ep, char *buf, size_t len)
-{
- int transferred, ret;
-
- ret = usb_sync_transfer(pdata, ep, LIBUSB_ENDPOINT_IN, buf, len,
- &transferred);
- if (ret)
- return ret;
- else
- return transferred;
-}
-
-static const struct iiod_client_ops usb_iiod_client_ops = {
- .write = write_data_sync,
- .read = read_data_sync,
- .read_line = read_data_sync,
-};
-
-static int usb_verify_eps(const struct libusb_interface_descriptor *iface)
-{
- unsigned int i, eps = iface->bNumEndpoints;
-
- /* Check that we have an even number of endpoints, and that input/output
- * endpoints are interleaved */
-
- if (eps < 2 || eps % 2)
- return -EINVAL;
-
- for (i = 0; i < eps; i += 2) {
- if (!(iface->endpoint[i + 0].bEndpointAddress
- & LIBUSB_ENDPOINT_IN))
- return -EINVAL;
-
- if (iface->endpoint[i + 1].bEndpointAddress
- & LIBUSB_ENDPOINT_IN)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int usb_populate_context_attrs(struct iio_context *ctx,
- libusb_device *dev, libusb_device_handle *hdl)
-{
- struct libusb_device_descriptor dev_desc;
- char buffer[64];
- unsigned int i;
- int ret;
-
- struct {
- const char *attr;
- uint8_t idx;
- } attrs[3];
-
- libusb_get_device_descriptor(dev, &dev_desc);
-
- attrs[0].attr = "usb,vendor";
- attrs[0].idx = dev_desc.iManufacturer;
- attrs[1].attr = "usb,product";
- attrs[1].idx = dev_desc.iProduct;
- attrs[2].attr = "usb,serial";
- attrs[2].idx = dev_desc.iSerialNumber;
-
- iio_snprintf(buffer, sizeof(buffer), "%04hx", dev_desc.idVendor);
- ret = iio_context_add_attr(ctx, "usb,idVendor", buffer);
- if (ret < 0)
- return ret;
-
- iio_snprintf(buffer, sizeof(buffer), "%04hx", dev_desc.idProduct);
- ret = iio_context_add_attr(ctx, "usb,idProduct", buffer);
- if (ret < 0)
- return ret;
-
- iio_snprintf(buffer, sizeof(buffer), "%1hhx.%1hhx",
- (unsigned char)((dev_desc.bcdUSB >> 8) & 0xf),
- (unsigned char)((dev_desc.bcdUSB >> 4) & 0xf));
- ret = iio_context_add_attr(ctx, "usb,release", buffer);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < ARRAY_SIZE(attrs); i++) {
- if (attrs[i].idx) {
- ret = libusb_get_string_descriptor_ascii(hdl,
- attrs[i].idx, (unsigned char *) buffer,
- sizeof(buffer));
- if (ret < 0)
- return -(int) libusb_to_errno(ret);
-
- ret = iio_context_add_attr(ctx, attrs[i].attr, buffer);
- if (ret < 0)
- return ret;
- }
- }
-
-#ifdef HAS_LIBUSB_GETVERSION
- /*
- * libusb_get_version was added 2012-04-17: v1.0.10,
- * before LIBUSB_API_VERSION was added - Jan 8, 2014
- * so, you can't use that to determine if it is here
- */
- {
- struct libusb_version const *ver = libusb_get_version();
- iio_snprintf(buffer, sizeof(buffer), "%i.%i.%i.%i%s",
- ver->major, ver->minor, ver->micro,
- ver->nano, ver->rc);
- ret = iio_context_add_attr(ctx, "usb,libusb", buffer);
- if (ret < 0)
- return ret;
- }
-#endif
- return 0;
-}
-
-struct iio_context * usb_create_context(unsigned int bus,
- unsigned int address, unsigned int interface)
-{
- libusb_context *usb_ctx;
- libusb_device_handle *hdl;
- const struct libusb_interface_descriptor *iface;
- libusb_device *usb_dev;
- struct libusb_config_descriptor *conf_desc;
- libusb_device **device_list;
- struct iio_context *ctx;
- struct iio_context_pdata *pdata;
- char err_str[1024];
- unsigned int i;
- int ret;
-
- pdata = zalloc(sizeof(*pdata));
- if (!pdata) {
- ERROR("Unable to allocate pdata\n");
- ret = -ENOMEM;
- goto err_set_errno;
- }
-
- pdata->lock = iio_mutex_create();
- if (!pdata->lock) {
- ERROR("Unable to create mutex\n");
- ret = -ENOMEM;
- goto err_free_pdata;
- }
-
- pdata->ep_lock = iio_mutex_create();
- if (!pdata->ep_lock) {
- ERROR("Unable to create mutex\n");
- ret = -ENOMEM;
- goto err_destroy_mutex;
- }
-
- pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
- &usb_iiod_client_ops);
- if (!pdata->iiod_client) {
- ERROR("Unable to create IIOD client\n");
- ret = -errno;
- goto err_destroy_ep_mutex;
- }
-
- ret = libusb_init(&usb_ctx);
- if (ret) {
- ret = -(int) libusb_to_errno(ret);
- ERROR("Unable to init libusb: %i\n", ret);
- goto err_destroy_iiod_client;
- }
-
- libusb_get_device_list(usb_ctx, &device_list);
-
- usb_dev = NULL;
-
- for (i = 0; device_list[i]; i++) {
- libusb_device *dev = device_list[i];
-
- if (bus == libusb_get_bus_number(dev) &&
- address == libusb_get_device_address(dev)) {
- usb_dev = dev;
-
- ret = libusb_open(usb_dev, &hdl);
- /*
- * Workaround for libusb on Windows >= 8.1. A device
- * might appear twice in the list with one device being
- * bogus and only partially initialized. libusb_open()
- * returns LIBUSB_ERROR_NOT_SUPPORTED for such devices,
- * which should never happen for normal devices. So if
- * we find such a device skip it and keep looking.
- */
- if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
- WARNING("Skipping broken USB device. Please upgrade libusb.\n");
- usb_dev = NULL;
- continue;
- }
-
- break;
- }
- }
-
- libusb_free_device_list(device_list, true);
-
- if (!usb_dev) {
- ret = -ENODEV;
- goto err_libusb_exit;
- }
-
- if (ret) {
- ret = -(int) libusb_to_errno(ret);
- ERROR("Unable to open device\n");
- goto err_libusb_exit;
- }
-
-#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000016)
- libusb_set_auto_detach_kernel_driver(hdl, true);
-#endif
-
- ret = libusb_claim_interface(hdl, interface);
- if (ret) {
- ret = -(int) libusb_to_errno(ret);
- ERROR("Unable to claim interface %u:%u:%u: %i\n",
- bus, address, interface, ret);
- goto err_libusb_close;
- }
-
- ret = libusb_get_active_config_descriptor(usb_dev, &conf_desc);
- if (ret) {
- ret = -(int) libusb_to_errno(ret);
- ERROR("Unable to get config descriptor: %i\n", ret);
- goto err_libusb_close;
- }
-
- iface = &conf_desc->interface[interface].altsetting[0];
-
- ret = usb_verify_eps(iface);
- if (ret) {
- ERROR("Invalid configuration of endpoints\n");
- goto err_free_config_descriptor;
- }
-
- pdata->nb_ep_couples = iface->bNumEndpoints / 2;
-
- DEBUG("Found %hhu usable i/o endpoint couples\n", pdata->nb_ep_couples);
-
- pdata->io_endpoints = calloc(pdata->nb_ep_couples,
- sizeof(*pdata->io_endpoints));
- if (!pdata->io_endpoints) {
- ERROR("Unable to allocate endpoints\n");
- ret = -ENOMEM;
- goto err_free_config_descriptor;
- }
-
- for (i = 0; i < pdata->nb_ep_couples; i++) {
- struct iio_usb_ep_couple *ep = &pdata->io_endpoints[i];
-
- ep->addr_in = iface->endpoint[i * 2 + 0].bEndpointAddress;
- ep->addr_out = iface->endpoint[i * 2 + 1].bEndpointAddress;
- ep->pipe_id = i;
-
- DEBUG("Couple %i with endpoints 0x%x / 0x%x\n", i,
- ep->addr_in, ep->addr_out);
-
- ep->lock = iio_mutex_create();
- if (!ep->lock) {
- ERROR("Unable to create mutex\n");
- ret = -ENOMEM;
- goto err_free_endpoints;
- }
- }
-
- pdata->ctx = usb_ctx;
- pdata->hdl = hdl;
- pdata->timeout_ms = DEFAULT_TIMEOUT_MS;
- pdata->interface = interface;
-
- ret = usb_io_context_init(&pdata->io_ctx);
- if (ret)
- goto err_free_endpoints;
-
- /* We reserve the first I/O endpoint couple for global operations */
- pdata->io_ctx.ep = &pdata->io_endpoints[0];
- pdata->io_ctx.ep->in_use = true;
-
- ret = usb_reset_pipes(pdata);
- if (ret) {
- iio_strerror(-ret, err_str, sizeof(err_str));
- ERROR("Failed to reset pipes: %s\n", err_str);
- goto err_io_context_exit;
- }
-
- ret = usb_open_pipe(pdata, 0);
- if (ret) {
- iio_strerror(-ret, err_str, sizeof(err_str));
- ERROR("Failed to open control pipe: %s\n", err_str);
- goto err_io_context_exit;
- }
-
- ctx = iiod_client_create_context(pdata->iiod_client, &pdata->io_ctx);
- if (!ctx) {
- ret = -errno;
- goto err_reset_pipes;
- }
-
- libusb_free_config_descriptor(conf_desc);
-
- ctx->name = "usb";
- ctx->ops = &usb_ops;
- ctx->pdata = pdata;
-
- for (i = 0; i < ctx->nb_devices; i++) {
- struct iio_device *dev = ctx->devices[i];
-
- dev->pdata = zalloc(sizeof(*dev->pdata));
- if (!dev->pdata) {
- ERROR("Unable to allocate memory\n");
- ret = -ENOMEM;
- goto err_context_destroy;
- }
-
- ret = usb_io_context_init(&dev->pdata->io_ctx);
- if (ret)
- goto err_context_destroy;
- }
-
- ret = usb_populate_context_attrs(ctx, usb_dev, hdl);
- if (ret < 0)
- goto err_context_destroy;
-
- return ctx;
-
-err_context_destroy:
- iio_context_destroy(ctx);
- errno = -ret;
- return NULL;
-
-err_reset_pipes:
- usb_reset_pipes(pdata); /* Close everything */
-err_io_context_exit:
- usb_io_context_exit(&pdata->io_ctx);
-err_free_endpoints:
- for (i = 0; i < pdata->nb_ep_couples; i++)
- if (pdata->io_endpoints[i].lock)
- iio_mutex_destroy(pdata->io_endpoints[i].lock);
- if (pdata->io_endpoints)
- free(pdata->io_endpoints);
-err_free_config_descriptor:
- libusb_free_config_descriptor(conf_desc);
-err_libusb_close:
- libusb_close(hdl);
-err_libusb_exit:
- libusb_exit(usb_ctx);
-err_destroy_iiod_client:
- iiod_client_destroy(pdata->iiod_client);
-err_destroy_ep_mutex:
- iio_mutex_destroy(pdata->ep_lock);
-err_destroy_mutex:
- iio_mutex_destroy(pdata->lock);
-err_free_pdata:
- free(pdata);
-err_set_errno:
- errno = -ret;
- return NULL;
-}
-
-struct iio_context * usb_create_context_from_uri(const char *uri)
-{
- long bus, address, interface;
- char *end;
- const char *ptr;
-
- if (strncmp(uri, "usb:", sizeof("usb:") - 1) != 0)
- goto err_bad_uri;
-
- ptr = (const char *) ((uintptr_t) uri + sizeof("usb:") - 1);
- if (!isdigit(*ptr))
- goto err_bad_uri;
-
- bus = strtol(ptr, &end, 10);
- if (ptr == end || *end != '.')
- goto err_bad_uri;
-
- ptr = (const char *) ((uintptr_t) end + 1);
- if (!isdigit(*ptr))
- goto err_bad_uri;
-
- address = strtol(ptr, &end, 10);
- if (ptr == end)
- goto err_bad_uri;
-
- if (*end == '\0') {
- interface = 0;
- } else if (*end == '.') {
- ptr = (const char *) ((uintptr_t) end + 1);
- if (!isdigit(*ptr))
- goto err_bad_uri;
-
- interface = strtol(ptr, &end, 10);
- if (ptr == end || *end != '\0')
- goto err_bad_uri;
- } else {
- goto err_bad_uri;
- }
-
- if (bus < 0 || address < 0 || interface < 0)
- goto err_bad_uri;
-
- return usb_create_context((unsigned int) bus,
- (unsigned int) address, (unsigned int) interface);
-
-err_bad_uri:
- ERROR("Bad URI: \'%s\'\n", uri);
- errno = EINVAL;
- return NULL;
-}
-
-static int usb_fill_context_info(struct iio_context_info *info,
- struct libusb_device *dev, struct libusb_device_handle *hdl,
- unsigned int interface)
-{
- struct libusb_device_descriptor desc;
- char manufacturer[64], product[64], serial[64];
- char uri[sizeof("usb:127.255.255")];
- char description[sizeof(manufacturer) + sizeof(product) +
- sizeof(serial) + sizeof("0000:0000 ( ), serial=")];
- int ret;
-
- libusb_get_device_descriptor(dev, &desc);
-
- iio_snprintf(uri, sizeof(uri), "usb:%d.%d.%u",
- libusb_get_bus_number(dev), libusb_get_device_address(dev),
- interface);
-
- if (desc.iManufacturer == 0) {
- manufacturer[0] = '\0';
- } else {
- ret = libusb_get_string_descriptor_ascii(hdl,
- desc.iManufacturer,
- (unsigned char *) manufacturer,
- sizeof(manufacturer));
- if (ret < 0)
- manufacturer[0] = '\0';
- }
-
- if (desc.iProduct == 0) {
- product[0] = '\0';
- } else {
- ret = libusb_get_string_descriptor_ascii(hdl,
- desc.iProduct, (unsigned char *) product,
- sizeof(product));
- if (ret < 0)
- product[0] = '\0';
- }
-
- if (desc.iSerialNumber == 0) {
- serial[0] = '\0';
- } else {
- ret = libusb_get_string_descriptor_ascii(hdl,
- desc.iSerialNumber, (unsigned char *) serial,
- sizeof(serial));
- if (ret < 0)
- serial[0] = '\0';
- }
-
- iio_snprintf(description, sizeof(description),
- "%04x:%04x (%s %s), serial=%s", desc.idVendor,
- desc.idProduct, manufacturer, product, serial);
-
- info->uri = iio_strdup(uri);
- if (!info->uri)
- return -ENOMEM;
-
- info->description = iio_strdup(description);
- if (!info->description)
- return -ENOMEM;
-
- return 0;
-}
-
-struct iio_scan_backend_context {
- libusb_context *ctx;
-};
-
-struct iio_scan_backend_context * usb_context_scan_init(void)
-{
- struct iio_scan_backend_context *ctx;
- int ret;
-
- ctx = malloc(sizeof(*ctx));
- if (!ctx) {
- errno = ENOMEM;
- return NULL;
- }
-
- ret = libusb_init(&ctx->ctx);
- if (ret) {
- free(ctx);
- errno = (int) libusb_to_errno(ret);
- return NULL;
- }
-
- return ctx;
-}
-
-void usb_context_scan_free(struct iio_scan_backend_context *ctx)
-{
- libusb_exit(ctx->ctx);
- free(ctx);
-}
-
-int usb_context_scan(struct iio_scan_backend_context *ctx,
- struct iio_scan_result *scan_result)
-{
- struct iio_context_info **info;
- libusb_device **device_list;
- unsigned int i;
- int ret;
-
- ret = libusb_get_device_list(ctx->ctx, &device_list);
- if (ret < 0)
- return -(int) libusb_to_errno(ret);
-
- for (i = 0; device_list[i]; i++) {
- struct libusb_device_handle *hdl;
- struct libusb_device *dev = device_list[i];
- unsigned int interface = 0;
-
- ret = libusb_open(dev, &hdl);
- if (ret)
- continue;
-
- if (!iio_usb_match_device(dev, hdl, &interface)) {
- info = iio_scan_result_add(scan_result, 1);
- if (!info)
- ret = -ENOMEM;
- else
- ret = usb_fill_context_info(*info, dev, hdl,
- interface);
- }
-
- libusb_close(hdl);
- if (ret < 0)
- goto cleanup_free_device_list;
- }
-
- ret = 0;
-
-cleanup_free_device_list:
- libusb_free_device_list(device_list, true);
- return ret;
-}