blob: fc35d5644fd258082633de02564c2ac6544f5190 [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 Cercueil04841832015-12-02 11:58:33 +0100138static ssize_t usb_read(const struct iio_device *dev, void *dst, size_t len,
139 uint32_t *mask, size_t words)
140{
141 struct iio_device_pdata *pdata = dev->pdata;
142 ssize_t ret;
143
144 iio_mutex_lock(pdata->lock);
145 ret = iiod_client_read_unlocked(dev->ctx->pdata->iiod_client,
146 pdata->ep, dev, dst, len, mask, words);
147 iio_mutex_unlock(pdata->lock);
148
149 return ret;
150}
151
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100152static ssize_t usb_read_dev_attr(const struct iio_device *dev,
153 const char *attr, char *dst, size_t len, bool is_debug)
154{
155 struct iio_context_pdata *pdata = dev->ctx->pdata;
156
157 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, dev,
158 NULL, attr, dst, len, is_debug);
159}
160
161static ssize_t usb_write_dev_attr(const struct iio_device *dev,
162 const char *attr, const char *src, size_t len, bool is_debug)
163{
164 struct iio_context_pdata *pdata = dev->ctx->pdata;
165
166 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, dev,
167 NULL, attr, src, len, is_debug);
168}
169
170static ssize_t usb_read_chn_attr(const struct iio_channel *chn,
171 const char *attr, char *dst, size_t len)
172{
173 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
174
175 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, chn->dev,
176 chn, attr, dst, len, false);
177}
178
179static ssize_t usb_write_chn_attr(const struct iio_channel *chn,
180 const char *attr, const char *src, size_t len)
181{
182 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
183
184 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, chn->dev,
185 chn, attr, src, len, false);
186}
187
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100188static int usb_set_kernel_buffers_count(const struct iio_device *dev,
189 unsigned int nb_blocks)
190{
191 struct iio_context_pdata *pdata = dev->ctx->pdata;
192
193 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
194 EP_OPS, dev, nb_blocks);
195}
196
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200197static void usb_shutdown(struct iio_context *ctx)
198{
199 iio_mutex_destroy(ctx->pdata->lock);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100200 iio_mutex_destroy(ctx->pdata->o_lock);
201 iio_mutex_destroy(ctx->pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200202
203 iiod_client_destroy(ctx->pdata->iiod_client);
204
205 libusb_close(ctx->pdata->hdl);
206 libusb_exit(ctx->pdata->ctx);
207}
208
209static const struct iio_backend_ops usb_ops = {
Paul Cercueilc11737c2015-11-26 14:44:46 +0100210 .get_version = usb_get_version,
Paul Cercueil4acd6042015-11-30 12:10:43 +0100211 .open = usb_open,
212 .close = usb_close,
Paul Cercueil04841832015-12-02 11:58:33 +0100213 .read = usb_read,
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100214 .read_device_attr = usb_read_dev_attr,
215 .read_channel_attr = usb_read_chn_attr,
216 .write_device_attr = usb_write_dev_attr,
217 .write_channel_attr = usb_write_chn_attr,
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100218 .set_kernel_buffers_count = usb_set_kernel_buffers_count,
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200219 .shutdown = usb_shutdown,
220};
221
222static ssize_t write_data_sync(struct iio_context_pdata *pdata,
223 int ep, const char *data, size_t len)
224{
225 int transferred, ret;
226
227 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_OUT,
228 (char *) data, len, &transferred, DEFAULT_TIMEOUT_MS);
229 if (ret)
230 return -libusb_to_errno(ret);
231 else
232 return transferred != len ? -EIO : len;
233}
234
235static ssize_t read_data_sync(struct iio_context_pdata *pdata,
236 int ep, char *buf, size_t len)
237{
238 int transferred, ret;
239
240 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
241 buf, len, &transferred, DEFAULT_TIMEOUT_MS);
242 if (ret)
243 return -libusb_to_errno(ret);
244 else
245 return transferred;
246}
247
248static struct iiod_client_ops usb_iiod_client_ops = {
249 .write = write_data_sync,
250 .read = read_data_sync,
251 .read_line = read_data_sync,
252};
253
254struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
255{
256 libusb_context *usb_ctx;
257 libusb_device_handle *hdl;
258 struct iio_context *ctx;
259 struct iio_context_pdata *pdata;
260 unsigned int i;
261 int ret;
262
263 pdata = calloc(1, sizeof(*pdata));
264 if (!pdata) {
265 ERROR("Unable to allocate pdata\n");
266 ret = -ENOMEM;
267 goto err_set_errno;
268 }
269
270 pdata->lock = iio_mutex_create();
271 if (!pdata->lock) {
272 ERROR("Unable to create mutex\n");
273 ret = -ENOMEM;
274 goto err_free_pdata;
275 }
276
Paul Cercueil4acd6042015-11-30 12:10:43 +0100277 pdata->i_lock = iio_mutex_create();
278 if (!pdata->i_lock) {
279 ERROR("Unable to create mutex\n");
280 ret = -ENOMEM;
281 goto err_destroy_mutex;
282 }
283
284 pdata->o_lock = iio_mutex_create();
285 if (!pdata->o_lock) {
286 ERROR("Unable to create mutex\n");
287 ret = -ENOMEM;
288 goto err_destroy_i_mutex;
289 }
290
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200291 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
292 &usb_iiod_client_ops);
293 if (!pdata->iiod_client) {
294 ERROR("Unable to create IIOD client\n");
295 ret = -errno;
Paul Cercueil4acd6042015-11-30 12:10:43 +0100296 goto err_destroy_o_mutex;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200297 }
298
299 ret = libusb_init(&usb_ctx);
300 if (ret) {
301 ret = -libusb_to_errno(ret);
302 ERROR("Unable to init libusb: %i\n", ret);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100303 goto err_destroy_iiod_client;
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200304 }
305
306 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
307 if (!hdl) {
308 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
309 ret = -ENODEV;
310 goto err_libusb_exit;
311 }
312
313 libusb_set_auto_detach_kernel_driver(hdl, true);
314
315 ret = libusb_claim_interface(hdl, 0);
316 if (ret) {
317 ret = -libusb_to_errno(ret);
318 ERROR("Unable to claim interface 0: %i\n", ret);
319 goto err_libusb_close;
320 }
321
322 pdata->ctx = usb_ctx;
323 pdata->hdl = hdl;
324
325 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
326 if (!ctx)
327 goto err_libusb_close;
328
329 ctx->name = "usb";
330 ctx->ops = &usb_ops;
331 ctx->pdata = pdata;
332
333 DEBUG("Initializing context...\n");
334 ret = iio_context_init(ctx);
335 if (ret < 0)
336 goto err_context_destroy;
337
Paul Cercueil4acd6042015-11-30 12:10:43 +0100338 for (i = 0; i < ctx->nb_devices; i++) {
339 struct iio_device *dev = ctx->devices[i];
340
341 dev->pdata = calloc(1, sizeof(*dev->pdata));
342 if (!dev->pdata) {
343 ERROR("Unable to allocate memory\n");
344 ret = -ENOMEM;
345 goto err_context_destroy;
346 }
347
348 dev->pdata->is_tx = iio_device_is_tx(dev);
349
350 if (dev->pdata->is_tx) {
351 dev->pdata->lock = pdata->o_lock;
352 dev->pdata->ep = EP_OUTPUT;
353 } else {
354 dev->pdata->lock = pdata->i_lock;
355 dev->pdata->ep = EP_INPUT;
356 }
357 }
358
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200359 return ctx;
360
361err_context_destroy:
362 iio_context_destroy(ctx);
363 errno = -ret;
364 return NULL;
365
366err_libusb_close:
367 libusb_close(hdl);
368err_libusb_exit:
369 libusb_exit(usb_ctx);
370err_destroy_iiod_client:
371 iiod_client_destroy(pdata->iiod_client);
Paul Cercueil4acd6042015-11-30 12:10:43 +0100372err_destroy_o_mutex:
373 iio_mutex_destroy(pdata->o_lock);
374err_destroy_i_mutex:
375 iio_mutex_destroy(pdata->i_lock);
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200376err_destroy_mutex:
377 iio_mutex_destroy(pdata->lock);
378err_free_pdata:
379 free(pdata);
380err_set_errno:
381 errno = -ret;
382 return NULL;
383}