blob: fd138ab55b17a34481eec04ea0c7f517777a460d [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,
Paul Cercueilb8bc93f2015-12-11 11:38:49 +0100294 (char *) data, (int) len,
295 &transferred, DEFAULT_TIMEOUT_MS);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200296 if (ret)
Paul Cercueil463fc782015-12-04 16:04:12 +0100297 return -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200298 else
Paul Cercueilb8bc93f2015-12-11 11:38:49 +0100299 return transferred != len ? -EIO : (ssize_t) len;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200300}
301
302static ssize_t read_data_sync(struct iio_context_pdata *pdata,
303 int ep, char *buf, size_t len)
304{
305 int transferred, ret;
306
307 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
Paul Cercueilb8bc93f2015-12-11 11:38:49 +0100308 buf, (int) len, &transferred, DEFAULT_TIMEOUT_MS);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200309 if (ret)
Paul Cercueil463fc782015-12-04 16:04:12 +0100310 return -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200311 else
312 return transferred;
313}
314
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +0100315static const struct iiod_client_ops usb_iiod_client_ops = {
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200316 .write = write_data_sync,
317 .read = read_data_sync,
318 .read_line = read_data_sync,
319};
320
321struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
322{
323 libusb_context *usb_ctx;
324 libusb_device_handle *hdl;
325 struct iio_context *ctx;
326 struct iio_context_pdata *pdata;
327 unsigned int i;
328 int ret;
329
330 pdata = calloc(1, sizeof(*pdata));
331 if (!pdata) {
332 ERROR("Unable to allocate pdata\n");
333 ret = -ENOMEM;
334 goto err_set_errno;
335 }
336
337 pdata->lock = iio_mutex_create();
338 if (!pdata->lock) {
339 ERROR("Unable to create mutex\n");
340 ret = -ENOMEM;
341 goto err_free_pdata;
342 }
343
Paul Cercueil4acd6042015-11-30 12:10:43 +0100344 pdata->i_lock = iio_mutex_create();
345 if (!pdata->i_lock) {
346 ERROR("Unable to create mutex\n");
347 ret = -ENOMEM;
348 goto err_destroy_mutex;
349 }
350
351 pdata->o_lock = iio_mutex_create();
352 if (!pdata->o_lock) {
353 ERROR("Unable to create mutex\n");
354 ret = -ENOMEM;
355 goto err_destroy_i_mutex;
356 }
357
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200358 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
359 &usb_iiod_client_ops);
360 if (!pdata->iiod_client) {
361 ERROR("Unable to create IIOD client\n");
362 ret = -errno;
Paul Cercueil4acd6042015-11-30 12:10:43 +0100363 goto err_destroy_o_mutex;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200364 }
365
366 ret = libusb_init(&usb_ctx);
367 if (ret) {
Paul Cercueil463fc782015-12-04 16:04:12 +0100368 ret = -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200369 ERROR("Unable to init libusb: %i\n", ret);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100370 goto err_destroy_iiod_client;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200371 }
372
373 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
374 if (!hdl) {
375 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
376 ret = -ENODEV;
377 goto err_libusb_exit;
378 }
379
380 libusb_set_auto_detach_kernel_driver(hdl, true);
381
382 ret = libusb_claim_interface(hdl, 0);
383 if (ret) {
Paul Cercueil463fc782015-12-04 16:04:12 +0100384 ret = -(int) libusb_to_errno(ret);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200385 ERROR("Unable to claim interface 0: %i\n", ret);
386 goto err_libusb_close;
387 }
388
389 pdata->ctx = usb_ctx;
390 pdata->hdl = hdl;
Paul Cercueil7a988892015-12-03 12:39:20 +0100391 pdata->timeout_ms = DEFAULT_TIMEOUT_MS;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200392
393 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
394 if (!ctx)
395 goto err_libusb_close;
396
397 ctx->name = "usb";
398 ctx->ops = &usb_ops;
399 ctx->pdata = pdata;
400
401 DEBUG("Initializing context...\n");
402 ret = iio_context_init(ctx);
403 if (ret < 0)
404 goto err_context_destroy;
405
Paul Cercueil4acd6042015-11-30 12:10:43 +0100406 for (i = 0; i < ctx->nb_devices; i++) {
407 struct iio_device *dev = ctx->devices[i];
408
409 dev->pdata = calloc(1, sizeof(*dev->pdata));
410 if (!dev->pdata) {
411 ERROR("Unable to allocate memory\n");
412 ret = -ENOMEM;
413 goto err_context_destroy;
414 }
415
416 dev->pdata->is_tx = iio_device_is_tx(dev);
417
418 if (dev->pdata->is_tx) {
419 dev->pdata->lock = pdata->o_lock;
420 dev->pdata->ep = EP_OUTPUT;
421 } else {
422 dev->pdata->lock = pdata->i_lock;
423 dev->pdata->ep = EP_INPUT;
424 }
425 }
426
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200427 return ctx;
428
429err_context_destroy:
430 iio_context_destroy(ctx);
431 errno = -ret;
432 return NULL;
433
434err_libusb_close:
435 libusb_close(hdl);
436err_libusb_exit:
437 libusb_exit(usb_ctx);
438err_destroy_iiod_client:
439 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100440err_destroy_o_mutex:
441 iio_mutex_destroy(pdata->o_lock);
442err_destroy_i_mutex:
443 iio_mutex_destroy(pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200444err_destroy_mutex:
445 iio_mutex_destroy(pdata->lock);
446err_free_pdata:
447 free(pdata);
448err_set_errno:
449 errno = -ret;
450 return NULL;
451}