blob: 58c6c7e572073cf572943ae43ebb54389caf3465 [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
34struct iio_context_pdata {
35 libusb_context *ctx;
36 libusb_device_handle *hdl;
37
38 struct iiod_client *iiod_client;
39
40 /* Lock for non-streaming operations */
41 struct iio_mutex *lock;
42};
43
44static const unsigned int libusb_to_errno_codes[] = {
45 [- LIBUSB_ERROR_INVALID_PARAM] = EINVAL,
46 [- LIBUSB_ERROR_ACCESS] = EACCES,
47 [- LIBUSB_ERROR_NO_DEVICE] = ENODEV,
48 [- LIBUSB_ERROR_NOT_FOUND] = ENXIO,
49 [- LIBUSB_ERROR_BUSY] = EBUSY,
50 [- LIBUSB_ERROR_TIMEOUT] = ETIMEDOUT,
51 [- LIBUSB_ERROR_OVERFLOW] = EIO,
52 [- LIBUSB_ERROR_PIPE] = EPIPE,
53 [- LIBUSB_ERROR_INTERRUPTED] = EINTR,
54 [- LIBUSB_ERROR_NO_MEM] = ENOMEM,
55 [- LIBUSB_ERROR_NOT_SUPPORTED] = ENOSYS,
56};
57
58static unsigned int libusb_to_errno(int error)
59{
60 switch ((enum libusb_error) error) {
61 case LIBUSB_ERROR_INVALID_PARAM:
62 case LIBUSB_ERROR_ACCESS:
63 case LIBUSB_ERROR_NO_DEVICE:
64 case LIBUSB_ERROR_NOT_FOUND:
65 case LIBUSB_ERROR_BUSY:
66 case LIBUSB_ERROR_TIMEOUT:
67 case LIBUSB_ERROR_PIPE:
68 case LIBUSB_ERROR_INTERRUPTED:
69 case LIBUSB_ERROR_NO_MEM:
70 case LIBUSB_ERROR_NOT_SUPPORTED:
71 return libusb_to_errno_codes[- (int) error];
72 case LIBUSB_ERROR_IO:
73 case LIBUSB_ERROR_OTHER:
74 case LIBUSB_ERROR_OVERFLOW:
75 default:
76 return EIO;
77 }
78}
79
Paul Cercueilc11737c2015-11-26 14:44:46 +010080static int usb_get_version(const struct iio_context *ctx,
81 unsigned int *major, unsigned int *minor, char git_tag[8])
82{
83 return iiod_client_get_version(ctx->pdata->iiod_client,
84 EP_OPS, major, minor, git_tag);
85}
86
Paul Cercueil3069e3b2015-11-26 16:01:25 +010087static ssize_t usb_read_dev_attr(const struct iio_device *dev,
88 const char *attr, char *dst, size_t len, bool is_debug)
89{
90 struct iio_context_pdata *pdata = dev->ctx->pdata;
91
92 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, dev,
93 NULL, attr, dst, len, is_debug);
94}
95
96static ssize_t usb_write_dev_attr(const struct iio_device *dev,
97 const char *attr, const char *src, size_t len, bool is_debug)
98{
99 struct iio_context_pdata *pdata = dev->ctx->pdata;
100
101 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, dev,
102 NULL, attr, src, len, is_debug);
103}
104
105static ssize_t usb_read_chn_attr(const struct iio_channel *chn,
106 const char *attr, char *dst, size_t len)
107{
108 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
109
110 return iiod_client_read_attr(pdata->iiod_client, EP_OPS, chn->dev,
111 chn, attr, dst, len, false);
112}
113
114static ssize_t usb_write_chn_attr(const struct iio_channel *chn,
115 const char *attr, const char *src, size_t len)
116{
117 struct iio_context_pdata *pdata = chn->dev->ctx->pdata;
118
119 return iiod_client_write_attr(pdata->iiod_client, EP_OPS, chn->dev,
120 chn, attr, src, len, false);
121}
122
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100123static int usb_set_kernel_buffers_count(const struct iio_device *dev,
124 unsigned int nb_blocks)
125{
126 struct iio_context_pdata *pdata = dev->ctx->pdata;
127
128 return iiod_client_set_kernel_buffers_count(pdata->iiod_client,
129 EP_OPS, dev, nb_blocks);
130}
131
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200132static void usb_shutdown(struct iio_context *ctx)
133{
134 iio_mutex_destroy(ctx->pdata->lock);
135
136 iiod_client_destroy(ctx->pdata->iiod_client);
137
138 libusb_close(ctx->pdata->hdl);
139 libusb_exit(ctx->pdata->ctx);
140}
141
142static const struct iio_backend_ops usb_ops = {
Paul Cercueilc11737c2015-11-26 14:44:46 +0100143 .get_version = usb_get_version,
Paul Cercueil3069e3b2015-11-26 16:01:25 +0100144 .read_device_attr = usb_read_dev_attr,
145 .read_channel_attr = usb_read_chn_attr,
146 .write_device_attr = usb_write_dev_attr,
147 .write_channel_attr = usb_write_chn_attr,
Paul Cercueil6c8337e2015-11-27 11:13:09 +0100148 .set_kernel_buffers_count = usb_set_kernel_buffers_count,
Paul Cercueile06f4ce2015-04-20 12:59:31 +0200149 .shutdown = usb_shutdown,
150};
151
152static ssize_t write_data_sync(struct iio_context_pdata *pdata,
153 int ep, const char *data, size_t len)
154{
155 int transferred, ret;
156
157 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_OUT,
158 (char *) data, len, &transferred, DEFAULT_TIMEOUT_MS);
159 if (ret)
160 return -libusb_to_errno(ret);
161 else
162 return transferred != len ? -EIO : len;
163}
164
165static ssize_t read_data_sync(struct iio_context_pdata *pdata,
166 int ep, char *buf, size_t len)
167{
168 int transferred, ret;
169
170 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
171 buf, len, &transferred, DEFAULT_TIMEOUT_MS);
172 if (ret)
173 return -libusb_to_errno(ret);
174 else
175 return transferred;
176}
177
178static struct iiod_client_ops usb_iiod_client_ops = {
179 .write = write_data_sync,
180 .read = read_data_sync,
181 .read_line = read_data_sync,
182};
183
184struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
185{
186 libusb_context *usb_ctx;
187 libusb_device_handle *hdl;
188 struct iio_context *ctx;
189 struct iio_context_pdata *pdata;
190 unsigned int i;
191 int ret;
192
193 pdata = calloc(1, sizeof(*pdata));
194 if (!pdata) {
195 ERROR("Unable to allocate pdata\n");
196 ret = -ENOMEM;
197 goto err_set_errno;
198 }
199
200 pdata->lock = iio_mutex_create();
201 if (!pdata->lock) {
202 ERROR("Unable to create mutex\n");
203 ret = -ENOMEM;
204 goto err_free_pdata;
205 }
206
207 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
208 &usb_iiod_client_ops);
209 if (!pdata->iiod_client) {
210 ERROR("Unable to create IIOD client\n");
211 ret = -errno;
212 goto err_destroy_mutex;
213 }
214
215 ret = libusb_init(&usb_ctx);
216 if (ret) {
217 ret = -libusb_to_errno(ret);
218 ERROR("Unable to init libusb: %i\n", ret);
219 goto err_free_pdata;
220 }
221
222 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
223 if (!hdl) {
224 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
225 ret = -ENODEV;
226 goto err_libusb_exit;
227 }
228
229 libusb_set_auto_detach_kernel_driver(hdl, true);
230
231 ret = libusb_claim_interface(hdl, 0);
232 if (ret) {
233 ret = -libusb_to_errno(ret);
234 ERROR("Unable to claim interface 0: %i\n", ret);
235 goto err_libusb_close;
236 }
237
238 pdata->ctx = usb_ctx;
239 pdata->hdl = hdl;
240
241 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
242 if (!ctx)
243 goto err_libusb_close;
244
245 ctx->name = "usb";
246 ctx->ops = &usb_ops;
247 ctx->pdata = pdata;
248
249 DEBUG("Initializing context...\n");
250 ret = iio_context_init(ctx);
251 if (ret < 0)
252 goto err_context_destroy;
253
254 return ctx;
255
256err_context_destroy:
257 iio_context_destroy(ctx);
258 errno = -ret;
259 return NULL;
260
261err_libusb_close:
262 libusb_close(hdl);
263err_libusb_exit:
264 libusb_exit(usb_ctx);
265err_destroy_iiod_client:
266 iiod_client_destroy(pdata->iiod_client);
267err_destroy_mutex:
268 iio_mutex_destroy(pdata->lock);
269err_free_pdata:
270 free(pdata);
271err_set_errno:
272 errno = -ret;
273 return NULL;
274}