blob: 922dea80ae0a2d272eb4e6ba54b06ba7e6522f66 [file] [log] [blame]
Paul Cercueile06f4ce2015-04-20 12:59:31 +02001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2015 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
19#include "debug.h"
20#include "iio-lock.h"
21#include "iio-private.h"
22#include "iiod-client.h"
23
24#include <errno.h>
25#include <libusb-1.0/libusb.h>
26#include <stdbool.h>
27#include <string.h>
28
29#define DEFAULT_TIMEOUT_MS 5000
30
31/* Endpoint for non-streaming operations */
32#define EP_OPS 1
33
Paul Cercueil4acd6042015-11-30 12:10:43 +010034/* Endpoint for input devices */
35#define EP_INPUT 2
36
37/* Endpoint for output devices */
38#define EP_OUTPUT 3
39
Paul Cercueile06f4ce2015-04-20 12:59:31 +020040struct iio_context_pdata {
41 libusb_context *ctx;
42 libusb_device_handle *hdl;
43
44 struct iiod_client *iiod_client;
45
46 /* Lock for non-streaming operations */
47 struct iio_mutex *lock;
Paul Cercueil4acd6042015-11-30 12:10:43 +010048
49 /* Locks for input/output devices */
50 struct iio_mutex *i_lock, *o_lock;
51};
52
53struct iio_device_pdata {
54 bool is_tx;
55 struct iio_mutex *lock;
56
57 bool opened;
58 unsigned int ep;
Paul Cercueile06f4ce2015-04-20 12:59:31 +020059};
60
61static const unsigned int libusb_to_errno_codes[] = {
62 [- LIBUSB_ERROR_INVALID_PARAM] = EINVAL,
63 [- LIBUSB_ERROR_ACCESS] = EACCES,
64 [- LIBUSB_ERROR_NO_DEVICE] = ENODEV,
65 [- LIBUSB_ERROR_NOT_FOUND] = ENXIO,
66 [- LIBUSB_ERROR_BUSY] = EBUSY,
67 [- LIBUSB_ERROR_TIMEOUT] = ETIMEDOUT,
68 [- LIBUSB_ERROR_OVERFLOW] = EIO,
69 [- LIBUSB_ERROR_PIPE] = EPIPE,
70 [- LIBUSB_ERROR_INTERRUPTED] = EINTR,
71 [- LIBUSB_ERROR_NO_MEM] = ENOMEM,
72 [- LIBUSB_ERROR_NOT_SUPPORTED] = ENOSYS,
73};
74
75static unsigned int libusb_to_errno(int error)
76{
77 switch ((enum libusb_error) error) {
78 case LIBUSB_ERROR_INVALID_PARAM:
79 case LIBUSB_ERROR_ACCESS:
80 case LIBUSB_ERROR_NO_DEVICE:
81 case LIBUSB_ERROR_NOT_FOUND:
82 case LIBUSB_ERROR_BUSY:
83 case LIBUSB_ERROR_TIMEOUT:
84 case LIBUSB_ERROR_PIPE:
85 case LIBUSB_ERROR_INTERRUPTED:
86 case LIBUSB_ERROR_NO_MEM:
87 case LIBUSB_ERROR_NOT_SUPPORTED:
88 return libusb_to_errno_codes[- (int) error];
89 case LIBUSB_ERROR_IO:
90 case LIBUSB_ERROR_OTHER:
91 case LIBUSB_ERROR_OVERFLOW:
92 default:
93 return EIO;
94 }
95}
96
Paul Cercueilc11737c2015-11-26 14:44:46 +010097static int usb_get_version(const struct iio_context *ctx,
98 unsigned int *major, unsigned int *minor, char git_tag[8])
99{
100 return iiod_client_get_version(ctx->pdata->iiod_client,
101 EP_OPS, major, minor, git_tag);
102}
103
Paul Cercueil4acd6042015-11-30 12:10:43 +0100104static int usb_open(const struct iio_device *dev,
105 size_t samples_count, bool cyclic)
106{
107 struct iio_device_pdata *pdata = dev->pdata;
108 int ret = -EBUSY;
109
110 iio_mutex_lock(pdata->lock);
111
112 if (!pdata->opened) {
113 ret = iiod_client_open_unlocked(dev->ctx->pdata->iiod_client,
114 pdata->ep, dev, samples_count, cyclic);
115 pdata->opened = !ret;
116 }
117
118 iio_mutex_unlock(pdata->lock);
119 return ret;
120}
121
122static int usb_close(const struct iio_device *dev)
123{
124 struct iio_device_pdata *pdata = dev->pdata;
125 int ret = -EBADF;
126
127 iio_mutex_lock(pdata->lock);
128 if (pdata->opened) {
129 ret = iiod_client_close_unlocked(dev->ctx->pdata->iiod_client,
130 pdata->ep, dev);
131 pdata->opened = false;
132 }
133
134 iio_mutex_unlock(pdata->lock);
135 return ret;
136}
137
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100138static ssize_t usb_read_dev_attr(const struct iio_device *dev,
139 const char *attr, char *dst, size_t len, bool is_debug)
140{
141 struct iio_context_pdata *pdata = dev->ctx->pdata;
142
143 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, dev,
144 NULL, attr, dst, len, is_debug);
145}
146
147static ssize_t usb_write_dev_attr(const struct iio_device *dev,
148 const char *attr, const char *src, size_t len, bool is_debug)
149{
150 struct iio_context_pdata *pdata = dev->ctx->pdata;
151
152 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, dev,
153 NULL, attr, src, len, is_debug);
154}
155
156static ssize_t usb_read_chn_attr(const struct iio_channel *chn,
157 const char *attr, char *dst, size_t len)
158{
159 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
160
161 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, chn->dev,
162 chn, attr, dst, len, false);
163}
164
165static ssize_t usb_write_chn_attr(const struct iio_channel *chn,
166 const char *attr, const char *src, size_t len)
167{
168 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
169
170 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, chn->dev,
171 chn, attr, src, len, false);
172}
173
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100174static int usb_set_kernel_buffers_count(const struct iio_device *dev,
175 unsigned int nb_blocks)
176{
177 struct iio_context_pdata *pdata = dev->ctx->pdata;
178
179 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
180 EP_OPS, dev, nb_blocks);
181}
182
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200183static void usb_shutdown(struct iio_context *ctx)
184{
185 iio_mutex_destroy(ctx->pdata->lock);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100186 iio_mutex_destroy(ctx->pdata->o_lock);
187 iio_mutex_destroy(ctx->pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200188
189 iiod_client_destroy(ctx->pdata->iiod_client);
190
191 libusb_close(ctx->pdata->hdl);
192 libusb_exit(ctx->pdata->ctx);
193}
194
195static const struct iio_backend_ops usb_ops = {
Paul Cercueilc11737c2015-11-26 14:44:46 +0100196 .get_version = usb_get_version,
Paul Cercueil4acd6042015-11-30 12:10:43 +0100197 .open = usb_open,
198 .close = usb_close,
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100199 .read_device_attr = usb_read_dev_attr,
200 .read_channel_attr = usb_read_chn_attr,
201 .write_device_attr = usb_write_dev_attr,
202 .write_channel_attr = usb_write_chn_attr,
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100203 .set_kernel_buffers_count = usb_set_kernel_buffers_count,
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200204 .shutdown = usb_shutdown,
205};
206
207static ssize_t write_data_sync(struct iio_context_pdata *pdata,
208 int ep, const char *data, size_t len)
209{
210 int transferred, ret;
211
212 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_OUT,
213 (char *) data, len, &transferred, DEFAULT_TIMEOUT_MS);
214 if (ret)
215 return -libusb_to_errno(ret);
216 else
217 return transferred != len ? -EIO : len;
218}
219
220static ssize_t read_data_sync(struct iio_context_pdata *pdata,
221 int ep, char *buf, size_t len)
222{
223 int transferred, ret;
224
225 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
226 buf, len, &transferred, DEFAULT_TIMEOUT_MS);
227 if (ret)
228 return -libusb_to_errno(ret);
229 else
230 return transferred;
231}
232
233static struct iiod_client_ops usb_iiod_client_ops = {
234 .write = write_data_sync,
235 .read = read_data_sync,
236 .read_line = read_data_sync,
237};
238
239struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
240{
241 libusb_context *usb_ctx;
242 libusb_device_handle *hdl;
243 struct iio_context *ctx;
244 struct iio_context_pdata *pdata;
245 unsigned int i;
246 int ret;
247
248 pdata = calloc(1, sizeof(*pdata));
249 if (!pdata) {
250 ERROR("Unable to allocate pdata\n");
251 ret = -ENOMEM;
252 goto err_set_errno;
253 }
254
255 pdata->lock = iio_mutex_create();
256 if (!pdata->lock) {
257 ERROR("Unable to create mutex\n");
258 ret = -ENOMEM;
259 goto err_free_pdata;
260 }
261
Paul Cercueil4acd6042015-11-30 12:10:43 +0100262 pdata->i_lock = iio_mutex_create();
263 if (!pdata->i_lock) {
264 ERROR("Unable to create mutex\n");
265 ret = -ENOMEM;
266 goto err_destroy_mutex;
267 }
268
269 pdata->o_lock = iio_mutex_create();
270 if (!pdata->o_lock) {
271 ERROR("Unable to create mutex\n");
272 ret = -ENOMEM;
273 goto err_destroy_i_mutex;
274 }
275
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200276 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
277 &usb_iiod_client_ops);
278 if (!pdata->iiod_client) {
279 ERROR("Unable to create IIOD client\n");
280 ret = -errno;
Paul Cercueil4acd6042015-11-30 12:10:43 +0100281 goto err_destroy_o_mutex;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200282 }
283
284 ret = libusb_init(&usb_ctx);
285 if (ret) {
286 ret = -libusb_to_errno(ret);
287 ERROR("Unable to init libusb: %i\n", ret);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100288 goto err_destroy_iiod_client;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200289 }
290
291 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
292 if (!hdl) {
293 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
294 ret = -ENODEV;
295 goto err_libusb_exit;
296 }
297
298 libusb_set_auto_detach_kernel_driver(hdl, true);
299
300 ret = libusb_claim_interface(hdl, 0);
301 if (ret) {
302 ret = -libusb_to_errno(ret);
303 ERROR("Unable to claim interface 0: %i\n", ret);
304 goto err_libusb_close;
305 }
306
307 pdata->ctx = usb_ctx;
308 pdata->hdl = hdl;
309
310 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
311 if (!ctx)
312 goto err_libusb_close;
313
314 ctx->name = "usb";
315 ctx->ops = &usb_ops;
316 ctx->pdata = pdata;
317
318 DEBUG("Initializing context...\n");
319 ret = iio_context_init(ctx);
320 if (ret < 0)
321 goto err_context_destroy;
322
Paul Cercueil4acd6042015-11-30 12:10:43 +0100323 for (i = 0; i < ctx->nb_devices; i++) {
324 struct iio_device *dev = ctx->devices[i];
325
326 dev->pdata = calloc(1, sizeof(*dev->pdata));
327 if (!dev->pdata) {
328 ERROR("Unable to allocate memory\n");
329 ret = -ENOMEM;
330 goto err_context_destroy;
331 }
332
333 dev->pdata->is_tx = iio_device_is_tx(dev);
334
335 if (dev->pdata->is_tx) {
336 dev->pdata->lock = pdata->o_lock;
337 dev->pdata->ep = EP_OUTPUT;
338 } else {
339 dev->pdata->lock = pdata->i_lock;
340 dev->pdata->ep = EP_INPUT;
341 }
342 }
343
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200344 return ctx;
345
346err_context_destroy:
347 iio_context_destroy(ctx);
348 errno = -ret;
349 return NULL;
350
351err_libusb_close:
352 libusb_close(hdl);
353err_libusb_exit:
354 libusb_exit(usb_ctx);
355err_destroy_iiod_client:
356 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100357err_destroy_o_mutex:
358 iio_mutex_destroy(pdata->o_lock);
359err_destroy_i_mutex:
360 iio_mutex_destroy(pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200361err_destroy_mutex:
362 iio_mutex_destroy(pdata->lock);
363err_free_pdata:
364 free(pdata);
365err_set_errno:
366 errno = -ret;
367 return NULL;
368}