blob: 747f85c1c2bf955aa38ac069861bf42d63ce015d [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
80static void usb_shutdown(struct iio_context *ctx)
81{
82 iio_mutex_destroy(ctx->pdata->lock);
83
84 iiod_client_destroy(ctx->pdata->iiod_client);
85
86 libusb_close(ctx->pdata->hdl);
87 libusb_exit(ctx->pdata->ctx);
88}
89
90static const struct iio_backend_ops usb_ops = {
91 .shutdown = usb_shutdown,
92};
93
94static ssize_t write_data_sync(struct iio_context_pdata *pdata,
95 int ep, const char *data, size_t len)
96{
97 int transferred, ret;
98
99 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_OUT,
100 (char *) data, len, &transferred, DEFAULT_TIMEOUT_MS);
101 if (ret)
102 return -libusb_to_errno(ret);
103 else
104 return transferred != len ? -EIO : len;
105}
106
107static ssize_t read_data_sync(struct iio_context_pdata *pdata,
108 int ep, char *buf, size_t len)
109{
110 int transferred, ret;
111
112 ret = libusb_bulk_transfer(pdata->hdl, ep | LIBUSB_ENDPOINT_IN,
113 buf, len, &transferred, DEFAULT_TIMEOUT_MS);
114 if (ret)
115 return -libusb_to_errno(ret);
116 else
117 return transferred;
118}
119
120static struct iiod_client_ops usb_iiod_client_ops = {
121 .write = write_data_sync,
122 .read = read_data_sync,
123 .read_line = read_data_sync,
124};
125
126struct iio_context * usb_create_context(unsigned short vid, unsigned short pid)
127{
128 libusb_context *usb_ctx;
129 libusb_device_handle *hdl;
130 struct iio_context *ctx;
131 struct iio_context_pdata *pdata;
132 unsigned int i;
133 int ret;
134
135 pdata = calloc(1, sizeof(*pdata));
136 if (!pdata) {
137 ERROR("Unable to allocate pdata\n");
138 ret = -ENOMEM;
139 goto err_set_errno;
140 }
141
142 pdata->lock = iio_mutex_create();
143 if (!pdata->lock) {
144 ERROR("Unable to create mutex\n");
145 ret = -ENOMEM;
146 goto err_free_pdata;
147 }
148
149 pdata->iiod_client = iiod_client_new(pdata, pdata->lock,
150 &usb_iiod_client_ops);
151 if (!pdata->iiod_client) {
152 ERROR("Unable to create IIOD client\n");
153 ret = -errno;
154 goto err_destroy_mutex;
155 }
156
157 ret = libusb_init(&usb_ctx);
158 if (ret) {
159 ret = -libusb_to_errno(ret);
160 ERROR("Unable to init libusb: %i\n", ret);
161 goto err_free_pdata;
162 }
163
164 hdl = libusb_open_device_with_vid_pid(usb_ctx, vid, pid);
165 if (!hdl) {
166 ERROR("Unable to find device 0x%04hx:0x%04hx\n", vid, pid);
167 ret = -ENODEV;
168 goto err_libusb_exit;
169 }
170
171 libusb_set_auto_detach_kernel_driver(hdl, true);
172
173 ret = libusb_claim_interface(hdl, 0);
174 if (ret) {
175 ret = -libusb_to_errno(ret);
176 ERROR("Unable to claim interface 0: %i\n", ret);
177 goto err_libusb_close;
178 }
179
180 pdata->ctx = usb_ctx;
181 pdata->hdl = hdl;
182
183 ctx = iiod_client_create_context(pdata->iiod_client, EP_OPS);
184 if (!ctx)
185 goto err_libusb_close;
186
187 ctx->name = "usb";
188 ctx->ops = &usb_ops;
189 ctx->pdata = pdata;
190
191 DEBUG("Initializing context...\n");
192 ret = iio_context_init(ctx);
193 if (ret < 0)
194 goto err_context_destroy;
195
196 return ctx;
197
198err_context_destroy:
199 iio_context_destroy(ctx);
200 errno = -ret;
201 return NULL;
202
203err_libusb_close:
204 libusb_close(hdl);
205err_libusb_exit:
206 libusb_exit(usb_ctx);
207err_destroy_iiod_client:
208 iiod_client_destroy(pdata->iiod_client);
209err_destroy_mutex:
210 iio_mutex_destroy(pdata->lock);
211err_free_pdata:
212 free(pdata);
213err_set_errno:
214 errno = -ret;
215 return NULL;
216}