blob: 078a6fed219c5bf96a4df85abb1d037a6c4c01a3 [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;
Paul Cercueil7a988892015-12-03 12:39:20 +010051
52 unsigned int timeout_ms;
Paul Cercueil4acd6042015-11-30 12:10:43 +010053};
54
55struct iio_device_pdata {
56 bool is_tx;
57 struct iio_mutex *lock;
58
59 bool opened;
60 unsigned int ep;
Paul Cercueile06f4ce2015-04-20 12:59:31 +020061};
62
63static const unsigned int libusb_to_errno_codes[] = {
64 [- LIBUSB_ERROR_INVALID_PARAM] = EINVAL,
65 [- LIBUSB_ERROR_ACCESS] = EACCES,
66 [- LIBUSB_ERROR_NO_DEVICE] = ENODEV,
67 [- LIBUSB_ERROR_NOT_FOUND] = ENXIO,
68 [- LIBUSB_ERROR_BUSY] = EBUSY,
69 [- LIBUSB_ERROR_TIMEOUT] = ETIMEDOUT,
70 [- LIBUSB_ERROR_OVERFLOW] = EIO,
71 [- LIBUSB_ERROR_PIPE] = EPIPE,
72 [- LIBUSB_ERROR_INTERRUPTED] = EINTR,
73 [- LIBUSB_ERROR_NO_MEM] = ENOMEM,
74 [- LIBUSB_ERROR_NOT_SUPPORTED] = ENOSYS,
75};
76
77static unsigned int libusb_to_errno(int error)
78{
79 switch ((enum libusb_error) error) {
80 case LIBUSB_ERROR_INVALID_PARAM:
81 case LIBUSB_ERROR_ACCESS:
82 case LIBUSB_ERROR_NO_DEVICE:
83 case LIBUSB_ERROR_NOT_FOUND:
84 case LIBUSB_ERROR_BUSY:
85 case LIBUSB_ERROR_TIMEOUT:
86 case LIBUSB_ERROR_PIPE:
87 case LIBUSB_ERROR_INTERRUPTED:
88 case LIBUSB_ERROR_NO_MEM:
89 case LIBUSB_ERROR_NOT_SUPPORTED:
90 return libusb_to_errno_codes[- (int) error];
91 case LIBUSB_ERROR_IO:
92 case LIBUSB_ERROR_OTHER:
93 case LIBUSB_ERROR_OVERFLOW:
94 default:
95 return EIO;
96 }
97}
98
Paul Cercueilc11737c2015-11-26 14:44:46 +010099static int usb_get_version(const struct iio_context *ctx,
100 unsigned int *major, unsigned int *minor, char git_tag[8])
101{
102 return iiod_client_get_version(ctx->pdata->iiod_client,
103 EP_OPS, major, minor, git_tag);
104}
105
Paul Cercueil4acd6042015-11-30 12:10:43 +0100106static int usb_open(const struct iio_device *dev,
107 size_t samples_count, bool cyclic)
108{
109 struct iio_device_pdata *pdata = dev->pdata;
110 int ret = -EBUSY;
111
112 iio_mutex_lock(pdata->lock);
113
114 if (!pdata->opened) {
115 ret = iiod_client_open_unlocked(dev->ctx->pdata->iiod_client,
116 pdata->ep, dev, samples_count, cyclic);
117 pdata->opened = !ret;
118 }
119
120 iio_mutex_unlock(pdata->lock);
121 return ret;
122}
123
124static int usb_close(const struct iio_device *dev)
125{
126 struct iio_device_pdata *pdata = dev->pdata;
127 int ret = -EBADF;
128
129 iio_mutex_lock(pdata->lock);
130 if (pdata->opened) {
131 ret = iiod_client_close_unlocked(dev->ctx->pdata->iiod_client,
132 pdata->ep, dev);
133 pdata->opened = false;
134 }
135
136 iio_mutex_unlock(pdata->lock);
137 return ret;
138}
139
Paul Cercueil04841832015-12-02 11:58:33 +0100140static ssize_t usb_read(const struct iio_device *dev, void *dst, size_t len,
141 uint32_t *mask, size_t words)
142{
143 struct iio_device_pdata *pdata = dev->pdata;
144 ssize_t ret;
145
146 iio_mutex_lock(pdata->lock);
147 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
148 pdata->ep, dev, dst, len, mask, words);
149 iio_mutex_unlock(pdata->lock);
150
151 return ret;
152}
153
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100154static ssize_t usb_read_dev_attr(const struct iio_device *dev,
155 const char *attr, char *dst, size_t len, bool is_debug)
156{
157 struct iio_context_pdata *pdata = dev->ctx->pdata;
158
159 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, dev,
160 NULL, attr, dst, len, is_debug);
161}
162
163static ssize_t usb_write_dev_attr(const struct iio_device *dev,
164 const char *attr, const char *src, size_t len, bool is_debug)
165{
166 struct iio_context_pdata *pdata = dev->ctx->pdata;
167
168 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, dev,
169 NULL, attr, src, len, is_debug);
170}
171
172static ssize_t usb_read_chn_attr(const struct iio_channel *chn,
173 const char *attr, char *dst, size_t len)
174{
175 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
176
177 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, chn->dev,
178 chn, attr, dst, len, false);
179}
180
181static ssize_t usb_write_chn_attr(const struct iio_channel *chn,
182 const char *attr, const char *src, size_t len)
183{
184 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
185
186 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, chn->dev,
187 chn, attr, src, len, false);
188}
189
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100190static int usb_set_kernel_buffers_count(const struct iio_device *dev,
191 unsigned int nb_blocks)
192{
193 struct iio_context_pdata *pdata = dev->ctx->pdata;
194
195 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
196 EP_OPS, dev, nb_blocks);
197}
198
Paul Cercueil7a988892015-12-03 12:39:20 +0100199static unsigned int usb_calculate_remote_timeout(unsigned int timeout)
200{
201 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
202 * by the remote. Is there something better to do here? */
203 return timeout / 2;
204}
205
206static int usb_set_timeout(struct iio_context *ctx, unsigned int timeout)
207{
208 struct iio_context_pdata *pdata = ctx->pdata;
209 unsigned int remote_timeout = usb_calculate_remote_timeout(timeout);
210 int ret;
211
212 ret = iiod_client_set_timeout(pdata->iiod_client,
213 EP_OPS, remote_timeout);
214 if (ret < 0)
215 return ret;
216
217 iio_mutex_lock(pdata->i_lock);
218 ret = iiod_client_set_timeout(pdata->iiod_client, EP_INPUT,
219 remote_timeout);
220 iio_mutex_unlock(pdata->i_lock);
221 if (ret < 0)
222 goto err_restore_old_timeout_ep_ops;
223
224 iio_mutex_lock(pdata->i_lock);
225 ret = iiod_client_set_timeout(pdata->iiod_client, EP_OUTPUT,
226 remote_timeout);
227 iio_mutex_unlock(pdata->o_lock);
228 if (ret < 0)
229 goto err_restore_old_timeout_ep_input;
230
231 pdata->timeout_ms = timeout;
232 return 0;
233
234err_restore_old_timeout_ep_input:
235 iiod_client_set_timeout(pdata->iiod_client,
236 EP_INPUT, pdata->timeout_ms);
237err_restore_old_timeout_ep_ops:
238 iiod_client_set_timeout(pdata->iiod_client, EP_OPS, pdata->timeout_ms);
239 return ret;
240}
241
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200242static void usb_shutdown(struct iio_context *ctx)
243{
244 iio_mutex_destroy(ctx->pdata->lock);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100245 iio_mutex_destroy(ctx->pdata->o_lock);
246 iio_mutex_destroy(ctx->pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200247
248 iiod_client_destroy(ctx->pdata->iiod_client);
249
250 libusb_close(ctx->pdata->hdl);
251 libusb_exit(ctx->pdata->ctx);
252}
253
254static const struct iio_backend_ops usb_ops = {
Paul Cercueilc11737c2015-11-26 14:44:46 +0100255 .get_version = usb_get_version,
Paul Cercueil4acd6042015-11-30 12:10:43 +0100256 .open = usb_open,
257 .close = usb_close,
Paul Cercueil04841832015-12-02 11:58:33 +0100258 .read = usb_read,
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100259 .read_device_attr = usb_read_dev_attr,
260 .read_channel_attr = usb_read_chn_attr,
261 .write_device_attr = usb_write_dev_attr,
262 .write_channel_attr = usb_write_chn_attr,
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100263 .set_kernel_buffers_count = usb_set_kernel_buffers_count,
Paul Cercueil7a988892015-12-03 12:39:20 +0100264 .set_timeout = usb_set_timeout,
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200265 .shutdown = usb_shutdown,
266};
267
268static ssize_t write_data_sync(struct iio_context_pdata *pdata,
269 int ep, const char *data, size_t len)
270{
271 int transferred, ret;
272
273 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_OUT,
274 (char *) data, len, &transferred, DEFAULT_TIMEOUT_MS);
275 if (ret)
276 return -libusb_to_errno(ret);
277 else
278 return transferred != len ? -EIO : len;
279}
280
281static ssize_t read_data_sync(struct iio_context_pdata *pdata,
282 int ep, char *buf, size_t len)
283{
284 int transferred, ret;
285
286 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
287 buf, len, &transferred, DEFAULT_TIMEOUT_MS);
288 if (ret)
289 return -libusb_to_errno(ret);
290 else
291 return transferred;
292}
293
294static struct iiod_client_ops usb_iiod_client_ops = {
295 .write = write_data_sync,
296 .read = read_data_sync,
297 .read_line = read_data_sync,
298};
299
300struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
301{
302 libusb_context *usb_ctx;
303 libusb_device_handle *hdl;
304 struct iio_context *ctx;
305 struct iio_context_pdata *pdata;
306 unsigned int i;
307 int ret;
308
309 pdata = calloc(1, sizeof(*pdata));
310 if (!pdata) {
311 ERROR("Unable to allocate pdata\n");
312 ret = -ENOMEM;
313 goto err_set_errno;
314 }
315
316 pdata->lock = iio_mutex_create();
317 if (!pdata->lock) {
318 ERROR("Unable to create mutex\n");
319 ret = -ENOMEM;
320 goto err_free_pdata;
321 }
322
Paul Cercueil4acd6042015-11-30 12:10:43 +0100323 pdata->i_lock = iio_mutex_create();
324 if (!pdata->i_lock) {
325 ERROR("Unable to create mutex\n");
326 ret = -ENOMEM;
327 goto err_destroy_mutex;
328 }
329
330 pdata->o_lock = iio_mutex_create();
331 if (!pdata->o_lock) {
332 ERROR("Unable to create mutex\n");
333 ret = -ENOMEM;
334 goto err_destroy_i_mutex;
335 }
336
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200337 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
338 &usb_iiod_client_ops);
339 if (!pdata->iiod_client) {
340 ERROR("Unable to create IIOD client\n");
341 ret = -errno;
Paul Cercueil4acd6042015-11-30 12:10:43 +0100342 goto err_destroy_o_mutex;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200343 }
344
345 ret = libusb_init(&usb_ctx);
346 if (ret) {
347 ret = -libusb_to_errno(ret);
348 ERROR("Unable to init libusb: %i\n", ret);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100349 goto err_destroy_iiod_client;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200350 }
351
352 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
353 if (!hdl) {
354 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
355 ret = -ENODEV;
356 goto err_libusb_exit;
357 }
358
359 libusb_set_auto_detach_kernel_driver(hdl, true);
360
361 ret = libusb_claim_interface(hdl, 0);
362 if (ret) {
363 ret = -libusb_to_errno(ret);
364 ERROR("Unable to claim interface 0: %i\n", ret);
365 goto err_libusb_close;
366 }
367
368 pdata->ctx = usb_ctx;
369 pdata->hdl = hdl;
Paul Cercueil7a988892015-12-03 12:39:20 +0100370 pdata->timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200371
372 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
373 if (!ctx)
374 goto err_libusb_close;
375
376 ctx->name = "usb";
377 ctx->ops = &usb_ops;
378 ctx->pdata = pdata;
379
380 DEBUG("Initializing context...\n");
381 ret = iio_context_init(ctx);
382 if (ret < 0)
383 goto err_context_destroy;
384
Paul Cercueil4acd6042015-11-30 12:10:43 +0100385 for (i = 0; i < ctx->nb_devices; i++) {
386 struct iio_device *dev = ctx->devices[i];
387
388 dev->pdata = calloc(1, sizeof(*dev->pdata));
389 if (!dev->pdata) {
390 ERROR("Unable to allocate memory\n");
391 ret = -ENOMEM;
392 goto err_context_destroy;
393 }
394
395 dev->pdata->is_tx = iio_device_is_tx(dev);
396
397 if (dev->pdata->is_tx) {
398 dev->pdata->lock = pdata->o_lock;
399 dev->pdata->ep = EP_OUTPUT;
400 } else {
401 dev->pdata->lock = pdata->i_lock;
402 dev->pdata->ep = EP_INPUT;
403 }
404 }
405
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200406 return ctx;
407
408err_context_destroy:
409 iio_context_destroy(ctx);
410 errno = -ret;
411 return NULL;
412
413err_libusb_close:
414 libusb_close(hdl);
415err_libusb_exit:
416 libusb_exit(usb_ctx);
417err_destroy_iiod_client:
418 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100419err_destroy_o_mutex:
420 iio_mutex_destroy(pdata->o_lock);
421err_destroy_i_mutex:
422 iio_mutex_destroy(pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200423err_destroy_mutex:
424 iio_mutex_destroy(pdata->lock);
425err_free_pdata:
426 free(pdata);
427err_set_errno:
428 errno = -ret;
429 return NULL;
430}