1 /*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2016 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 #include "../debug.h"
19 #include "../iio-private.h"
20 #include "ops.h"
21 #include "thread-pool.h"
22
23 #include <fcntl.h>
24 #include <linux/usb/functionfs.h>
25 #include <stdint.h>
26 #include <string.h>
27
28 /* u8"IIO" for non-c11 compilers */
29 #define NAME "\x0049\x0049\x004F"
30
31 #define LE32(x) ((__BYTE_ORDER != __BIG_ENDIAN) ? (x) : __bswap_constant_32(x))
32 #define LE16(x) ((__BYTE_ORDER != __BIG_ENDIAN) ? (x) : __bswap_constant_16(x))
33
34 #define IIO_USD_CMD_RESET_PIPES 0
35 #define IIO_USD_CMD_OPEN_PIPE 1
36 #define IIO_USD_CMD_CLOSE_PIPE 2
37
38
39 struct usb_ffs_header {
40 struct usb_functionfs_descs_head_v2 header;
41 uint32_t nb_fs, nb_hs, nb_ss;
42 } __attribute__((packed));
43
44 struct usb_ffs_strings {
45 struct usb_functionfs_strings_head head;
46 uint16_t lang;
47 const char string[sizeof(NAME)];
48 } __attribute__((packed));
49
50 struct usbd_pdata {
51 struct iio_context *ctx;
52 char *ffs;
53 int ep0_fd;
54 bool debug, use_aio;
55 struct thread_pool **pool;
56 unsigned int nb_pipes;
57 };
58
59 struct usbd_client_pdata {
60 struct usbd_pdata *pdata;
61 int ep_in, ep_out;
62 };
63
64 static const struct usb_ffs_strings ffs_strings = {
65 .head = {
66 .magic = LE32(FUNCTIONFS_STRINGS_MAGIC),
67 .length = LE32(sizeof(ffs_strings)),
68 .str_count = LE32(1),
69 .lang_count = LE32(1),
70 },
71
72 .lang = LE16(0x409),
73 .string = NAME,
74 };
75
usbd_client_thread(struct thread_pool * pool,void * d)76 static void usbd_client_thread(struct thread_pool *pool, void *d)
77 {
78 struct usbd_client_pdata *pdata = d;
79
80 interpreter(pdata->pdata->ctx, pdata->ep_in, pdata->ep_out,
81 pdata->pdata->debug, false,
82 pdata->pdata->use_aio, pool);
83
84 close(pdata->ep_in);
85 close(pdata->ep_out);
86 free(pdata);
87 }
88
usb_open_pipe(struct usbd_pdata * pdata,unsigned int pipe_id)89 static int usb_open_pipe(struct usbd_pdata *pdata, unsigned int pipe_id)
90 {
91 struct usbd_client_pdata *cpdata;
92 char buf[256];
93 int err;
94
95 if (pipe_id >= pdata->nb_pipes)
96 return -EINVAL;
97
98 cpdata = malloc(sizeof(*cpdata));
99 if (!pdata)
100 return -ENOMEM;
101
102 /* Either we open this pipe for the first time, or it was closed before.
103 * In that case we called thread_pool_stop() without waiting for all the
104 * threads to finish. We do that here. Since the running thread might still
105 * have a open handle to the endpoints make sure that they have exited
106 * before opening the endpoints again. */
107 thread_pool_stop_and_wait(pdata->pool[pipe_id]);
108
109 snprintf(buf, sizeof(buf), "%s/ep%u", pdata->ffs, pipe_id * 2 + 1);
110 cpdata->ep_out = open(buf, O_WRONLY);
111 if (cpdata->ep_out < 0) {
112 err = -errno;
113 goto err_free_cpdata;
114 }
115
116 snprintf(buf, sizeof(buf), "%s/ep%u", pdata->ffs, pipe_id * 2 + 2);
117 cpdata->ep_in = open(buf, O_RDONLY);
118 if (cpdata->ep_in < 0) {
119 err = -errno;
120 goto err_close_ep_out;
121 }
122
123 cpdata->pdata = pdata;
124
125 err = thread_pool_add_thread(pdata->pool[pipe_id],
126 usbd_client_thread, cpdata, "usbd_client_thd");
127 if (!err)
128 return 0;
129
130 close(cpdata->ep_in);
131 err_close_ep_out:
132 close(cpdata->ep_out);
133 err_free_cpdata:
134 free(cpdata);
135 return err;
136 }
137
usb_close_pipe(struct usbd_pdata * pdata,unsigned int pipe_id)138 static int usb_close_pipe(struct usbd_pdata *pdata, unsigned int pipe_id)
139 {
140 if (pipe_id >= pdata->nb_pipes)
141 return -EINVAL;
142
143 thread_pool_stop(pdata->pool[pipe_id]);
144 return 0;
145 }
146
usb_close_pipes(struct usbd_pdata * pdata)147 static void usb_close_pipes(struct usbd_pdata *pdata)
148 {
149 unsigned int i;
150
151 for (i = 0; i < pdata->nb_pipes; i++)
152 usb_close_pipe(pdata, i);
153 }
154
handle_event(struct usbd_pdata * pdata,const struct usb_functionfs_event * event)155 static int handle_event(struct usbd_pdata *pdata,
156 const struct usb_functionfs_event *event)
157 {
158 int ret = 0;
159
160 if (event->type == FUNCTIONFS_SETUP) {
161 const struct usb_ctrlrequest *req = &event->u.setup;
162
163 switch (req->bRequest) {
164 case IIO_USD_CMD_RESET_PIPES:
165 usb_close_pipes(pdata);
166 break;
167 case IIO_USD_CMD_OPEN_PIPE:
168 ret = usb_open_pipe(pdata, le16toh(req->wValue));
169 break;
170 case IIO_USD_CMD_CLOSE_PIPE:
171 ret = usb_close_pipe(pdata, le16toh(req->wValue));
172 break;
173 }
174 }
175
176 return ret;
177 }
178
usbd_main(struct thread_pool * pool,void * d)179 static void usbd_main(struct thread_pool *pool, void *d)
180 {
181 int stop_fd = thread_pool_get_poll_fd(pool);
182 struct usbd_pdata *pdata = d;
183 unsigned int i;
184
185 for (;;) {
186 struct usb_functionfs_event event;
187 struct pollfd pfd[2];
188 int ret;
189
190 pfd[0].fd = pdata->ep0_fd;
191 pfd[0].events = POLLIN;
192 pfd[0].revents = 0;
193 pfd[1].fd = stop_fd;
194 pfd[1].events = POLLIN;
195 pfd[1].revents = 0;
196
197 poll_nointr(pfd, 2);
198
199 if (pfd[1].revents & POLLIN) /* STOP event */
200 break;
201
202 if (!(pfd[0].revents & POLLIN)) /* Should never happen. */
203 continue;
204
205 ret = read(pdata->ep0_fd, &event, sizeof(event));
206 if (ret != sizeof(event)) {
207 WARNING("Short read!\n");
208 continue;
209 }
210
211 ret = handle_event(pdata, &event);
212 if (ret) {
213 ERROR("Unable to handle event: %i\n", ret);
214 break;
215 }
216
217 /* Clear out the errors on ep0 when we close endpoints */
218 ret = read(pdata->ep0_fd, NULL, 0);
219 }
220
221 for (i = 0; i < pdata->nb_pipes; i++) {
222 thread_pool_stop_and_wait(pdata->pool[i]);
223 thread_pool_destroy(pdata->pool[i]);
224 }
225
226 close(pdata->ep0_fd);
227 free(pdata->ffs);
228 free(pdata->pool);
229 free(pdata);
230 }
231
create_header(unsigned int nb_pipes,uint32_t size)232 static struct usb_ffs_header * create_header(
233 unsigned int nb_pipes, uint32_t size)
234 {
235 /* Packet sizes for USB high-speed, full-speed, super-speed */
236 const unsigned int packet_sizes[3] = { 64, 512, 1024, };
237 struct usb_ffs_header *hdr;
238 unsigned int i, pipe_id;
239 uintptr_t ptr;
240
241 hdr = zalloc(size);
242 if (!hdr) {
243 errno = ENOMEM;
244 return NULL;
245 }
246
247 hdr->header.magic = LE32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
248 hdr->header.length = htole32(size);
249 hdr->header.flags = LE32(FUNCTIONFS_HAS_FS_DESC |
250 FUNCTIONFS_HAS_HS_DESC |
251 FUNCTIONFS_HAS_SS_DESC);
252
253 hdr->nb_fs = htole32(nb_pipes * 2 + 1);
254 hdr->nb_hs = htole32(nb_pipes * 2 + 1);
255 hdr->nb_ss = htole32(nb_pipes * 4 + 1);
256
257 ptr = ((uintptr_t) hdr) + sizeof(*hdr);
258
259 for (i = 0; i < 3; i++) {
260 struct usb_interface_descriptor *desc =
261 (struct usb_interface_descriptor *) ptr;
262 struct usb_endpoint_descriptor_no_audio *ep;
263 struct usb_ss_ep_comp_descriptor *comp;
264
265 desc->bLength = sizeof(*desc);
266 desc->bDescriptorType = USB_DT_INTERFACE;
267 desc->bNumEndpoints = nb_pipes * 2;
268 desc->bInterfaceClass = USB_CLASS_COMM;
269 desc->iInterface = 1;
270
271 ep = (struct usb_endpoint_descriptor_no_audio *)
272 (ptr + sizeof(*desc));
273
274 for (pipe_id = 0; pipe_id < nb_pipes; pipe_id++) {
275 ep->bLength = sizeof(*ep);
276 ep->bDescriptorType = USB_DT_ENDPOINT;
277 ep->bEndpointAddress = (pipe_id + 1) | USB_DIR_IN;
278 ep->bmAttributes = USB_ENDPOINT_XFER_BULK;
279 ep->wMaxPacketSize = htole16(packet_sizes[i]);
280 ep++;
281
282 if (i == 2) {
283 comp = (struct usb_ss_ep_comp_descriptor *) ep;
284 comp->bLength = USB_DT_SS_EP_COMP_SIZE;
285 comp->bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
286 comp++;
287 ep = (struct usb_endpoint_descriptor_no_audio *) comp;
288 }
289
290 ep->bLength = sizeof(*ep);
291 ep->bDescriptorType = USB_DT_ENDPOINT;
292 ep->bEndpointAddress = (pipe_id + 1) | USB_DIR_OUT;
293 ep->bmAttributes = USB_ENDPOINT_XFER_BULK;
294 ep->wMaxPacketSize = htole16(packet_sizes[i]);
295 ep++;
296
297 if (i == 2) {
298 comp = (struct usb_ss_ep_comp_descriptor *) ep;
299 comp->bLength = USB_DT_SS_EP_COMP_SIZE;
300 comp->bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
301 comp++;
302 ep = (struct usb_endpoint_descriptor_no_audio *) comp;
303 }
304 }
305
306 ptr += sizeof(*desc) + nb_pipes * 2 * sizeof(*ep);
307 }
308
309 return hdr;
310 }
311
write_header(int fd,unsigned int nb_pipes)312 static int write_header(int fd, unsigned int nb_pipes)
313 {
314 uint32_t size = sizeof(struct usb_ffs_header) +
315 3 * sizeof(struct usb_interface_descriptor) +
316 6 * nb_pipes * sizeof(struct usb_endpoint_descriptor_no_audio) +
317 2 * nb_pipes * sizeof(struct usb_ss_ep_comp_descriptor);
318 struct usb_ffs_header *hdr;
319 int ret;
320
321 hdr = create_header(nb_pipes, size);
322 if (!hdr)
323 return -errno;
324
325 ret = write(fd, hdr, size);
326 free(hdr);
327 if (ret < 0)
328 return -errno;
329
330 ret = write(fd, &ffs_strings, sizeof(ffs_strings));
331 if (ret < 0)
332 return -errno;
333
334 return 0;
335 }
336
start_usb_daemon(struct iio_context * ctx,const char * ffs,bool debug,bool use_aio,unsigned int nb_pipes,struct thread_pool * pool)337 int start_usb_daemon(struct iio_context *ctx, const char *ffs,
338 bool debug, bool use_aio, unsigned int nb_pipes,
339 struct thread_pool *pool)
340 {
341 struct usbd_pdata *pdata;
342 unsigned int i;
343 char buf[256];
344 int ret;
345
346 pdata = zalloc(sizeof(*pdata));
347 if (!pdata)
348 return -ENOMEM;
349
350 pdata->nb_pipes = nb_pipes;
351
352 pdata->pool = calloc(nb_pipes, sizeof(*pdata->pool));
353 if (!pdata->pool) {
354 ret = -ENOMEM;
355 goto err_free_pdata;
356 }
357
358 pdata->ffs = strdup(ffs);
359 if (!pdata->ffs) {
360 ret = -ENOMEM;
361 goto err_free_pdata_pool;
362 }
363
364 snprintf(buf, sizeof(buf), "%s/ep0", ffs);
365
366 pdata->ep0_fd = open(buf, O_RDWR);
367 if (pdata->ep0_fd < 0) {
368 ret = -errno;
369 goto err_free_ffs;
370 }
371
372 ret = write_header(pdata->ep0_fd, nb_pipes);
373 if (ret < 0)
374 goto err_close_ep0;
375
376 for (i = 0; i < nb_pipes; i++) {
377 pdata->pool[i] = thread_pool_new();
378 if (!pdata->pool[i]) {
379 ret = -errno;
380 goto err_free_pools;
381 }
382 }
383
384 pdata->ctx = ctx;
385 pdata->debug = debug;
386 pdata->use_aio = use_aio;
387
388 ret = thread_pool_add_thread(pool, usbd_main, pdata, "usbd_main_thd");
389 if (!ret)
390 return 0;
391
392 err_free_pools:
393 /* If we get here, usbd_main was not started, so the pools can be
394 * destroyed directly */
395 for (i = 0; i < nb_pipes; i++) {
396 if (pdata->pool[i])
397 thread_pool_destroy(pdata->pool[i]);
398 }
399 err_close_ep0:
400 close(pdata->ep0_fd);
401 err_free_ffs:
402 free(pdata->ffs);
403 err_free_pdata_pool:
404 free(pdata->pool);
405 err_free_pdata:
406 free(pdata);
407 return ret;
408 }
409