blob: d9faf94040a521bf43316af7d6331c139b14b59b [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
Paul Cercueile06f4ce2015-04-20 12:59:31 +020019#include "iio-lock.h"
20#include "iio-private.h"
21#include "iiod-client.h"
22
23#include <errno.h>
24#include <libusb-1.0/libusb.h>
25#include <stdbool.h>
26#include <string.h>
27
Paul Cercueil3c1e7852015-12-04 16:14:28 +010028#ifdef ERROR
29#undef ERROR
30#endif
31
32#include "debug.h"
33
Paul Cercueile06f4ce2015-04-20 12:59:31 +020034#define DEFAULT_TIMEOUT_MS 5000
35
36/* Endpoint for non-streaming operations */
37#define EP_OPS 1
38
Paul Cercueil4acd6042015-11-30 12:10:43 +010039/* Endpoint for input devices */
40#define EP_INPUT 2
41
42/* Endpoint for output devices */
43#define EP_OUTPUT 3
44
Paul Cercueile06f4ce2015-04-20 12:59:31 +020045struct iio_context_pdata {
46 libusb_context *ctx;
47 libusb_device_handle *hdl;
48
49 struct iiod_client *iiod_client;
50
51 /* Lock for non-streaming operations */
52 struct iio_mutex *lock;
Paul Cercueil4acd6042015-11-30 12:10:43 +010053
54 /* Locks for input/output devices */
55 struct iio_mutex *i_lock, *o_lock;
Paul Cercueil7a988892015-12-03 12:39:20 +010056
57 unsigned int timeout_ms;
Paul Cercueil4acd6042015-11-30 12:10:43 +010058};
59
60struct iio_device_pdata {
61 bool is_tx;
62 struct iio_mutex *lock;
63
64 bool opened;
65 unsigned int ep;
Paul Cercueile06f4ce2015-04-20 12:59:31 +020066};
67
68static const unsigned int libusb_to_errno_codes[] = {
69 [- LIBUSB_ERROR_INVALID_PARAM] = EINVAL,
70 [- LIBUSB_ERROR_ACCESS] = EACCES,
71 [- LIBUSB_ERROR_NO_DEVICE] = ENODEV,
72 [- LIBUSB_ERROR_NOT_FOUND] = ENXIO,
73 [- LIBUSB_ERROR_BUSY] = EBUSY,
74 [- LIBUSB_ERROR_TIMEOUT] = ETIMEDOUT,
75 [- LIBUSB_ERROR_OVERFLOW] = EIO,
76 [- LIBUSB_ERROR_PIPE] = EPIPE,
77 [- LIBUSB_ERROR_INTERRUPTED] = EINTR,
78 [- LIBUSB_ERROR_NO_MEM] = ENOMEM,
79 [- LIBUSB_ERROR_NOT_SUPPORTED] = ENOSYS,
80};
81
82static unsigned int libusb_to_errno(int error)
83{
84 switch ((enum libusb_error) error) {
85 case LIBUSB_ERROR_INVALID_PARAM:
86 case LIBUSB_ERROR_ACCESS:
87 case LIBUSB_ERROR_NO_DEVICE:
88 case LIBUSB_ERROR_NOT_FOUND:
89 case LIBUSB_ERROR_BUSY:
90 case LIBUSB_ERROR_TIMEOUT:
91 case LIBUSB_ERROR_PIPE:
92 case LIBUSB_ERROR_INTERRUPTED:
93 case LIBUSB_ERROR_NO_MEM:
94 case LIBUSB_ERROR_NOT_SUPPORTED:
95 return libusb_to_errno_codes[- (int) error];
96 case LIBUSB_ERROR_IO:
97 case LIBUSB_ERROR_OTHER:
98 case LIBUSB_ERROR_OVERFLOW:
99 default:
100 return EIO;
101 }
102}
103
Paul Cercueilc11737c2015-11-26 14:44:46 +0100104static int usb_get_version(const struct iio_context *ctx,
105 unsigned int *major, unsigned int *minor, char git_tag[8])
106{
107 return iiod_client_get_version(ctx->pdata->iiod_client,
108 EP_OPS, major, minor, git_tag);
109}
110
Paul Cercueil4acd6042015-11-30 12:10:43 +0100111static int usb_open(const struct iio_device *dev,
112 size_t samples_count, bool cyclic)
113{
114 struct iio_device_pdata *pdata = dev->pdata;
115 int ret = -EBUSY;
116
117 iio_mutex_lock(pdata->lock);
118
119 if (!pdata->opened) {
120 ret = iiod_client_open_unlocked(dev->ctx->pdata->iiod_client,
121 pdata->ep, dev, samples_count, cyclic);
122 pdata->opened = !ret;
123 }
124
125 iio_mutex_unlock(pdata->lock);
126 return ret;
127}
128
129static int usb_close(const struct iio_device *dev)
130{
131 struct iio_device_pdata *pdata = dev->pdata;
132 int ret = -EBADF;
133
134 iio_mutex_lock(pdata->lock);
135 if (pdata->opened) {
136 ret = iiod_client_close_unlocked(dev->ctx->pdata->iiod_client,
137 pdata->ep, dev);
138 pdata->opened = false;
139 }
140
141 iio_mutex_unlock(pdata->lock);
142 return ret;
143}
144
Paul Cercueil04841832015-12-02 11:58:33 +0100145static ssize_t usb_read(const struct iio_device *dev, void *dst, size_t len,
146 uint32_t *mask, size_t words)
147{
148 struct iio_device_pdata *pdata = dev->pdata;
149 ssize_t ret;
150
151 iio_mutex_lock(pdata->lock);
152 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
153 pdata->ep, dev, dst, len, mask, words);
154 iio_mutex_unlock(pdata->lock);
155
156 return ret;
157}
158
Paul Cercueile78e9882015-12-04 16:31:10 +0100159static ssize_t usb_write(const struct iio_device *dev,
160 const void *src, size_t len)
161{
162 struct iio_device_pdata *pdata = dev->pdata;
163 ssize_t ret;
164
165 iio_mutex_lock(pdata->lock);
166 ret = iiod_client_write_unlocked(dev->ctx->pdata->iiod_client,
167 pdata->ep, dev, src, len);
168 iio_mutex_unlock(pdata->lock);
169
170 return ret;
171}
172
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100173static ssize_t usb_read_dev_attr(const struct iio_device *dev,
174 const char *attr, char *dst, size_t len, bool is_debug)
175{
176 struct iio_context_pdata *pdata = dev->ctx->pdata;
177
178 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, dev,
179 NULL, attr, dst, len, is_debug);
180}
181
182static ssize_t usb_write_dev_attr(const struct iio_device *dev,
183 const char *attr, const char *src, size_t len, bool is_debug)
184{
185 struct iio_context_pdata *pdata = dev->ctx->pdata;
186
187 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, dev,
188 NULL, attr, src, len, is_debug);
189}
190
191static ssize_t usb_read_chn_attr(const struct iio_channel *chn,
192 const char *attr, char *dst, size_t len)
193{
194 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
195
196 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, chn->dev,
197 chn, attr, dst, len, false);
198}
199
200static ssize_t usb_write_chn_attr(const struct iio_channel *chn,
201 const char *attr, const char *src, size_t len)
202{
203 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
204
205 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, chn->dev,
206 chn, attr, src, len, false);
207}
208
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100209static int usb_set_kernel_buffers_count(const struct iio_device *dev,
210 unsigned int nb_blocks)
211{
212 struct iio_context_pdata *pdata = dev->ctx->pdata;
213
214 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
215 EP_OPS, dev, nb_blocks);
216}
217
Paul Cercueil7a988892015-12-03 12:39:20 +0100218static unsigned int usb_calculate_remote_timeout(unsigned int timeout)
219{
220 /* XXX(pcercuei): We currently hardcode timeout / 2 for the backend used
221 * by the remote. Is there something better to do here? */
222 return timeout / 2;
223}
224
225static int usb_set_timeout(struct iio_context *ctx, unsigned int timeout)
226{
227 struct iio_context_pdata *pdata = ctx->pdata;
228 unsigned int remote_timeout = usb_calculate_remote_timeout(timeout);
229 int ret;
230
231 ret = iiod_client_set_timeout(pdata->iiod_client,
232 EP_OPS, remote_timeout);
233 if (ret < 0)
234 return ret;
235
236 iio_mutex_lock(pdata->i_lock);
237 ret = iiod_client_set_timeout(pdata->iiod_client, EP_INPUT,
238 remote_timeout);
239 iio_mutex_unlock(pdata->i_lock);
240 if (ret < 0)
241 goto err_restore_old_timeout_ep_ops;
242
243 iio_mutex_lock(pdata->i_lock);
244 ret = iiod_client_set_timeout(pdata->iiod_client, EP_OUTPUT,
245 remote_timeout);
246 iio_mutex_unlock(pdata->o_lock);
247 if (ret < 0)
248 goto err_restore_old_timeout_ep_input;
249
250 pdata->timeout_ms = timeout;
251 return 0;
252
253err_restore_old_timeout_ep_input:
254 iiod_client_set_timeout(pdata->iiod_client,
255 EP_INPUT, pdata->timeout_ms);
256err_restore_old_timeout_ep_ops:
257 iiod_client_set_timeout(pdata->iiod_client, EP_OPS, pdata->timeout_ms);
258 return ret;
259}
260
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200261static void usb_shutdown(struct iio_context *ctx)
262{
263 iio_mutex_destroy(ctx->pdata->lock);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100264 iio_mutex_destroy(ctx->pdata->o_lock);
265 iio_mutex_destroy(ctx->pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200266
267 iiod_client_destroy(ctx->pdata->iiod_client);
268
269 libusb_close(ctx->pdata->hdl);
270 libusb_exit(ctx->pdata->ctx);
271}
272
273static const struct iio_backend_ops usb_ops = {
Paul Cercueilc11737c2015-11-26 14:44:46 +0100274 .get_version = usb_get_version,
Paul Cercueil4acd6042015-11-30 12:10:43 +0100275 .open = usb_open,
276 .close = usb_close,
Paul Cercueil04841832015-12-02 11:58:33 +0100277 .read = usb_read,
Paul Cercueile78e9882015-12-04 16:31:10 +0100278 .write = usb_write,
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100279 .read_device_attr = usb_read_dev_attr,
280 .read_channel_attr = usb_read_chn_attr,
281 .write_device_attr = usb_write_dev_attr,
282 .write_channel_attr = usb_write_chn_attr,
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100283 .set_kernel_buffers_count = usb_set_kernel_buffers_count,
Paul Cercueil7a988892015-12-03 12:39:20 +0100284 .set_timeout = usb_set_timeout,
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200285 .shutdown = usb_shutdown,
286};
287
288static ssize_t write_data_sync(struct iio_context_pdata *pdata,
289 int ep, const char *data, size_t len)
290{
291 int transferred, ret;
292
293 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_OUT,
294 (char *) data, len, &transferred, DEFAULT_TIMEOUT_MS);
295 if (ret)
Paul Cercueil463fc782015-12-04 16:04:12 +0100296 return -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200297 else
298 return transferred != len ? -EIO : len;
299}
300
301static ssize_t read_data_sync(struct iio_context_pdata *pdata,
302 int ep, char *buf, size_t len)
303{
304 int transferred, ret;
305
306 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
307 buf, len, &transferred, DEFAULT_TIMEOUT_MS);
308 if (ret)
Paul Cercueil463fc782015-12-04 16:04:12 +0100309 return -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200310 else
311 return transferred;
312}
313
314static struct iiod_client_ops usb_iiod_client_ops = {
315 .write = write_data_sync,
316 .read = read_data_sync,
317 .read_line = read_data_sync,
318};
319
320struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
321{
322 libusb_context *usb_ctx;
323 libusb_device_handle *hdl;
324 struct iio_context *ctx;
325 struct iio_context_pdata *pdata;
326 unsigned int i;
327 int ret;
328
329 pdata = calloc(1, sizeof(*pdata));
330 if (!pdata) {
331 ERROR("Unable to allocate pdata\n");
332 ret = -ENOMEM;
333 goto err_set_errno;
334 }
335
336 pdata->lock = iio_mutex_create();
337 if (!pdata->lock) {
338 ERROR("Unable to create mutex\n");
339 ret = -ENOMEM;
340 goto err_free_pdata;
341 }
342
Paul Cercueil4acd6042015-11-30 12:10:43 +0100343 pdata->i_lock = iio_mutex_create();
344 if (!pdata->i_lock) {
345 ERROR("Unable to create mutex\n");
346 ret = -ENOMEM;
347 goto err_destroy_mutex;
348 }
349
350 pdata->o_lock = iio_mutex_create();
351 if (!pdata->o_lock) {
352 ERROR("Unable to create mutex\n");
353 ret = -ENOMEM;
354 goto err_destroy_i_mutex;
355 }
356
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200357 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
358 &usb_iiod_client_ops);
359 if (!pdata->iiod_client) {
360 ERROR("Unable to create IIOD client\n");
361 ret = -errno;
Paul Cercueil4acd6042015-11-30 12:10:43 +0100362 goto err_destroy_o_mutex;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200363 }
364
365 ret = libusb_init(&usb_ctx);
366 if (ret) {
Paul Cercueil463fc782015-12-04 16:04:12 +0100367 ret = -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200368 ERROR("Unable to init libusb: %i\n", ret);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100369 goto err_destroy_iiod_client;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200370 }
371
372 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
373 if (!hdl) {
374 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
375 ret = -ENODEV;
376 goto err_libusb_exit;
377 }
378
379 libusb_set_auto_detach_kernel_driver(hdl, true);
380
381 ret = libusb_claim_interface(hdl, 0);
382 if (ret) {
Paul Cercueil463fc782015-12-04 16:04:12 +0100383 ret = -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200384 ERROR("Unable to claim interface 0: %i\n", ret);
385 goto err_libusb_close;
386 }
387
388 pdata->ctx = usb_ctx;
389 pdata->hdl = hdl;
Paul Cercueil7a988892015-12-03 12:39:20 +0100390 pdata->timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200391
392 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
393 if (!ctx)
394 goto err_libusb_close;
395
396 ctx->name = "usb";
397 ctx->ops = &usb_ops;
398 ctx->pdata = pdata;
399
400 DEBUG("Initializing context...\n");
401 ret = iio_context_init(ctx);
402 if (ret < 0)
403 goto err_context_destroy;
404
Paul Cercueil4acd6042015-11-30 12:10:43 +0100405 for (i = 0; i < ctx->nb_devices; i++) {
406 struct iio_device *dev = ctx->devices[i];
407
408 dev->pdata = calloc(1, sizeof(*dev->pdata));
409 if (!dev->pdata) {
410 ERROR("Unable to allocate memory\n");
411 ret = -ENOMEM;
412 goto err_context_destroy;
413 }
414
415 dev->pdata->is_tx = iio_device_is_tx(dev);
416
417 if (dev->pdata->is_tx) {
418 dev->pdata->lock = pdata->o_lock;
419 dev->pdata->ep = EP_OUTPUT;
420 } else {
421 dev->pdata->lock = pdata->i_lock;
422 dev->pdata->ep = EP_INPUT;
423 }
424 }
425
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200426 return ctx;
427
428err_context_destroy:
429 iio_context_destroy(ctx);
430 errno = -ret;
431 return NULL;
432
433err_libusb_close:
434 libusb_close(hdl);
435err_libusb_exit:
436 libusb_exit(usb_ctx);
437err_destroy_iiod_client:
438 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100439err_destroy_o_mutex:
440 iio_mutex_destroy(pdata->o_lock);
441err_destroy_i_mutex:
442 iio_mutex_destroy(pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200443err_destroy_mutex:
444 iio_mutex_destroy(pdata->lock);
445err_free_pdata:
446 free(pdata);
447err_set_errno:
448 errno = -ret;
449 return NULL;
450}